Browse Source

Merge pull request #205 - Decompilation of lifted operators

This decompiles the C# generated code for lifted operators back to the original short form.
This can result in a significant improvement to the readability of the resulting code in some more complex functions because C# generates 2 temporary locals for lifted operators that can now be inlined.

As a byproduct the following improvements are also included: more thorough boolean logic decompilation; various project/solution file improvements; Ldloca support for variable splitting; simplified shift operators (already in icsharpcode branch); significant performance improvement for stack analysis of variables to offset the added complexity from ldloca support; decompilation of compound assignment with overloaded operators; some type analysis refactoring.
pull/275/merge
Daniel Grunwald 14 years ago
parent
commit
25237a19d8
  1. 5
      AvalonEdit/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj
  2. 30
      ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  3. 4
      ICSharpCode.Decompiler/Ast/NameVariables.cs
  4. 14
      ICSharpCode.Decompiler/Ast/Transforms/PushNegation.cs
  5. 11
      ICSharpCode.Decompiler/Ast/Transforms/ReplaceMethodCallsWithOperators.cs
  6. 8
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  7. 50
      ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs
  8. 36
      ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
  9. 23
      ICSharpCode.Decompiler/ILAst/ILCodes.cs
  10. 9
      ICSharpCode.Decompiler/ILAst/ILInlining.cs
  11. 528
      ICSharpCode.Decompiler/ILAst/LiftedOperators.cs
  12. 108
      ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs
  13. 10
      ICSharpCode.Decompiler/ILAst/SimpleControlFlow.cs
  14. 144
      ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
  15. 3
      ICSharpCode.Decompiler/ILAst/YieldReturnDecompiler.cs
  16. 8
      ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj
  17. 12
      ICSharpCode.Decompiler/Tests/InitializerTests.cs
  18. 830
      ICSharpCode.Decompiler/Tests/LiftedOperators.cs
  19. 20
      ICSharpCode.Decompiler/Tests/TestRunner.cs
  20. 14
      ICSharpCode.Decompiler/Tests/TypeAnalysisTests.cs
  21. 9
      ILSpy.BamlDecompiler/ILSpy.BamlDecompiler.csproj
  22. 3
      ILSpy.BamlDecompiler/Tests/ILSpy.BamlDecompiler.Tests.csproj
  23. 5
      ILSpy.SharpDevelop.LGPL/ILSpy.SharpDevelop.LGPL.csproj
  24. 28
      ILSpy.sln
  25. 6
      ILSpy/ILSpy.csproj
  26. 6
      NRefactory/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj
  27. 1
      README.txt

5
AvalonEdit/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj

@ -33,7 +33,7 @@ @@ -33,7 +33,7 @@
<DefineConstants>DEBUG;TRACE;DOTNET4</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DebugSymbols>false</DebugSymbols>
<DebugSymbols>true</DebugSymbols>
<DebugType>PdbOnly</DebugType>
<Optimize>True</Optimize>
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
@ -42,9 +42,8 @@ @@ -42,9 +42,8 @@
<PropertyGroup Condition=" '$(Platform)' == 'AnyCPU' ">
<RegisterForComInterop>False</RegisterForComInterop>
<GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies>
<BaseAddress>4194304</BaseAddress>
<BaseAddress>452984832</BaseAddress>
<PlatformTarget>AnyCPU</PlatformTarget>
<FileAlignment>4096</FileAlignment>
</PropertyGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
<ItemGroup>

30
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -421,7 +421,13 @@ namespace ICSharpCode.Decompiler.Ast @@ -421,7 +421,13 @@ namespace ICSharpCode.Decompiler.Ast
case ILCode.CompoundAssignment:
{
CastExpression cast = arg1 as CastExpression;
BinaryOperatorExpression boe = (BinaryOperatorExpression)(cast != null ? cast.Expression : arg1);
var boe = cast != null ? (BinaryOperatorExpression)cast.Expression : arg1 as BinaryOperatorExpression;
// AssignmentExpression doesn't support overloaded operators so they have to be processed to BinaryOperatorExpression
if (boe == null) {
var tmp = new ParenthesizedExpression(arg1);
ReplaceMethodCallsWithOperators.ProcessInvocationExpression((InvocationExpression)arg1);
boe = (BinaryOperatorExpression)tmp.Expression;
}
var assignment = new Ast.AssignmentExpression {
Left = boe.Left.Detach(),
Operator = ReplaceMethodCallsWithOperators.GetAssignmentOperatorForBinaryOperator(boe.Operator),
@ -440,17 +446,25 @@ namespace ICSharpCode.Decompiler.Ast @@ -440,17 +446,25 @@ namespace ICSharpCode.Decompiler.Ast
#endregion
#region Comparison
case ILCode.Ceq: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, arg2);
case ILCode.Cne: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, arg2);
case ILCode.Cgt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2);
case ILCode.Cgt_Un: {
// can also mean Inequality, when used with object references
TypeReference arg1Type = byteCode.Arguments[0].InferredType;
if (arg1Type != null && !arg1Type.IsValueType)
return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, arg2);
else
return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2);
if (arg1Type != null && !arg1Type.IsValueType) goto case ILCode.Cne;
goto case ILCode.Cgt;
}
case ILCode.Cle_Un: {
// can also mean Equality, when used with object references
TypeReference arg1Type = byteCode.Arguments[0].InferredType;
if (arg1Type != null && !arg1Type.IsValueType) goto case ILCode.Ceq;
goto case ILCode.Cle;
}
case ILCode.Cle: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2);
case ILCode.Cge_Un:
case ILCode.Cge: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2);
case ILCode.Clt_Un:
case ILCode.Clt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2);
case ILCode.Clt_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2);
#endregion
#region Logical
case ILCode.LogicNot: return new Ast.UnaryOperatorExpression(UnaryOperatorType.Not, arg1);
@ -792,8 +806,12 @@ namespace ICSharpCode.Decompiler.Ast @@ -792,8 +806,12 @@ namespace ICSharpCode.Decompiler.Ast
}
case ILCode.InitializedObject:
return new InitializedObjectExpression();
case ILCode.Wrap:
return arg1.WithAnnotation(PushNegation.LiftedOperatorAnnotation);
case ILCode.AddressOf:
return MakeRef(arg1);
case ILCode.NullableOf:
case ILCode.ValueOf: return arg1;
default:
throw new Exception("Unknown OpCode: " + byteCode.Code);
}

4
ICSharpCode.Decompiler/Ast/NameVariables.cs

@ -175,6 +175,10 @@ namespace ICSharpCode.Decompiler.Ast @@ -175,6 +175,10 @@ namespace ICSharpCode.Decompiler.Ast
case ILCode.Clt_Un:
case ILCode.Cgt:
case ILCode.Cgt_Un:
case ILCode.Cle:
case ILCode.Cle_Un:
case ILCode.Cge:
case ILCode.Cge_Un:
ILVariable loadVar;
if (expr.Arguments[0].Match(ILCode.Ldloc, out loadVar) && loadVar == variable) {
isLoopCounter = true;

14
ICSharpCode.Decompiler/Ast/Transforms/PushNegation.cs

@ -26,8 +26,18 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -26,8 +26,18 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
{
public class PushNegation: DepthFirstAstVisitor<object, object>, IAstTransform
{
sealed class LiftedOperator { }
/// <summary>
/// Annotation for lifted operators that cannot be transformed by PushNegation
/// </summary>
public static readonly object LiftedOperatorAnnotation = new LiftedOperator();
public override object VisitUnaryOperatorExpression(UnaryOperatorExpression unary, object data)
{
// lifted operators can't be transformed
if (unary.Annotation<LiftedOperator>() != null || unary.Expression.Annotation<LiftedOperator>() != null)
return base.VisitUnaryOperatorExpression(unary, data);
// Remove double negation
// !!a
if (unary.Operator == UnaryOperatorType.Not &&
@ -108,6 +118,10 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -108,6 +118,10 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
public override object VisitBinaryOperatorExpression(BinaryOperatorExpression binaryOperatorExpression, object data)
{
// lifted operators can't be transformed
if (binaryOperatorExpression.Annotation<LiftedOperator>() != null)
return base.VisitBinaryOperatorExpression(binaryOperatorExpression, data);
BinaryOperatorType op = binaryOperatorExpression.Operator;
bool? rightOperand = null;
if (binaryOperatorExpression.Right is PrimitiveExpression)

11
ICSharpCode.Decompiler/Ast/Transforms/ReplaceMethodCallsWithOperators.cs

@ -51,6 +51,11 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -51,6 +51,11 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
{
base.VisitInvocationExpression(invocationExpression, data);
return ProcessInvocationExpression(invocationExpression);
}
internal static object ProcessInvocationExpression(InvocationExpression invocationExpression)
{
MethodReference methodRef = invocationExpression.Annotation<MethodReference>();
if (methodRef == null)
return null;
@ -115,7 +120,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -115,7 +120,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
return null;
}
BinaryOperatorType? GetBinaryOperatorTypeFromMetadataName(string name)
static BinaryOperatorType? GetBinaryOperatorTypeFromMetadataName(string name)
{
switch (name) {
case "op_Addition":
@ -132,7 +137,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -132,7 +137,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
return BinaryOperatorType.BitwiseAnd;
case "op_BitwiseOr":
return BinaryOperatorType.BitwiseOr;
case "op_ExlusiveOr":
case "op_ExclusiveOr":
return BinaryOperatorType.ExclusiveOr;
case "op_LeftShift":
return BinaryOperatorType.ShiftLeft;
@ -155,7 +160,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -155,7 +160,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
}
}
UnaryOperatorType? GetUnaryOperatorTypeFromMetadataName(string name)
static UnaryOperatorType? GetUnaryOperatorTypeFromMetadataName(string name)
{
switch (name) {
case "op_LogicalNot":

8
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -19,8 +19,7 @@ @@ -19,8 +19,7 @@
<PlatformTarget>AnyCPU</PlatformTarget>
<RegisterForComInterop>False</RegisterForComInterop>
<GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies>
<BaseAddress>4194304</BaseAddress>
<FileAlignment>4096</FileAlignment>
<BaseAddress>448462848</BaseAddress>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<OutputPath>bin\Debug\</OutputPath>
@ -32,8 +31,8 @@ @@ -32,8 +31,8 @@
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<OutputPath>bin\Release\</OutputPath>
<DebugSymbols>False</DebugSymbols>
<DebugType>None</DebugType>
<DebugSymbols>true</DebugSymbols>
<DebugType>PdbOnly</DebugType>
<Optimize>True</Optimize>
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
<DefineConstants>TRACE</DefineConstants>
@ -96,6 +95,7 @@ @@ -96,6 +95,7 @@
<Compile Include="FlowAnalysis\SsaOptimization.cs" />
<Compile Include="FlowAnalysis\SsaVariable.cs" />
<Compile Include="FlowAnalysis\TransformToSsa.cs" />
<Compile Include="ILAst\LiftedOperators.cs" />
<Compile Include="ILAst\InitializerPeepholeTransforms.cs" />
<Compile Include="ILAst\DefaultDictionary.cs" />
<Compile Include="ILAst\GotoRemoval.cs" />

50
ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs

@ -339,9 +339,10 @@ namespace ICSharpCode.Decompiler.ILAst @@ -339,9 +339,10 @@ namespace ICSharpCode.Decompiler.ILAst
// Calculate new variable state
VariableSlot[] newVariableState = VariableSlot.CloneVariableState(byteCode.VariablesBefore);
if (byteCode.Code == ILCode.Stloc) {
if (byteCode.Code == ILCode.Stloc || byteCode.Code == ILCode.Ldloca) {
int varIndex = ((VariableReference)byteCode.Operand).Index;
newVariableState[varIndex] = new VariableSlot(byteCode);
newVariableState[varIndex] = byteCode.Code == ILCode.Stloc || byteCode.Next.Code == ILCode.Initobj ?
new VariableSlot(byteCode) : new VariableSlot(newVariableState[varIndex].StoredBy.Union(byteCode), false);
}
// After the leave, finally block might have touched the variables
@ -523,8 +524,12 @@ namespace ICSharpCode.Decompiler.ILAst @@ -523,8 +524,12 @@ namespace ICSharpCode.Decompiler.ILAst
for(int variableIndex = 0; variableIndex < varCount; variableIndex++) {
// Find all stores and loads for this variable
List<ByteCode> stores = body.Where(b => b.Code == ILCode.Stloc && b.Operand is VariableDefinition && b.OperandAsVariable.Index == variableIndex).ToList();
List<ByteCode> loads = body.Where(b => (b.Code == ILCode.Ldloc || b.Code == ILCode.Ldloca) && b.Operand is VariableDefinition && b.OperandAsVariable.Index == variableIndex).ToList();
var stores = body.Where(b => (b.Code == ILCode.Stloc || b.Code == ILCode.Ldloca) && b.Operand is VariableDefinition && b.OperandAsVariable.Index == variableIndex).ToList();
// ldloca on an uninitialized variable or followed by initobj isn't considered a load
var loads = body.Where(b =>
(b.Code == ILCode.Ldloc || (b.Code == ILCode.Ldloca && b.Next.Code != ILCode.Initobj &&
(b.VariablesBefore[variableIndex].StoredBy.Length != 0 || b.VariablesBefore[variableIndex].StoredByAll)))
&& b.Operand is VariableDefinition && b.OperandAsVariable.Index == variableIndex).ToList();
TypeReference varType = methodDef.Body.Variables[variableIndex].VariableType;
List<VariableInfo> newVars;
@ -532,8 +537,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -532,8 +537,7 @@ namespace ICSharpCode.Decompiler.ILAst
bool isPinned = methodDef.Body.Variables[variableIndex].IsPinned;
// If the variable is pinned, use single variable.
// If any of the loads is from "all", use single variable
// If any of the loads is ldloca, fallback to single variable as well
if (isPinned || loads.Any(b => b.VariablesBefore[variableIndex].StoredByAll || b.Code == ILCode.Ldloca)) {
if (isPinned || loads.Any(b => b.VariablesBefore[variableIndex].StoredByAll)) {
newVars = new List<VariableInfo>(1) { new VariableInfo() {
Variable = new ILVariable() {
Name = "var_" + variableIndex,
@ -545,7 +549,12 @@ namespace ICSharpCode.Decompiler.ILAst @@ -545,7 +549,12 @@ namespace ICSharpCode.Decompiler.ILAst
}};
} else {
// Create a new variable for each store
newVars = stores.Select(st => new VariableInfo() {
newVars = stores.Where(st =>
{
if (st.Code == ILCode.Stloc || st.Next.Code == ILCode.Initobj) return true;
var storedBy = st.VariablesBefore[variableIndex].StoredBy;
return storedBy.Length == 0 || storedBy[0] == st;
}).Select(st => new VariableInfo() {
Variable = new ILVariable() {
Name = "var_" + variableIndex + "_" + st.Offset.ToString("X2"),
Type = varType,
@ -582,14 +591,16 @@ namespace ICSharpCode.Decompiler.ILAst @@ -582,14 +591,16 @@ namespace ICSharpCode.Decompiler.ILAst
} else if (storedBy.Length == 1) {
VariableInfo newVar = newVars.Single(v => v.Stores.Contains(storedBy[0]));
newVar.Loads.Add(load);
if (load.Code == ILCode.Ldloca) newVar.Stores.Add(load);
} else {
List<VariableInfo> mergeVars = newVars.Where(v => v.Stores.Union(storedBy).Any()).ToList();
List<VariableInfo> mergeVars = newVars.Where(v => v.Stores.Intersect(storedBy).Any()).ToList();
VariableInfo mergedVar = new VariableInfo() {
Variable = mergeVars[0].Variable,
Stores = mergeVars.SelectMany(v => v.Stores).ToList(),
Loads = mergeVars.SelectMany(v => v.Loads).ToList()
};
mergedVar.Loads.Add(load);
if (load.Code == ILCode.Ldloca) mergedVar.Stores.Add(load);
newVars = newVars.Except(mergeVars).ToList();
newVars.Add(mergedVar);
}
@ -819,15 +830,34 @@ namespace ICSharpCode.Decompiler.ILAst @@ -819,15 +830,34 @@ namespace ICSharpCode.Decompiler.ILAst
list.RemoveRange(start, count);
return ret;
}
public static T[] Union<T>(this T[] a, T b)
{
if (a.Length == 0)
return new[] { b };
if (Array.IndexOf(a, b) >= 0)
return a;
var res = new T[a.Length + 1];
Array.Copy(a, res, a.Length);
res[res.Length - 1] = b;
return res;
}
public static T[] Union<T>(this T[] a, T[] b)
{
if (a == b)
return a;
if (a.Length == 0)
return b;
if (b.Length == 0)
return a;
if (a.Length == 1 && b.Length == 1 && a[0].Equals(b[0]))
return a;
if (a.Length == 1) {
if (b.Length == 1)
return a[0].Equals(b[0]) ? a : new[] { a[0], b[0] };
return b.Union(a[0]);
}
if (b.Length == 1)
return a.Union(b[0]);
return Enumerable.Union(a, b).ToArray();
}
}

36
ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

@ -42,10 +42,12 @@ namespace ICSharpCode.Decompiler.ILAst @@ -42,10 +42,12 @@ namespace ICSharpCode.Decompiler.ILAst
SimplifyTernaryOperator,
SimplifyNullCoalescing,
JoinBasicBlocks,
SimplifyLogicNot,
SimplifyShiftOperators,
TransformDecimalCtorToConstant,
SimplifyLdObjAndStObj,
SimplifyCustomShortCircuit,
SimplifyLiftedOperators,
TransformArrayInitializers,
TransformMultidimensionalArrayInitializers,
TransformObjectInitializers,
@ -134,6 +136,9 @@ namespace ICSharpCode.Decompiler.ILAst @@ -134,6 +136,9 @@ namespace ICSharpCode.Decompiler.ILAst
if (abortBeforeStep == ILAstOptimizationStep.JoinBasicBlocks) return;
modified |= block.RunOptimization(new SimpleControlFlow(context, method).JoinBasicBlocks);
if (abortBeforeStep == ILAstOptimizationStep.SimplifyLogicNot) return;
modified |= block.RunOptimization(SimplifyLogicNot);
if (abortBeforeStep == ILAstOptimizationStep.SimplifyShiftOperators) return;
modified |= block.RunOptimization(SimplifyShiftOperators);
@ -146,6 +151,9 @@ namespace ICSharpCode.Decompiler.ILAst @@ -146,6 +151,9 @@ namespace ICSharpCode.Decompiler.ILAst
if (abortBeforeStep == ILAstOptimizationStep.SimplifyCustomShortCircuit) return;
modified |= block.RunOptimization(new SimpleControlFlow(context, method).SimplifyCustomShortCircuit);
if (abortBeforeStep == ILAstOptimizationStep.SimplifyLiftedOperators) return;
modified |= block.RunOptimization(SimplifyLiftedOperators);
if (abortBeforeStep == ILAstOptimizationStep.TransformArrayInitializers) return;
modified |= block.RunOptimization(TransformArrayInitializers);
@ -307,27 +315,30 @@ namespace ICSharpCode.Decompiler.ILAst @@ -307,27 +315,30 @@ namespace ICSharpCode.Decompiler.ILAst
for (int i = 0; i < block.Body.Count; i++) {
ILExpression expr = block.Body[i] as ILExpression;
if (expr != null && expr.Prefixes == null) {
ILCode op;
switch(expr.Code) {
case ILCode.Switch:
case ILCode.Brtrue:
expr.Arguments.Single().ILRanges.AddRange(expr.ILRanges);
expr.ILRanges.Clear();
continue;
case ILCode.__Brfalse: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, expr.Arguments.Single())); break;
case ILCode.__Beq: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.Ceq, null, expr.Arguments)); break;
case ILCode.__Bne_Un: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, new ILExpression(ILCode.Ceq, null, expr.Arguments))); break;
case ILCode.__Bgt: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.Cgt, null, expr.Arguments)); break;
case ILCode.__Bgt_Un: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.Cgt_Un, null, expr.Arguments)); break;
case ILCode.__Ble: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, new ILExpression(ILCode.Cgt, null, expr.Arguments))); break;
case ILCode.__Ble_Un: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, new ILExpression(ILCode.Cgt_Un, null, expr.Arguments))); break;
case ILCode.__Blt: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.Clt, null, expr.Arguments)); break;
case ILCode.__Blt_Un: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.Clt_Un, null, expr.Arguments)); break;
case ILCode.__Bge: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, new ILExpression(ILCode.Clt, null, expr.Arguments))); break;
case ILCode.__Bge_Un: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, new ILExpression(ILCode.Clt_Un, null, expr.Arguments))); break;
case ILCode.__Brfalse: op = ILCode.LogicNot; break;
case ILCode.__Beq: op = ILCode.Ceq; break;
case ILCode.__Bne_Un: op = ILCode.Cne; break;
case ILCode.__Bgt: op = ILCode.Cgt; break;
case ILCode.__Bgt_Un: op = ILCode.Cgt_Un; break;
case ILCode.__Ble: op = ILCode.Cle; break;
case ILCode.__Ble_Un: op = ILCode.Cle_Un; break;
case ILCode.__Blt: op = ILCode.Clt; break;
case ILCode.__Blt_Un: op = ILCode.Clt_Un; break;
case ILCode.__Bge: op = ILCode.Cge; break;
case ILCode.__Bge_Un: op = ILCode.Cge_Un; break;
default:
continue;
}
((ILExpression)block.Body[i]).Arguments.Single().ILRanges.AddRange(expr.ILRanges);
var newExpr = new ILExpression(op, null, expr.Arguments);
block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, newExpr);
newExpr.ILRanges = expr.ILRanges;
}
}
}
@ -721,6 +732,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -721,6 +732,7 @@ namespace ICSharpCode.Decompiler.ILAst
case ILCode.Ldc_I8:
case ILCode.Ldc_R4:
case ILCode.Ldc_R8:
case ILCode.Ldc_Decimal:
return true;
default:
return false;

23
ICSharpCode.Decompiler/ILAst/ILCodes.cs

@ -247,12 +247,22 @@ namespace ICSharpCode.Decompiler.ILAst @@ -247,12 +247,22 @@ namespace ICSharpCode.Decompiler.ILAst
Readonly,
// Virtual codes - defined for convenience
Cne,
Cge,
Cge_Un,
Cle,
Cle_Un,
Ldexception, // Operand holds the CatchType for catch handler, null for filter
LogicNot,
LogicAnd,
LogicOr,
NullCoalescing,
InitArray, // Array Initializer
/// <summary>
/// Defines a barrier between the parent expression and the argument expression that prevents combining them
/// </summary>
Wrap,
// new Class { Prop = 1, Collection = { { 2, 3 }, {4, 5} }}
// is represented as:
@ -306,7 +316,18 @@ namespace ICSharpCode.Decompiler.ILAst @@ -306,7 +316,18 @@ namespace ICSharpCode.Decompiler.ILAst
/// Used for postincrement for properties, and to represent the Address() method on multi-dimensional arrays.
/// Also used when inlining a method call on a value type: "stloc(v, ...); call(M, ldloca(v));" becomes "call(M, AddressOf(...))"
/// </remarks>
AddressOf
AddressOf,
/// <summary>Simulates getting the value of a lifted operator's nullable argument</summary>
/// <remarks>
/// For example "stloc(v1, ...); stloc(v2, ...); logicand(ceq(call(Nullable`1::GetValueOrDefault, ldloca(v1)), ldloc(v2)), callgetter(Nullable`1::get_HasValue, ldloca(v1)))" becomes "wrap(ceq(ValueOf(...), ...))"
/// </remarks>
ValueOf,
/// <summary>Simulates creating a new nullable value from a value type argument</summary>
/// <remarks>
/// For example "stloc(v1, ...); stloc(v2, ...); ternaryop(callgetter(Nullable`1::get_HasValue, ldloca(v1)), newobj(Nullable`1::.ctor, add(call(Nullable`1::GetValueOrDefault, ldloca(v1)), ldloc(v2))), defaultvalue(Nullable`1))"
/// becomes "NullableOf(add(valueof(...), ...))"
/// </remarks>
NullableOf,
}
public static class ILCodeUtil

9
ICSharpCode.Decompiler/ILAst/ILInlining.cs

@ -406,7 +406,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -406,7 +406,7 @@ namespace ICSharpCode.Decompiler.ILAst
}
/// <summary>
/// Determines whether it is save to move 'expressionBeingMoved' past 'expr'
/// Determines whether it is safe to move 'expressionBeingMoved' past 'expr'
/// </summary>
bool IsSafeForInlineOver(ILExpression expr, ILExpression expressionBeingMoved)
{
@ -427,6 +427,9 @@ namespace ICSharpCode.Decompiler.ILAst @@ -427,6 +427,9 @@ namespace ICSharpCode.Decompiler.ILAst
case ILCode.Ldflda:
case ILCode.Ldsflda:
case ILCode.Ldelema:
case ILCode.AddressOf:
case ILCode.ValueOf:
case ILCode.NullableOf:
// address-loading instructions are safe if their arguments are safe
foreach (ILExpression arg in expr.Arguments) {
if (!IsSafeForInlineOver(arg, expressionBeingMoved))
@ -434,8 +437,8 @@ namespace ICSharpCode.Decompiler.ILAst @@ -434,8 +437,8 @@ namespace ICSharpCode.Decompiler.ILAst
}
return true;
default:
// abort, inlining is not possible
return false;
// instructions with no side-effects are safe (except for Ldloc and Ldloca which are handled separately)
return expr.HasNoSideEffects();
}
}

528
ICSharpCode.Decompiler/ILAst/LiftedOperators.cs

@ -0,0 +1,528 @@ @@ -0,0 +1,528 @@
// Copyright (c) 2011 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;
using System.Collections.Generic;
using System.Linq;
using Mono.Cecil;
namespace ICSharpCode.Decompiler.ILAst
{
partial class ILAstOptimizer
{
bool SimplifyLiftedOperators(List<ILNode> body, ILExpression expr, int pos)
{
if (!new PatternMatcher(typeSystem).SimplifyLiftedOperators(expr)) return false;
var inlining = new ILInlining(method);
while (--pos >= 0 && inlining.InlineIfPossible(body, ref pos)) ;
return true;
}
sealed class PatternMatcher
{
readonly TypeSystem typeSystem;
public PatternMatcher(TypeSystem typeSystem)
{
this.typeSystem = typeSystem;
}
public bool SimplifyLiftedOperators(ILExpression expr)
{
if (Simplify(expr)) return true;
bool modified = false;
foreach (var a in expr.Arguments)
modified |= SimplifyLiftedOperators(a);
return modified;
}
abstract class Pattern
{
public readonly Pattern[] Arguments;
protected Pattern(Pattern[] arguments)
{
this.Arguments = arguments;
}
public virtual bool Match(PatternMatcher pm, ILExpression e)
{
if (e.Arguments.Count != this.Arguments.Length || e.Prefixes != null) return false;
for (int i = 0; i < this.Arguments.Length; i++)
if (!this.Arguments[i].Match(pm, e.Arguments[i])) return false;
return true;
}
public virtual ILExpression BuildNew(PatternMatcher pm)
{
throw new NotSupportedException();
}
public static Pattern operator &(Pattern a, Pattern b)
{
return new ILPattern(ILCode.LogicAnd, a, b);
}
public static Pattern operator |(Pattern a, Pattern b)
{
return new ILPattern(ILCode.LogicOr, a, b);
}
public static Pattern operator !(Pattern a)
{
return new ILPattern(ILCode.LogicNot, a);
}
}
sealed class ILPattern : Pattern
{
readonly ILCode code;
public ILPattern(ILCode code, params Pattern[] arguments)
: base(arguments)
{
this.code = code;
}
public override bool Match(PatternMatcher pm, ILExpression e)
{
return e.Code == this.code && base.Match(pm, e);
}
public override ILExpression BuildNew(PatternMatcher pm)
{
var args = new ILExpression[this.Arguments.Length];
for (int i = 0; i < args.Length; i++) args[i] = this.Arguments[i].BuildNew(pm);
TypeReference t = null;
switch (code) {
case ILCode.Ceq:
case ILCode.Cne:
t = pm.typeSystem.Boolean;
break;
case ILCode.NullCoalescing:
t = args[1].InferredType;
break;
}
return new ILExpression(code, null, args) { InferredType = t };
}
}
sealed class MethodPattern : Pattern
{
readonly ILCode code;
readonly string method;
public MethodPattern(ILCode code, string method, params Pattern[] arguments)
: base(arguments)
{
this.code = code;
this.method = method;
}
public override bool Match(PatternMatcher pm, ILExpression e)
{
if (e.Code != this.code) return false;
var m = (MethodReference)e.Operand;
return m.Name == this.method && TypeAnalysis.IsNullableType(m.DeclaringType) && base.Match(pm, e);
}
}
enum OperatorType
{
Equality, InEquality, Comparison, Other
}
sealed class OperatorPattern : Pattern
{
OperatorType type;
bool simple;
public OperatorPattern() : base(null) { }
public OperatorPattern(OperatorType type, bool simple)
: this()
{
this.type = type;
this.simple = simple;
}
public override bool Match(PatternMatcher pm, ILExpression e)
{
switch (e.Code) {
case ILCode.Ceq:
if (type != OperatorType.Equality) return false;
break;
case ILCode.Cne:
if (type != OperatorType.InEquality) return false;
break;
case ILCode.Cgt:
case ILCode.Cgt_Un:
case ILCode.Cge:
case ILCode.Cge_Un:
case ILCode.Clt:
case ILCode.Clt_Un:
case ILCode.Cle:
case ILCode.Cle_Un:
if (type != OperatorType.Comparison) return false;
break;
case ILCode.Add:
case ILCode.Add_Ovf:
case ILCode.Add_Ovf_Un:
case ILCode.Sub:
case ILCode.Sub_Ovf:
case ILCode.Sub_Ovf_Un:
case ILCode.Mul:
case ILCode.Mul_Ovf:
case ILCode.Mul_Ovf_Un:
case ILCode.Div:
case ILCode.Div_Un:
case ILCode.Rem:
case ILCode.Rem_Un:
case ILCode.And:
case ILCode.Or:
case ILCode.Xor:
case ILCode.Shl:
case ILCode.Shr:
case ILCode.Shr_Un:
case ILCode.Not:
case ILCode.Neg:
case ILCode.LogicNot:
if (type != OperatorType.Other) return false;
break;
case ILCode.Call:
var m = e.Operand as MethodReference;
if (m == null || m.HasThis || !m.HasParameters || e.Arguments.Count > 2 || !IsCustomOperator(m.Name)) return false;
break;
default: return false;
}
if (pm.Operator != null) throw new InvalidOperationException();
pm.Operator = e;
var a0 = e.Arguments[0];
if (!simple) return VariableAGetValueOrDefault.Match(pm, a0) && VariableBGetValueOrDefault.Match(pm, e.Arguments[1]);
if (e.Arguments.Count == 1) return VariableAGetValueOrDefault.Match(pm, a0);
if (VariableAGetValueOrDefault.Match(pm, a0)) {
pm.SimpleOperand = e.Arguments[1];
pm.SimpleLeftOperand = false;
return true;
}
if (VariableAGetValueOrDefault.Match(pm, e.Arguments[1])) {
pm.SimpleOperand = a0;
pm.SimpleLeftOperand = true;
return true;
}
return false;
}
bool IsCustomOperator(string s)
{
switch (type) {
case OperatorType.Equality: return s == "op_Equality";
case OperatorType.InEquality: return s == "op_Inequality";
case OperatorType.Comparison:
if (s.Length < 11 || !s.StartsWith("op_", StringComparison.Ordinal)) return false;
switch (s) {
case "op_GreaterThan":
case "op_GreaterThanOrEqual":
case "op_LessThan":
case "op_LessThanOrEqual": return true;
default: return false;
}
default:
if (s.Length < 10 || !s.StartsWith("op_", StringComparison.Ordinal)) return false;
switch (s) {
case "op_Addition":
case "op_Subtraction":
case "op_Multiply":
case "op_Division":
case "op_Modulus":
case "op_BitwiseAnd":
case "op_BitwiseOr":
case "op_ExclusiveOr":
case "op_LeftShift":
case "op_RightShift":
case "op_UnaryNegation":
case "op_UnaryPlus":
case "op_LogicalNot":
case "op_OnesComplement":
case "op_Increment":
case "op_Decrement": return true;
default: return false;
}
}
}
public override ILExpression BuildNew(PatternMatcher pm)
{
var res = pm.Operator;
res.Arguments.Clear();
if (pm.SimpleLeftOperand) res.Arguments.Add(pm.SimpleOperand);
res.Arguments.Add(VariableA.BuildNew(pm));
if (pm.B != null) res.Arguments.Add(VariableB.BuildNew(pm));
else if (pm.SimpleOperand != null && !pm.SimpleLeftOperand) res.Arguments.Add(pm.SimpleOperand);
return res;
}
}
sealed class AnyPattern : Pattern
{
public AnyPattern() : base(null) { }
public override bool Match(PatternMatcher pm, ILExpression e)
{
if (pm.SimpleOperand != null) throw new InvalidOperationException();
pm.SimpleOperand = e;
return true;
}
public override ILExpression BuildNew(PatternMatcher pm)
{
return pm.SimpleOperand;
}
}
sealed class VariablePattern : Pattern
{
readonly ILCode code;
readonly bool b;
public VariablePattern(ILCode code, bool b)
: base(null)
{
this.code = code;
this.b = b;
}
public override bool Match(PatternMatcher pm, ILExpression e)
{
if (e.Code != this.code) return false;
var v = e.Operand as ILVariable;
return v != null && (this.b ? Capture(ref pm.B, v) : Capture(ref pm.A, v));
}
static bool Capture(ref ILVariable pmvar, ILVariable v)
{
if (pmvar != null) return pmvar == v;
pmvar = v;
return true;
}
static readonly ILExpression[] EmptyArguments = new ILExpression[0];
public override ILExpression BuildNew(PatternMatcher pm)
{
var v = this.b ? pm.B : pm.A;
var e = new ILExpression(ILCode.Ldloc, v, EmptyArguments);
if (TypeAnalysis.IsNullableType(v.Type)) e = new ILExpression(ILCode.ValueOf, null, e);
return e;
}
}
sealed class BooleanPattern : Pattern
{
public static readonly Pattern False = new BooleanPattern(false), True = new BooleanPattern(true);
readonly object value;
BooleanPattern(bool value)
: base(null)
{
this.value = Convert.ToInt32(value);
}
public override bool Match(PatternMatcher pm, ILExpression e)
{
return e.Code == ILCode.Ldc_I4 && TypeAnalysis.IsBoolean(e.InferredType) && object.Equals(e.Operand, value);
}
public override ILExpression BuildNew(PatternMatcher pm)
{
// boolean constants are wrapped inside a container to disable simplyfication of equality comparisons
return new ILExpression(ILCode.Wrap, null, new ILExpression(ILCode.Ldc_I4, value));
}
}
static readonly Pattern VariableRefA = new VariablePattern(ILCode.Ldloca, false), VariableRefB = new VariablePattern(ILCode.Ldloca, true);
static readonly Pattern VariableA = new VariablePattern(ILCode.Ldloc, false), VariableB = new VariablePattern(ILCode.Ldloc, true);
static readonly Pattern VariableAHasValue = new MethodPattern(ILCode.CallGetter, "get_HasValue", VariableRefA);
static readonly Pattern VariableAGetValueOrDefault = new MethodPattern(ILCode.Call, "GetValueOrDefault", VariableRefA);
static readonly Pattern VariableBHasValue = new MethodPattern(ILCode.CallGetter, "get_HasValue", VariableRefB);
static readonly Pattern VariableBGetValueOrDefault = new MethodPattern(ILCode.Call, "GetValueOrDefault", VariableRefB);
static readonly Pattern CeqHasValue = new ILPattern(ILCode.Ceq, VariableAHasValue, VariableBHasValue);
static readonly Pattern CneHasValue = new ILPattern(ILCode.Cne, VariableAHasValue, VariableBHasValue);
static readonly Pattern AndHasValue = new ILPattern(ILCode.And, VariableAHasValue, VariableBHasValue);
static readonly Pattern Any = new AnyPattern();
static readonly Pattern OperatorVariableAB = new OperatorPattern();
static OperatorPattern OperatorNN(OperatorType type)
{
return new OperatorPattern(type, false);
}
static OperatorPattern OperatorNV(OperatorType type)
{
return new OperatorPattern(type, true);
}
static Pattern NewObj(Pattern p)
{
return new MethodPattern(ILCode.Newobj, ".ctor", p);
}
static readonly Pattern[] Comparisons = new Pattern[] {
/* both operands nullable */
// == (primitive, decimal)
OperatorNN(OperatorType.Equality) & CeqHasValue,
// == (struct)
CeqHasValue & (!VariableAHasValue | OperatorNN(OperatorType.Equality)),
// != (primitive, decimal)
OperatorNN(OperatorType.InEquality) | CneHasValue,
// != (struct)
CneHasValue | (VariableAHasValue & OperatorNN(OperatorType.InEquality)),
// > , < , >= , <= (primitive, decimal)
OperatorNN(OperatorType.Comparison) & AndHasValue,
// > , < , >= , <= (struct)
AndHasValue & OperatorNN(OperatorType.Comparison),
/* only one operand nullable */
// == (primitive, decimal)
OperatorNV(OperatorType.Equality) & VariableAHasValue,
// == (struct)
VariableAHasValue & OperatorNV(OperatorType.Equality),
// != (primitive, decimal)
OperatorNV(OperatorType.InEquality) | !VariableAHasValue,
// != (struct)
!VariableAHasValue | OperatorNV(OperatorType.InEquality),
// > , <, >= , <= (primitive, decimal)
OperatorNV(OperatorType.Comparison) & VariableAHasValue,
// > , < , >= , <= (struct)
VariableAHasValue & OperatorNV(OperatorType.Comparison),
};
static readonly Pattern[] Other = new Pattern[] {
/* both operands nullable */
// & (bool)
new ILPattern(ILCode.TernaryOp, VariableAGetValueOrDefault | (!VariableBGetValueOrDefault & !VariableAHasValue), VariableB, VariableA),
new ILPattern(ILCode.And, VariableA, VariableB),
// | (bool)
new ILPattern(ILCode.TernaryOp, VariableAGetValueOrDefault | (!VariableBGetValueOrDefault & !VariableAHasValue), VariableA, VariableB),
new ILPattern(ILCode.Or, VariableA, VariableB),
// null coalescing
new ILPattern(ILCode.TernaryOp, VariableAHasValue, NewObj(VariableAGetValueOrDefault), VariableB),
new ILPattern(ILCode.NullCoalescing, VariableA, VariableB),
// all other
new ILPattern(ILCode.TernaryOp, AndHasValue, NewObj(OperatorNN(OperatorType.Other)), new ILPattern(ILCode.DefaultValue)),
OperatorVariableAB,
/* only one operand nullable */
// & (bool)
new ILPattern(ILCode.TernaryOp, Any, VariableA, NewObj(BooleanPattern.False)),
new ILPattern(ILCode.And, VariableA, Any),
// | (bool)
new ILPattern(ILCode.TernaryOp, Any, NewObj(BooleanPattern.True), VariableA),
new ILPattern(ILCode.Or, VariableA, Any),
// == true
VariableAGetValueOrDefault & VariableAHasValue,
new ILPattern(ILCode.Ceq, VariableA, BooleanPattern.True),
// != true
!VariableAGetValueOrDefault | !VariableAHasValue,
new ILPattern(ILCode.Cne, VariableA, BooleanPattern.True),
// == false
!VariableAGetValueOrDefault & VariableAHasValue,
new ILPattern(ILCode.Ceq, VariableA, BooleanPattern.False),
// != false
VariableAGetValueOrDefault | !VariableAHasValue,
new ILPattern(ILCode.Cne, VariableA, BooleanPattern.False),
// ?? true
!VariableAHasValue | VariableAGetValueOrDefault,
new ILPattern(ILCode.NullCoalescing, VariableA, BooleanPattern.True),
// ?? false
VariableAHasValue & VariableAGetValueOrDefault,
new ILPattern(ILCode.NullCoalescing, VariableA, BooleanPattern.False),
// null coalescing
new ILPattern(ILCode.TernaryOp, VariableAHasValue, VariableAGetValueOrDefault, Any),
new ILPattern(ILCode.NullCoalescing, VariableA, Any),
// all other
new ILPattern(ILCode.TernaryOp, VariableAHasValue, NewObj(OperatorNV(OperatorType.Other)), new ILPattern(ILCode.DefaultValue)),
OperatorVariableAB,
};
ILVariable A, B;
ILExpression Operator, SimpleOperand;
bool SimpleLeftOperand;
void Reset()
{
this.A = null;
this.B = null;
this.Operator = null;
this.SimpleOperand = null;
this.SimpleLeftOperand = false;
}
bool Simplify(ILExpression expr)
{
if (expr.Code == ILCode.TernaryOp || expr.Code == ILCode.LogicAnd || expr.Code == ILCode.LogicOr) {
Pattern[] ps;
if (expr.Code != ILCode.TernaryOp) {
ps = Comparisons;
for (int i = 0; i < ps.Length; i++) {
this.Reset();
if (!ps[i].Match(this, expr)) continue;
SetResult(expr, OperatorVariableAB.BuildNew(this));
return true;
}
}
ps = Other;
for (int i = 0; i < ps.Length; i += 2) {
this.Reset();
if (!ps[i].Match(this, expr)) continue;
var n = ps[i + 1].BuildNew(this);
SetResult(expr, n);
if (n.Code == ILCode.NullCoalescing) {
// if both operands are nullable then the result is also nullable
if (n.Arguments[1].Code == ILCode.ValueOf) {
n.Arguments[0] = n.Arguments[0].Arguments[0];
n.Arguments[1] = n.Arguments[1].Arguments[0];
}
} else if (n.Code != ILCode.Ceq && n.Code != ILCode.Cne) {
expr.Code = ILCode.NullableOf;
expr.InferredType = expr.ExpectedType = null;
}
return true;
}
}
return false;
}
static void SetResult(ILExpression expr, ILExpression n)
{
// IL ranges from removed nodes are assigned to the new operator expression
var removednodes = expr.GetSelfAndChildrenRecursive<ILExpression>().Except(n.GetSelfAndChildrenRecursive<ILExpression>());
n.ILRanges = ILRange.OrderAndJoint(n.ILRanges.Concat(removednodes.SelectMany(el => el.ILRanges)));
// the new expression is wrapped in a container so that negations aren't pushed through lifted comparison operations
expr.Code = ILCode.Wrap;
expr.Arguments.Clear();
expr.Arguments.Add(n);
expr.ILRanges.Clear();
expr.InferredType = n.InferredType;
}
}
}
}

108
ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs

@ -397,9 +397,21 @@ namespace ICSharpCode.Decompiler.ILAst @@ -397,9 +397,21 @@ namespace ICSharpCode.Decompiler.ILAst
return false;
ILExpression op = expr.Arguments.Last();
if (!CanBeRepresentedAsCompoundAssignment(op.Code))
// in case of compound assignments with a lifted operator the result is inside NullableOf and the operand is inside ValueOf
bool liftedOperator = false;
if (op.Code == ILCode.NullableOf) {
op = op.Arguments[0];
liftedOperator = true;
}
if (!CanBeRepresentedAsCompoundAssignment(op))
return false;
ILExpression ldelem = op.Arguments[0];
if (liftedOperator) {
if (ldelem.Code != ILCode.ValueOf)
return false;
ldelem = ldelem.Arguments[0];
}
if (ldelem.Code != expectedLdelemCode)
return false;
Debug.Assert(ldelem.Arguments.Count == expr.Arguments.Count - 1);
@ -414,9 +426,9 @@ namespace ICSharpCode.Decompiler.ILAst @@ -414,9 +426,9 @@ namespace ICSharpCode.Decompiler.ILAst
return true;
}
static bool CanBeRepresentedAsCompoundAssignment(ILCode code)
static bool CanBeRepresentedAsCompoundAssignment(ILExpression expr)
{
switch (code) {
switch (expr.Code) {
case ILCode.Add:
case ILCode.Add_Ovf:
case ILCode.Add_Ovf_Un:
@ -437,6 +449,24 @@ namespace ICSharpCode.Decompiler.ILAst @@ -437,6 +449,24 @@ namespace ICSharpCode.Decompiler.ILAst
case ILCode.Shr:
case ILCode.Shr_Un:
return true;
case ILCode.Call:
var m = expr.Operand as MethodReference;
if (m == null || m.HasThis || expr.Arguments.Count != 2) return false;
switch (m.Name) {
case "op_Addition":
case "op_Subtraction":
case "op_Multiply":
case "op_Division":
case "op_Modulus":
case "op_BitwiseAnd":
case "op_BitwiseOr":
case "op_ExclusiveOr":
case "op_LeftShift":
case "op_RightShift":
return true;
default:
return false;
}
default:
return false;
}
@ -869,6 +899,78 @@ namespace ICSharpCode.Decompiler.ILAst @@ -869,6 +899,78 @@ namespace ICSharpCode.Decompiler.ILAst
}
#endregion
#region SimplifyLogicNot
static bool SimplifyLogicNot(List<ILNode> body, ILExpression expr, int pos)
{
bool modified = false;
expr = SimplifyLogicNot(expr, ref modified);
Debug.Assert(expr == null);
return modified;
}
static ILExpression SimplifyLogicNot(ILExpression expr, ref bool modified)
{
ILExpression a;
// "ceq(a, ldc.i4.0)" becomes "logicnot(a)" if the inferred type for expression "a" is boolean
if (expr.Code == ILCode.Ceq && TypeAnalysis.IsBoolean(expr.Arguments[0].InferredType) && (a = expr.Arguments[1]).Code == ILCode.Ldc_I4 && (int)a.Operand == 0) {
expr.Code = ILCode.LogicNot;
expr.ILRanges.AddRange(a.ILRanges);
expr.Arguments.RemoveAt(1);
modified = true;
}
ILExpression res = null;
while (expr.Code == ILCode.LogicNot) {
a = expr.Arguments[0];
// remove double negation
if (a.Code == ILCode.LogicNot) {
res = a.Arguments[0];
res.ILRanges.AddRange(expr.ILRanges);
res.ILRanges.AddRange(a.ILRanges);
expr = res;
} else {
if (SimplifyLogicNotArgument(expr)) res = expr = a;
break;
}
}
for (int i = 0; i < expr.Arguments.Count; i++) {
a = SimplifyLogicNot(expr.Arguments[i], ref modified);
if (a != null) {
expr.Arguments[i] = a;
modified = true;
}
}
return res;
}
/// <summary>
/// If the argument is a binary comparison operation then the negation is pushed through it
/// </summary>
static bool SimplifyLogicNotArgument(ILExpression expr)
{
var a = expr.Arguments[0];
ILCode c;
switch (a.Code) {
case ILCode.Ceq: c = ILCode.Cne; break;
case ILCode.Cne: c = ILCode.Ceq; break;
case ILCode.Cgt: c = ILCode.Cle; break;
case ILCode.Cgt_Un: c = ILCode.Cle_Un; break;
case ILCode.Cge: c = ILCode.Clt; break;
case ILCode.Cge_Un: c = ILCode.Clt_Un; break;
case ILCode.Clt: c = ILCode.Cge; break;
case ILCode.Clt_Un: c = ILCode.Cge_Un; break;
case ILCode.Cle: c = ILCode.Cgt; break;
case ILCode.Cle_Un: c = ILCode.Cgt_Un; break;
default: return false;
}
a.Code = c;
a.ILRanges.AddRange(expr.ILRanges);
return true;
}
#endregion
#region SimplifyShiftOperators
static bool SimplifyShiftOperators(List<ILNode> body, ILExpression expr, int pos)
{

10
ICSharpCode.Decompiler/ILAst/SimpleControlFlow.cs

@ -98,16 +98,16 @@ namespace ICSharpCode.Decompiler.ILAst @@ -98,16 +98,16 @@ namespace ICSharpCode.Decompiler.ILAst
if (leftBoolVal != 0) {
newExpr = condExpr;
} else {
newExpr = new ILExpression(ILCode.LogicNot, null, condExpr);
newExpr = new ILExpression(ILCode.LogicNot, null, condExpr) { InferredType = typeSystem.Boolean };
}
} else if (retTypeIsBoolean && trueExpr.Match(ILCode.Ldc_I4, out leftBoolVal)) {
} else if ((retTypeIsBoolean || TypeAnalysis.IsBoolean(falseExpr.InferredType)) && trueExpr.Match(ILCode.Ldc_I4, out leftBoolVal) && (leftBoolVal == 0 || leftBoolVal == 1)) {
// It can be expressed as logical expression
if (leftBoolVal != 0) {
newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicOr, condExpr, falseExpr);
} else {
newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicAnd, new ILExpression(ILCode.LogicNot, null, condExpr), falseExpr);
}
} else if (retTypeIsBoolean && falseExpr.Match(ILCode.Ldc_I4, out rightBoolVal)) {
} else if ((retTypeIsBoolean || TypeAnalysis.IsBoolean(trueExpr.InferredType)) && falseExpr.Match(ILCode.Ldc_I4, out rightBoolVal) && (rightBoolVal == 0 || rightBoolVal == 1)) {
// It can be expressed as logical expression
if (rightBoolVal != 0) {
newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicOr, new ILExpression(ILCode.LogicNot, null, condExpr), trueExpr);
@ -343,10 +343,10 @@ namespace ICSharpCode.Decompiler.ILAst @@ -343,10 +343,10 @@ namespace ICSharpCode.Decompiler.ILAst
ILExpression current = right;
while(current.Arguments[0].Match(code))
current = current.Arguments[0];
current.Arguments[0] = new ILExpression(code, null, left, current.Arguments[0]);
current.Arguments[0] = new ILExpression(code, null, left, current.Arguments[0]) { InferredType = typeSystem.Boolean };
return right;
} else {
return new ILExpression(code, null, left, right);
return new ILExpression(code, null, left, right) { InferredType = typeSystem.Boolean };
}
}

144
ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs

@ -280,15 +280,9 @@ namespace ICSharpCode.Decompiler.ILAst @@ -280,15 +280,9 @@ namespace ICSharpCode.Decompiler.ILAst
if (forceInferChildren) {
InferTypeForExpression(expr.Arguments[0], typeSystem.Boolean);
}
return TypeWithMoreInformation(
InferTypeForExpression(expr.Arguments[1], expectedType, forceInferChildren),
InferTypeForExpression(expr.Arguments[2], expectedType, forceInferChildren)
);
return InferBinaryArguments(expr.Arguments[1], expr.Arguments[2], expectedType, forceInferChildren);
case ILCode.NullCoalescing:
return TypeWithMoreInformation(
InferTypeForExpression(expr.Arguments[0], expectedType, forceInferChildren),
InferTypeForExpression(expr.Arguments[1], expectedType, forceInferChildren)
);
return InferBinaryArguments(expr.Arguments[0], expr.Arguments[1], expectedType, forceInferChildren);
#endregion
#region Variable load/store
case ILCode.Stloc:
@ -472,7 +466,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -472,7 +466,7 @@ namespace ICSharpCode.Decompiler.ILAst
if (forceInferChildren) {
InferTypeForExpression(expr.Arguments[0], typeSystem.TypedReference);
}
return new TypeReference("System", "RuntimeTypeHandle", module, module, true);
return new TypeReference("System", "RuntimeTypeHandle", module, module.TypeSystem.Corlib, true);
case ILCode.Refanyval:
if (forceInferChildren) {
InferTypeForExpression(expr.Arguments[0], typeSystem.TypedReference);
@ -483,6 +477,10 @@ namespace ICSharpCode.Decompiler.ILAst @@ -483,6 +477,10 @@ namespace ICSharpCode.Decompiler.ILAst
TypeReference t = InferTypeForExpression(expr.Arguments[0], UnpackPointer(expectedType));
return t != null ? new ByReferenceType(t) : null;
}
case ILCode.ValueOf:
return GetNullableTypeArgument(InferTypeForExpression(expr.Arguments[0], CreateNullableType(expectedType)));
case ILCode.NullableOf:
return CreateNullableType(InferTypeForExpression(expr.Arguments[0], GetNullableTypeArgument(expectedType)));
#endregion
#region Arithmetic instructions
case ILCode.Not: // bitwise complement
@ -557,7 +555,9 @@ namespace ICSharpCode.Decompiler.ILAst @@ -557,7 +555,9 @@ namespace ICSharpCode.Decompiler.ILAst
}
case ILCode.CompoundAssignment:
{
TypeReference varType = InferTypeForExpression(expr.Arguments[0].Arguments[0], null);
var op = expr.Arguments[0];
if (op.Code == ILCode.NullableOf) op = op.Arguments[0].Arguments[0];
var varType = InferTypeForExpression(op.Arguments[0], null);
if (forceInferChildren) {
InferTypeForExpression(expr.Arguments[0], varType);
}
@ -593,16 +593,16 @@ namespace ICSharpCode.Decompiler.ILAst @@ -593,16 +593,16 @@ namespace ICSharpCode.Decompiler.ILAst
case ILCode.Ldc_R8:
return typeSystem.Double;
case ILCode.Ldc_Decimal:
return new TypeReference("System", "Decimal", module, module, true);
return new TypeReference("System", "Decimal", module, module.TypeSystem.Corlib, true);
case ILCode.Ldtoken:
if (expr.Operand is TypeReference)
return new TypeReference("System", "RuntimeTypeHandle", module, module, true);
return new TypeReference("System", "RuntimeTypeHandle", module, module.TypeSystem.Corlib, true);
else if (expr.Operand is FieldReference)
return new TypeReference("System", "RuntimeFieldHandle", module, module, true);
return new TypeReference("System", "RuntimeFieldHandle", module, module.TypeSystem.Corlib, true);
else
return new TypeReference("System", "RuntimeMethodHandle", module, module, true);
return new TypeReference("System", "RuntimeMethodHandle", module, module.TypeSystem.Corlib, true);
case ILCode.Arglist:
return new TypeReference("System", "RuntimeArgumentHandle", module, module, true);
return new TypeReference("System", "RuntimeArgumentHandle", module, module.TypeSystem.Corlib, true);
#endregion
#region Array instructions
case ILCode.Newarr:
@ -735,22 +735,30 @@ namespace ICSharpCode.Decompiler.ILAst @@ -735,22 +735,30 @@ namespace ICSharpCode.Decompiler.ILAst
return tr.IsValueType ? typeSystem.Object : tr;
}
case ILCode.Box:
if (forceInferChildren)
InferTypeForExpression(expr.Arguments.Single(), (TypeReference)expr.Operand);
return (TypeReference)expr.Operand;
{
var tr = (TypeReference)expr.Operand;
if (forceInferChildren)
InferTypeForExpression(expr.Arguments.Single(), tr);
return tr.IsValueType ? typeSystem.Object : tr;
}
#endregion
#region Comparison instructions
case ILCode.Ceq:
case ILCode.Cne:
if (forceInferChildren)
InferArgumentsInBinaryOperator(expr, null, null);
return typeSystem.Boolean;
case ILCode.Clt:
case ILCode.Cgt:
case ILCode.Cle:
case ILCode.Cge:
if (forceInferChildren)
InferArgumentsInBinaryOperator(expr, true, null);
return typeSystem.Boolean;
case ILCode.Clt_Un:
case ILCode.Cgt_Un:
case ILCode.Cle_Un:
case ILCode.Cge_Un:
if (forceInferChildren)
InferArgumentsInBinaryOperator(expr, false, null);
return typeSystem.Boolean;
@ -787,8 +795,12 @@ namespace ICSharpCode.Decompiler.ILAst @@ -787,8 +795,12 @@ namespace ICSharpCode.Decompiler.ILAst
#endregion
case ILCode.Pop:
return null;
case ILCode.Wrap:
case ILCode.Dup:
return InferTypeForExpression(expr.Arguments.Single(), expectedType);
{
var arg = expr.Arguments.Single();
return arg.ExpectedType = InferTypeForExpression(expr.Arguments.Single(), expectedType);
}
default:
Debug.WriteLine("Type Inference: Can't handle " + expr.Code.GetName());
return null;
@ -934,25 +946,24 @@ namespace ICSharpCode.Decompiler.ILAst @@ -934,25 +946,24 @@ namespace ICSharpCode.Decompiler.ILAst
type = ((TypeSpecification)type).ElementType;
return type;
}
static TypeReference GetNullableTypeArgument(TypeReference type)
{
var t = type as GenericInstanceType;
return IsNullableType(t) ? t.GenericArguments[0] : type;
}
GenericInstanceType CreateNullableType(TypeReference type)
{
if (type == null) return null;
var t = new GenericInstanceType(new TypeReference("System", "Nullable`1", module, module.TypeSystem.Corlib, true));
t.GenericArguments.Add(type);
return t;
}
TypeReference InferArgumentsInBinaryOperator(ILExpression expr, bool? isSigned, TypeReference expectedType)
{
ILExpression left = expr.Arguments[0];
ILExpression right = expr.Arguments[1];
TypeReference leftPreferred = DoInferTypeForExpression(left, expectedType);
TypeReference rightPreferred = DoInferTypeForExpression(right, expectedType);
if (IsSameType(leftPreferred, rightPreferred)) {
return left.InferredType = right.InferredType = left.ExpectedType = right.ExpectedType = leftPreferred;
} else if (IsSameType(rightPreferred, DoInferTypeForExpression(left, rightPreferred))) {
return left.InferredType = right.InferredType = left.ExpectedType = right.ExpectedType = rightPreferred;
} else if (IsSameType(leftPreferred, DoInferTypeForExpression(right, leftPreferred))) {
return left.InferredType = right.InferredType = left.ExpectedType = right.ExpectedType = leftPreferred;
} else {
left.ExpectedType = right.ExpectedType = TypeWithMoreInformation(leftPreferred, rightPreferred);
left.InferredType = DoInferTypeForExpression(left, left.ExpectedType);
right.InferredType = DoInferTypeForExpression(right, right.ExpectedType);
return left.ExpectedType;
}
return InferBinaryArguments(expr.Arguments[0], expr.Arguments[1], expectedType);
}
TypeReference InferArgumentsInAddition(ILExpression expr, bool? isSigned, TypeReference expectedType)
@ -964,25 +975,14 @@ namespace ICSharpCode.Decompiler.ILAst @@ -964,25 +975,14 @@ namespace ICSharpCode.Decompiler.ILAst
left.InferredType = left.ExpectedType = leftPreferred;
InferTypeForExpression(right, typeSystem.IntPtr);
return leftPreferred;
} else {
TypeReference rightPreferred = DoInferTypeForExpression(right, expectedType);
if (rightPreferred is PointerType) {
InferTypeForExpression(left, typeSystem.IntPtr);
right.InferredType = right.ExpectedType = rightPreferred;
return rightPreferred;
} else if (IsSameType(leftPreferred, rightPreferred)) {
return left.InferredType = right.InferredType = left.ExpectedType = right.ExpectedType = leftPreferred;
} else if (IsSameType(rightPreferred, DoInferTypeForExpression(left, rightPreferred))) {
return left.InferredType = right.InferredType = left.ExpectedType = right.ExpectedType = rightPreferred;
} else if (IsSameType(leftPreferred, DoInferTypeForExpression(right, leftPreferred))) {
return left.InferredType = right.InferredType = left.ExpectedType = right.ExpectedType = leftPreferred;
} else {
left.ExpectedType = right.ExpectedType = TypeWithMoreInformation(leftPreferred, rightPreferred);
left.InferredType = DoInferTypeForExpression(left, left.ExpectedType);
right.InferredType = DoInferTypeForExpression(right, right.ExpectedType);
return left.ExpectedType;
}
}
TypeReference rightPreferred = DoInferTypeForExpression(right, expectedType);
if (rightPreferred is PointerType) {
InferTypeForExpression(left, typeSystem.IntPtr);
right.InferredType = right.ExpectedType = rightPreferred;
return rightPreferred;
}
return InferBinaryArguments(left, right, expectedType, leftPreferred: leftPreferred, rightPreferred: rightPreferred);
}
TypeReference InferArgumentsInSubtraction(ILExpression expr, bool? isSigned, TypeReference expectedType)
@ -994,20 +994,27 @@ namespace ICSharpCode.Decompiler.ILAst @@ -994,20 +994,27 @@ namespace ICSharpCode.Decompiler.ILAst
left.InferredType = left.ExpectedType = leftPreferred;
InferTypeForExpression(right, typeSystem.IntPtr);
return leftPreferred;
}
return InferBinaryArguments(left, right, expectedType, leftPreferred: leftPreferred);
}
TypeReference InferBinaryArguments(ILExpression left, ILExpression right, TypeReference expectedType, bool forceInferChildren = false, TypeReference leftPreferred = null, TypeReference rightPreferred = null)
{
if (leftPreferred == null) leftPreferred = DoInferTypeForExpression(left, expectedType, forceInferChildren);
if (rightPreferred == null) rightPreferred = DoInferTypeForExpression(right, expectedType, forceInferChildren);
if (IsSameType(leftPreferred, rightPreferred)) {
return left.InferredType = right.InferredType = left.ExpectedType = right.ExpectedType = leftPreferred;
} else if (IsSameType(rightPreferred, DoInferTypeForExpression(left, rightPreferred, forceInferChildren))) {
return left.InferredType = right.InferredType = left.ExpectedType = right.ExpectedType = rightPreferred;
} else if (IsSameType(leftPreferred, DoInferTypeForExpression(right, leftPreferred, forceInferChildren))) {
// re-infer the left expression with the preferred type to reset any conflicts caused by the rightPreferred type
DoInferTypeForExpression(left, leftPreferred, forceInferChildren);
return left.InferredType = right.InferredType = left.ExpectedType = right.ExpectedType = leftPreferred;
} else {
TypeReference rightPreferred = DoInferTypeForExpression(right, expectedType);
if (IsSameType(leftPreferred, rightPreferred)) {
return left.InferredType = right.InferredType = left.ExpectedType = right.ExpectedType = leftPreferred;
} else if (IsSameType(rightPreferred, DoInferTypeForExpression(left, rightPreferred))) {
return left.InferredType = right.InferredType = left.ExpectedType = right.ExpectedType = rightPreferred;
} else if (IsSameType(leftPreferred, DoInferTypeForExpression(right, leftPreferred))) {
return left.InferredType = right.InferredType = left.ExpectedType = right.ExpectedType = leftPreferred;
} else {
left.ExpectedType = right.ExpectedType = TypeWithMoreInformation(leftPreferred, rightPreferred);
left.InferredType = DoInferTypeForExpression(left, left.ExpectedType);
right.InferredType = DoInferTypeForExpression(right, right.ExpectedType);
return left.ExpectedType;
}
left.ExpectedType = right.ExpectedType = TypeWithMoreInformation(leftPreferred, rightPreferred);
left.InferredType = DoInferTypeForExpression(left, left.ExpectedType, forceInferChildren);
right.InferredType = DoInferTypeForExpression(right, right.ExpectedType, forceInferChildren);
return left.ExpectedType;
}
}
@ -1152,6 +1159,11 @@ namespace ICSharpCode.Decompiler.ILAst @@ -1152,6 +1159,11 @@ namespace ICSharpCode.Decompiler.ILAst
}
return false;
}
internal static bool IsNullableType(TypeReference type)
{
return type != null && type.Name == "Nullable`1" && type.Namespace == "System";
}
public static TypeCode GetTypeCode(TypeReference type)
{

3
ICSharpCode.Decompiler/ILAst/YieldReturnDecompiler.cs

@ -634,13 +634,14 @@ namespace ICSharpCode.Decompiler.ILAst @@ -634,13 +634,14 @@ namespace ICSharpCode.Decompiler.ILAst
case ILCode.Ldc_I4:
return new SymbolicValue(SymbolicValueType.IntegerConstant, (int)expr.Operand);
case ILCode.Ceq:
case ILCode.Cne:
left = Eval(expr.Arguments[0]);
right = Eval(expr.Arguments[1]);
if (left.Type != SymbolicValueType.State || right.Type != SymbolicValueType.IntegerConstant)
throw new YieldAnalysisFailedException();
// bool: (state + left.Constant == right.Constant)
// bool: (state == right.Constant - left.Constant)
return new SymbolicValue(SymbolicValueType.StateEquals, unchecked ( right.Constant - left.Constant ));
return new SymbolicValue(expr.Code == ILCode.Ceq ? SymbolicValueType.StateEquals : SymbolicValueType.StateInEquals, unchecked(right.Constant - left.Constant));
case ILCode.LogicNot:
SymbolicValue val = Eval(expr.Arguments[0]);
if (val.Type == SymbolicValueType.StateEquals)

8
ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj

@ -23,6 +23,13 @@ @@ -23,6 +23,13 @@
<BaseAddress>4194304</BaseAddress>
<FileAlignment>4096</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Platform)' == 'AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<RegisterForComInterop>False</RegisterForComInterop>
<GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies>
<BaseAddress>4194304</BaseAddress>
<FileAlignment>4096</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<OutputPath>..\bin\Debug\</OutputPath>
<DebugSymbols>true</DebugSymbols>
@ -57,6 +64,7 @@ @@ -57,6 +64,7 @@
<ItemGroup>
<Compile Include="CallOverloadedMethod.cs" />
<Compile Include="CheckedUnchecked.cs" />
<Compile Include="LiftedOperators.cs" />
<Compile Include="CustomShortCircuitOperators.cs" />
<Compile Include="Helpers\CodeAssert.cs" />
<Compile Include="IncrementDecrement.cs" />

12
ICSharpCode.Decompiler/Tests/InitializerTests.cs

@ -532,9 +532,9 @@ public class InitializerTests @@ -532,9 +532,9 @@ public class InitializerTests
});
}
public void MultidimensionalInit()
public int[,] MultidimensionalInit()
{
int[,] expr_09 = new int[, ]
return new int[, ]
{
{
@ -651,9 +651,9 @@ public class InitializerTests @@ -651,9 +651,9 @@ public class InitializerTests
};
}
public void MultidimensionalInit2()
public int[][,] MultidimensionalInit2()
{
int[][,] array = new int[][,]
return new int[][,]
{
new int[, ]
{
@ -785,9 +785,9 @@ public class InitializerTests @@ -785,9 +785,9 @@ public class InitializerTests
};
}
public void ArrayOfArrayOfArrayInit()
public int[][,,] ArrayOfArrayOfArrayInit()
{
int[][,,] array = new int[][,,]
return new int[][,,]
{
new int[, , ]
{

830
ICSharpCode.Decompiler/Tests/LiftedOperators.cs

@ -0,0 +1,830 @@ @@ -0,0 +1,830 @@
// Copyright (c) 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;
using System.Runtime.InteropServices;
public static class LiftedOperators
{
// C# uses 4 different patterns of IL for lifted operators: bool, other primitive types, decimal, other structs.
// Different patterns are used depending on whether both of the operands are nullable or only the left/right operand is nullable.
// Negation must not be pushed through such comparisons because it would change the semantics.
// A comparison used in a condition differs somewhat from a comparison used as a simple value.
public static void BoolBasic(bool? a, bool? b)
{
if (a == b)
{
Console.WriteLine();
}
if (a != b)
{
Console.WriteLine();
}
if (!(a == b))
{
Console.WriteLine();
}
if (!(a != b))
{
Console.WriteLine();
}
}
public static void BoolComplex(bool? a, Func<bool> x)
{
if (a == x())
{
Console.WriteLine();
}
if (a != x())
{
Console.WriteLine();
}
if (x() == a)
{
Console.WriteLine();
}
if (x() != a)
{
Console.WriteLine();
}
if (!(a == x()))
{
Console.WriteLine();
}
if (!(a != x()))
{
Console.WriteLine();
}
if (!(x() == a))
{
Console.WriteLine();
}
if (!(x() != a))
{
Console.WriteLine();
}
}
public static void BoolConst(bool? a)
{
if (a == true)
{
Console.WriteLine();
}
if (a != true)
{
Console.WriteLine();
}
if (a == false)
{
Console.WriteLine();
}
if (a != false)
{
Console.WriteLine();
}
if (a ?? true)
{
Console.WriteLine();
}
if (a ?? false)
{
Console.WriteLine();
}
}
public static void BoolValueBasic(bool? a, bool? b)
{
Console.WriteLine(a == b);
Console.WriteLine(a != b);
Console.WriteLine(!(a == b));
Console.WriteLine(!(a != b));
Console.WriteLine(a & b);
Console.WriteLine(a | b);
Console.WriteLine(a ^ b);
Console.WriteLine(a ?? b);
Console.WriteLine(!a);
a &= b;
a |= b;
a ^= b;
}
public static void BoolValueComplex(bool? a, Func<bool> x)
{
Console.WriteLine(a == x());
Console.WriteLine(a != x());
Console.WriteLine(x() == a);
Console.WriteLine(x() != a);
Console.WriteLine(!(a == x()));
Console.WriteLine(!(a != x()));
Console.WriteLine(a & x());
Console.WriteLine(a | x());
Console.WriteLine(a ^ x());
Console.WriteLine(a ?? x());
a &= x();
a |= x();
a ^= x();
Console.WriteLine(x() ^ a);
(new bool?[0])[0] ^= x();
}
public static void BoolValueConst(bool? a)
{
Console.WriteLine(a == true);
Console.WriteLine(a != true);
Console.WriteLine(a == false);
Console.WriteLine(a != false);
Console.WriteLine(a ?? true);
Console.WriteLine(a ?? false);
}
public static void IntBasic(int? a, int? b)
{
if (a == b)
{
Console.WriteLine();
}
if (a != b)
{
Console.WriteLine();
}
if (a > b)
{
Console.WriteLine();
}
if (a < b)
{
Console.WriteLine();
}
if (a >= b)
{
Console.WriteLine();
}
if (a <= b)
{
Console.WriteLine();
}
if (!(a == b))
{
Console.WriteLine();
}
if (!(a != b))
{
Console.WriteLine();
}
if (!(a > b))
{
Console.WriteLine();
}
}
public static void IntComplex(int? a, Func<int> x)
{
if (a == x())
{
Console.WriteLine();
}
if (a != x())
{
Console.WriteLine();
}
if (a > x())
{
Console.WriteLine();
}
if (x() == a)
{
Console.WriteLine();
}
if (x() != a)
{
Console.WriteLine();
}
if (x() > a)
{
Console.WriteLine();
}
if (!(a == x()))
{
Console.WriteLine();
}
if (!(a != x()))
{
Console.WriteLine();
}
if (!(a > x()))
{
Console.WriteLine();
}
}
public static void IntConst(int? a)
{
if (a == 2)
{
Console.WriteLine();
}
if (a != 2)
{
Console.WriteLine();
}
if (a > 2)
{
Console.WriteLine();
}
if (2 == a)
{
Console.WriteLine();
}
if (2 != a)
{
Console.WriteLine();
}
if (2 > a)
{
Console.WriteLine();
}
}
public static void IntValueBasic(int? a, int? b)
{
Console.WriteLine(a == b);
Console.WriteLine(a != b);
Console.WriteLine(a > b);
Console.WriteLine(!(a == b));
Console.WriteLine(!(a != b));
Console.WriteLine(!(a > b));
Console.WriteLine(a + b);
Console.WriteLine(a - b);
Console.WriteLine(a * b);
Console.WriteLine(a / b);
Console.WriteLine(a % b);
Console.WriteLine(a & b);
Console.WriteLine(a | b);
Console.WriteLine(a ^ b);
Console.WriteLine(a << b);
Console.WriteLine(a >> b);
Console.WriteLine(a ?? b);
Console.WriteLine(-a);
Console.WriteLine(~a);
// TODO:
//Console.WriteLine(a++);
//Console.WriteLine(a--);
Console.WriteLine(++a);
Console.WriteLine(--a);
a += b;
a -= b;
a *= b;
a /= b;
a %= b;
a &= b;
a |= b;
a ^= b;
a <<= b;
a >>= b;
}
public static void IntValueComplex(int? a, Func<int> x)
{
Console.WriteLine(a == x());
Console.WriteLine(a != x());
Console.WriteLine(a > x());
Console.WriteLine(x() == a);
Console.WriteLine(x() != a);
Console.WriteLine(x() > a);
Console.WriteLine(a + x());
Console.WriteLine(a - x());
Console.WriteLine(a * x());
Console.WriteLine(a / x());
Console.WriteLine(a % x());
Console.WriteLine(a & x());
Console.WriteLine(a | x());
Console.WriteLine(a ^ x());
Console.WriteLine(a << x());
Console.WriteLine(a >> x());
Console.WriteLine(a ?? x());
a += x();
a -= x();
a *= x();
a /= x();
a %= x();
a &= x();
a |= x();
a ^= x();
a <<= x();
a >>= x();
Console.WriteLine(x() + a);
(new int?[0])[0] += x();
}
public static void IntValueConst(int? a)
{
Console.WriteLine(a == 2);
Console.WriteLine(a != 2);
Console.WriteLine(a > 2);
Console.WriteLine(2 == a);
Console.WriteLine(2 != a);
Console.WriteLine(2 > a);
Console.WriteLine(a + 2);
Console.WriteLine(a - 2);
Console.WriteLine(a * 2);
Console.WriteLine(a / 2);
Console.WriteLine(a % 2);
Console.WriteLine(a & 2);
Console.WriteLine(a | 2);
Console.WriteLine(a ^ 2);
Console.WriteLine(a << 2);
Console.WriteLine(a >> 2);
Console.WriteLine(a ?? 2);
a += 2;
a -= 2;
a *= 2;
a /= 2;
a %= 2;
a &= 2;
a |= 2;
a ^= 2;
a <<= 2;
a >>= 2;
Console.WriteLine(2 + a);
}
public static void NumberBasic(decimal? a, decimal? b)
{
if (a == b)
{
Console.WriteLine();
}
if (a != b)
{
Console.WriteLine();
}
if (a > b)
{
Console.WriteLine();
}
if (a < b)
{
Console.WriteLine();
}
if (a >= b)
{
Console.WriteLine();
}
if (a <= b)
{
Console.WriteLine();
}
if (!(a == b))
{
Console.WriteLine();
}
if (!(a != b))
{
Console.WriteLine();
}
if (!(a > b))
{
Console.WriteLine();
}
}
public static void NumberComplex(decimal? a, Func<decimal> x)
{
if (a == x())
{
Console.WriteLine();
}
if (a != x())
{
Console.WriteLine();
}
if (a > x())
{
Console.WriteLine();
}
if (x() == a)
{
Console.WriteLine();
}
if (x() != a)
{
Console.WriteLine();
}
if (x() > a)
{
Console.WriteLine();
}
}
public static void NumberConst(decimal? a)
{
if (a == 2m)
{
Console.WriteLine();
}
if (a != 2m)
{
Console.WriteLine();
}
if (a > 2m)
{
Console.WriteLine();
}
if (2m == a)
{
Console.WriteLine();
}
if (2m != a)
{
Console.WriteLine();
}
if (2m > a)
{
Console.WriteLine();
}
}
public static void NumberValueBasic(decimal? a, decimal? b)
{
Console.WriteLine(a == b);
Console.WriteLine(a != b);
Console.WriteLine(a > b);
Console.WriteLine(!(a == b));
Console.WriteLine(!(a != b));
Console.WriteLine(!(a > b));
Console.WriteLine(a + b);
Console.WriteLine(a - b);
Console.WriteLine(a * b);
Console.WriteLine(a / b);
Console.WriteLine(a % b);
Console.WriteLine(a ?? b);
Console.WriteLine(-a);
// TODO:
//Console.WriteLine(a++);
//Console.WriteLine(a--);
//Console.WriteLine(++a);
//Console.WriteLine(--a);
a += b;
a -= b;
a *= b;
a /= b;
a %= b;
}
public static void NumberValueComplex(decimal? a, Func<decimal> x)
{
Console.WriteLine(a == x());
Console.WriteLine(a != x());
Console.WriteLine(a > x());
Console.WriteLine(x() == a);
Console.WriteLine(x() != a);
Console.WriteLine(x() > a);
Console.WriteLine(a + x());
Console.WriteLine(a - x());
Console.WriteLine(a * x());
Console.WriteLine(a / x());
Console.WriteLine(a % x());
Console.WriteLine(a ?? x());
a += x();
a -= x();
a *= x();
a /= x();
a %= x();
Console.WriteLine(x() + a);
(new decimal?[0])[0] += x();
}
public static void NumberValueConst(decimal? a)
{
Console.WriteLine(a == 2m);
Console.WriteLine(a != 2m);
Console.WriteLine(a > 2m);
Console.WriteLine(2m == a);
Console.WriteLine(2m != a);
Console.WriteLine(2m > a);
Console.WriteLine(a + 2m);
Console.WriteLine(a - 2m);
Console.WriteLine(a * 2m);
Console.WriteLine(a / 2m);
Console.WriteLine(a % 2m);
Console.WriteLine(a ?? 2m);
a += 2m;
a -= 2m;
a *= 2m;
a /= 2m;
a %= 2m;
Console.WriteLine(2m + a);
}
public static void StructBasic(TS? a, TS? b)
{
if (a == b)
{
Console.WriteLine();
}
if (a != b)
{
Console.WriteLine();
}
if (a > b)
{
Console.WriteLine();
}
if (a < b)
{
Console.WriteLine();
}
if (a >= b)
{
Console.WriteLine();
}
if (a <= b)
{
Console.WriteLine();
}
if (!(a == b))
{
Console.WriteLine();
}
if (!(a != b))
{
Console.WriteLine();
}
if (!(a > b))
{
Console.WriteLine();
}
}
public static void StructComplex(TS? a, Func<TS> x)
{
if (a == x())
{
Console.WriteLine();
}
if (a != x())
{
Console.WriteLine();
}
if (a > x())
{
Console.WriteLine();
}
if (x() == a)
{
Console.WriteLine();
}
if (x() != a)
{
Console.WriteLine();
}
if (x() > a)
{
Console.WriteLine();
}
}
public static void StructValueBasic(TS? a, TS? b, int? i)
{
Console.WriteLine(a == b);
Console.WriteLine(a != b);
Console.WriteLine(a > b);
Console.WriteLine(!(a == b));
Console.WriteLine(!(a != b));
Console.WriteLine(!(a > b));
Console.WriteLine(a + b);
Console.WriteLine(a - b);
Console.WriteLine(a * b);
Console.WriteLine(a / b);
Console.WriteLine(a % b);
Console.WriteLine(a & b);
Console.WriteLine(a | b);
Console.WriteLine(a ^ b);
Console.WriteLine(a << i);
Console.WriteLine(a >> i);
Console.WriteLine(a ?? b);
Console.WriteLine(+a);
Console.WriteLine(-a);
Console.WriteLine(!a);
Console.WriteLine(~a);
// TODO:
//Console.WriteLine(a++);
//Console.WriteLine(a--);
//Console.WriteLine(++a);
//Console.WriteLine(--a);
//Console.WriteLine((int?)a);
a += b;
a -= b;
a *= b;
a /= b;
a %= b;
a &= b;
a |= b;
a ^= b;
a <<= i;
a >>= i;
}
public static void StructValueComplex(TS? a, Func<TS> x, Func<int> i)
{
Console.WriteLine(a == x());
Console.WriteLine(a != x());
Console.WriteLine(a > x());
Console.WriteLine(x() == a);
Console.WriteLine(x() != a);
Console.WriteLine(x() > a);
Console.WriteLine(a + x());
Console.WriteLine(a - x());
Console.WriteLine(a * x());
Console.WriteLine(a / x());
Console.WriteLine(a % x());
Console.WriteLine(a & x());
Console.WriteLine(a | x());
Console.WriteLine(a ^ x());
Console.WriteLine(a << i());
Console.WriteLine(a >> i());
Console.WriteLine(a ?? x());
a += x();
a -= x();
a *= x();
a /= x();
a %= x();
a &= x();
a |= x();
a ^= x();
a <<= i();
a >>= i();
Console.WriteLine(x() + a);
(new TS?[0])[0] += x();
}
}
// dummy structure for testing custom operators
[StructLayout(LayoutKind.Sequential, Size = 1)]
public struct TS
{
// unary
public static TS operator +(TS a)
{
throw null;
}
public static TS operator -(TS a)
{
throw null;
}
public static TS operator !(TS a)
{
throw null;
}
public static TS operator ~(TS a)
{
throw null;
}
public static TS operator ++(TS a)
{
throw null;
}
public static TS operator --(TS a)
{
throw null;
}
public static explicit operator int(TS a)
{
throw null;
}
// binary
public static TS operator +(TS a, TS b)
{
throw null;
}
public static TS operator -(TS a, TS b)
{
throw null;
}
public static TS operator *(TS a, TS b)
{
throw null;
}
public static TS operator /(TS a, TS b)
{
throw null;
}
public static TS operator %(TS a, TS b)
{
throw null;
}
public static TS operator &(TS a, TS b)
{
throw null;
}
public static TS operator |(TS a, TS b)
{
throw null;
}
public static TS operator ^(TS a, TS b)
{
throw null;
}
public static TS operator <<(TS a, int b)
{
throw null;
}
public static TS operator >>(TS a, int b)
{
throw null;
}
// comparisons
public static bool operator ==(TS a, TS b)
{
throw null;
}
public static bool operator !=(TS a, TS b)
{
throw null;
}
public static bool operator <(TS a, TS b)
{
throw null;
}
public static bool operator <=(TS a, TS b)
{
throw null;
}
public static bool operator >(TS a, TS b)
{
throw null;
}
public static bool operator >=(TS a, TS b)
{
throw null;
}
public override bool Equals(object obj)
{
throw null;
}
public override int GetHashCode()
{
throw null;
}
}

20
ICSharpCode.Decompiler/Tests/TestRunner.cs

@ -55,7 +55,7 @@ namespace ICSharpCode.Decompiler.Tests @@ -55,7 +55,7 @@ namespace ICSharpCode.Decompiler.Tests
[Test]
public void ExceptionHandling()
{
TestFile(@"..\..\Tests\ExceptionHandling.cs");
TestFile(@"..\..\Tests\ExceptionHandling.cs", false);
}
[Test]
@ -81,6 +81,12 @@ namespace ICSharpCode.Decompiler.Tests @@ -81,6 +81,12 @@ namespace ICSharpCode.Decompiler.Tests
{
TestFile(@"..\..\Tests\InitializerTests.cs");
}
[Test]
public void LiftedOperators()
{
TestFile(@"..\..\Tests\LiftedOperators.cs");
}
[Test]
public void Loops()
@ -149,9 +155,15 @@ namespace ICSharpCode.Decompiler.Tests @@ -149,9 +155,15 @@ namespace ICSharpCode.Decompiler.Tests
}
static void TestFile(string fileName)
{
TestFile(fileName, false);
TestFile(fileName, true);
}
static void TestFile(string fileName, bool optimize)
{
string code = File.ReadAllText(fileName);
AssemblyDefinition assembly = Compile(code);
AssemblyDefinition assembly = Compile(code, optimize);
AstBuilder decompiler = new AstBuilder(new DecompilerContext(assembly.MainModule));
decompiler.AddAssembly(assembly);
new Helpers.RemoveCompilerAttribute().Run(decompiler.CompilationUnit);
@ -160,11 +172,11 @@ namespace ICSharpCode.Decompiler.Tests @@ -160,11 +172,11 @@ namespace ICSharpCode.Decompiler.Tests
CodeAssert.AreEqual(code, output.ToString());
}
static AssemblyDefinition Compile(string code)
static AssemblyDefinition Compile(string code, bool optimize)
{
CSharpCodeProvider provider = new CSharpCodeProvider(new Dictionary<string, string> { { "CompilerVersion", "v4.0" } });
CompilerParameters options = new CompilerParameters();
options.CompilerOptions = "/unsafe /o-";
options.CompilerOptions = "/unsafe /o" + (optimize ? "+" : "-");
options.ReferencedAssemblies.Add("System.Core.dll");
CompilerResults results = provider.CompileAssemblyFromSource(options, code);
try {

14
ICSharpCode.Decompiler/Tests/TypeAnalysisTests.cs

@ -106,4 +106,18 @@ public class TypeAnalysisTests @@ -106,4 +106,18 @@ public class TypeAnalysisTests
{
return (int)num ^ (int)(num >> 32);
}
public void TernaryOp(Random a, Random b, bool c)
{
if ((c ? a : b) == null)
{
Console.WriteLine();
}
}
public void OperatorIs(object o)
{
Console.WriteLine(o is Random);
Console.WriteLine(!(o is Random));
}
}

9
ILSpy.BamlDecompiler/ILSpy.BamlDecompiler.csproj

@ -15,20 +15,17 @@ @@ -15,20 +15,17 @@
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
<BaseAddress>6488064</BaseAddress>
</PropertyGroup>
<PropertyGroup Condition=" '$(Platform)' == 'x86' ">
<PlatformTarget>x86</PlatformTarget>
<RegisterForComInterop>False</RegisterForComInterop>
<GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies>
<BaseAddress>4194304</BaseAddress>
<FileAlignment>4096</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Platform)' == 'AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<RegisterForComInterop>False</RegisterForComInterop>
<GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies>
<BaseAddress>4194304</BaseAddress>
<FileAlignment>4096</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<OutputPath>..\ILSpy\bin\Debug\</OutputPath>
@ -40,8 +37,8 @@ @@ -40,8 +37,8 @@
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<OutputPath>..\ILSpy\bin\Release\</OutputPath>
<DebugSymbols>false</DebugSymbols>
<DebugType>None</DebugType>
<DebugSymbols>true</DebugSymbols>
<DebugType>PdbOnly</DebugType>
<Optimize>True</Optimize>
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
<DefineConstants>TRACE</DefineConstants>

3
ILSpy.BamlDecompiler/Tests/ILSpy.BamlDecompiler.Tests.csproj

@ -21,6 +21,9 @@ @@ -21,6 +21,9 @@
<BaseAddress>4194304</BaseAddress>
<FileAlignment>4096</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Platform)' == 'AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<OutputPath>..\bin\Debug\</OutputPath>
<DebugSymbols>true</DebugSymbols>

5
ILSpy.SharpDevelop.LGPL/ILSpy.SharpDevelop.LGPL.csproj

@ -9,6 +9,7 @@ @@ -9,6 +9,7 @@
<AssemblyName>ILSpy.SharpDevelop.LGPL</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<AppDesignerFolder>Properties</AppDesignerFolder>
<BaseAddress>6881280</BaseAddress>
<SignAssembly>False</SignAssembly>
<DelaySign>False</DelaySign>
<RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
@ -27,8 +28,8 @@ @@ -27,8 +28,8 @@
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<OutputPath>bin\Release\</OutputPath>
<DebugSymbols>False</DebugSymbols>
<DebugType>None</DebugType>
<DebugSymbols>true</DebugSymbols>
<DebugType>PdbOnly</DebugType>
<Optimize>True</Optimize>
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
<DefineConstants>TRACE</DefineConstants>

28
ILSpy.sln

@ -99,12 +99,12 @@ Global @@ -99,12 +99,12 @@ Global
{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Release|Any CPU.Build.0 = Release|Any CPU
{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Release|x86.ActiveCfg = Release|Any CPU
{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Release|x86.Build.0 = Release|Any CPU
{FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Debug|Any CPU.ActiveCfg = Debug|x86
{FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Debug|Any CPU.Build.0 = Debug|x86
{FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Debug|x86.ActiveCfg = Debug|x86
{FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Debug|x86.Build.0 = Debug|x86
{FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Release|Any CPU.ActiveCfg = Release|x86
{FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Release|Any CPU.Build.0 = Release|x86
{FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Release|Any CPU.Build.0 = Release|Any CPU
{FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Release|x86.ActiveCfg = Release|x86
{FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Release|x86.Build.0 = Release|x86
{F32EBCC8-0E53-4421-867E-05B3D6E10C70}.Debug|Any CPU.Build.0 = Debug|Any CPU
@ -119,9 +119,9 @@ Global @@ -119,9 +119,9 @@ Global
{63E6915C-7EA4-4D76-AB28-0D7191EEA626}.Debug|Any CPU.ActiveCfg = net_4_0_Debug|Any CPU
{63E6915C-7EA4-4D76-AB28-0D7191EEA626}.Debug|x86.Build.0 = net_4_0_Debug|Any CPU
{63E6915C-7EA4-4D76-AB28-0D7191EEA626}.Debug|x86.ActiveCfg = net_4_0_Debug|Any CPU
{63E6915C-7EA4-4D76-AB28-0D7191EEA626}.Release|Any CPU.Build.0 = net_4_0_Debug|Any CPU
{63E6915C-7EA4-4D76-AB28-0D7191EEA626}.Release|Any CPU.Build.0 = net_4_0_Release|Any CPU
{63E6915C-7EA4-4D76-AB28-0D7191EEA626}.Release|Any CPU.ActiveCfg = net_4_0_Release|Any CPU
{63E6915C-7EA4-4D76-AB28-0D7191EEA626}.Release|x86.Build.0 = net_4_0_Debug|Any CPU
{63E6915C-7EA4-4D76-AB28-0D7191EEA626}.Release|x86.Build.0 = net_4_0_Release|Any CPU
{63E6915C-7EA4-4D76-AB28-0D7191EEA626}.Release|x86.ActiveCfg = net_4_0_Release|Any CPU
{7B82B671-419F-45F4-B778-D9286F996EFA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7B82B671-419F-45F4-B778-D9286F996EFA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
@ -139,12 +139,12 @@ Global @@ -139,12 +139,12 @@ Global
{A6BAD2BA-76BA-461C-8B6D-418607591247}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A6BAD2BA-76BA-461C-8B6D-418607591247}.Release|x86.Build.0 = Release|x86
{A6BAD2BA-76BA-461C-8B6D-418607591247}.Release|x86.ActiveCfg = Release|x86
{1169E6D1-1899-43D4-A500-07CE4235B388}.Debug|Any CPU.Build.0 = Debug|x86
{1169E6D1-1899-43D4-A500-07CE4235B388}.Debug|Any CPU.ActiveCfg = Debug|x86
{1169E6D1-1899-43D4-A500-07CE4235B388}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1169E6D1-1899-43D4-A500-07CE4235B388}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1169E6D1-1899-43D4-A500-07CE4235B388}.Debug|x86.Build.0 = Debug|x86
{1169E6D1-1899-43D4-A500-07CE4235B388}.Debug|x86.ActiveCfg = Debug|x86
{1169E6D1-1899-43D4-A500-07CE4235B388}.Release|Any CPU.Build.0 = Release|x86
{1169E6D1-1899-43D4-A500-07CE4235B388}.Release|Any CPU.ActiveCfg = Release|x86
{1169E6D1-1899-43D4-A500-07CE4235B388}.Release|Any CPU.Build.0 = Release|Any CPU
{1169E6D1-1899-43D4-A500-07CE4235B388}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1169E6D1-1899-43D4-A500-07CE4235B388}.Release|x86.Build.0 = Release|x86
{1169E6D1-1899-43D4-A500-07CE4235B388}.Release|x86.ActiveCfg = Release|x86
{6D3D0F0D-348D-456A-A6ED-E9BD5EFABB6A}.Debug|Any CPU.Build.0 = Debug|Any CPU
@ -155,12 +155,12 @@ Global @@ -155,12 +155,12 @@ Global
{1D18D788-F7EE-4585-A23B-34DC8EC63CB8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1D18D788-F7EE-4585-A23B-34DC8EC63CB8}.Release|Any CPU.Build.0 = Release|Any CPU
{1D18D788-F7EE-4585-A23B-34DC8EC63CB8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{704F66F1-5C7F-4326-A7AA-C604A3896D4E}.Debug|Any CPU.Build.0 = Debug|x86
{704F66F1-5C7F-4326-A7AA-C604A3896D4E}.Debug|Any CPU.ActiveCfg = Debug|x86
{704F66F1-5C7F-4326-A7AA-C604A3896D4E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{704F66F1-5C7F-4326-A7AA-C604A3896D4E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{704F66F1-5C7F-4326-A7AA-C604A3896D4E}.Debug|x86.Build.0 = Debug|x86
{704F66F1-5C7F-4326-A7AA-C604A3896D4E}.Debug|x86.ActiveCfg = Debug|x86
{704F66F1-5C7F-4326-A7AA-C604A3896D4E}.Release|Any CPU.Build.0 = Release|x86
{704F66F1-5C7F-4326-A7AA-C604A3896D4E}.Release|Any CPU.ActiveCfg = Release|x86
{704F66F1-5C7F-4326-A7AA-C604A3896D4E}.Release|Any CPU.Build.0 = Release|Any CPU
{704F66F1-5C7F-4326-A7AA-C604A3896D4E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{704F66F1-5C7F-4326-A7AA-C604A3896D4E}.Release|x86.Build.0 = Release|x86
{704F66F1-5C7F-4326-A7AA-C604A3896D4E}.Release|x86.ActiveCfg = Release|x86
{53DCA265-3C3C-42F9-B647-F72BA678122B}.Debug|Any CPU.Build.0 = Debug|Any CPU

6
ILSpy/ILSpy.csproj

@ -24,14 +24,12 @@ @@ -24,14 +24,12 @@
<RegisterForComInterop>False</RegisterForComInterop>
<GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies>
<BaseAddress>4194304</BaseAddress>
<FileAlignment>4096</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Platform)' == 'AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<RegisterForComInterop>False</RegisterForComInterop>
<GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies>
<BaseAddress>4194304</BaseAddress>
<FileAlignment>4096</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<OutputPath>bin\Debug\</OutputPath>
@ -44,8 +42,8 @@ @@ -44,8 +42,8 @@
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<OutputPath>bin\Release\</OutputPath>
<DebugSymbols>False</DebugSymbols>
<DebugType>None</DebugType>
<DebugSymbols>true</DebugSymbols>
<DebugType>PdbOnly</DebugType>
<Optimize>True</Optimize>
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
<DefineConstants>TRACE</DefineConstants>

6
NRefactory/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj

@ -25,8 +25,7 @@ @@ -25,8 +25,7 @@
<PlatformTarget>AnyCPU</PlatformTarget>
<RegisterForComInterop>False</RegisterForComInterop>
<GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies>
<BaseAddress>4194304</BaseAddress>
<FileAlignment>4096</FileAlignment>
<BaseAddress>465371136</BaseAddress>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<OutputPath>bin\Debug\</OutputPath>
@ -38,7 +37,8 @@ @@ -38,7 +37,8 @@
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<OutputPath>bin\Release\</OutputPath>
<DebugType>None</DebugType>
<DebugSymbols>true</DebugSymbols>
<DebugType>PdbOnly</DebugType>
<Optimize>True</Optimize>
<DefineConstants>TRACE</DefineConstants>
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>

1
README.txt

@ -17,3 +17,4 @@ ILSpy Contributors: @@ -17,3 +17,4 @@ ILSpy Contributors:
Siegfried Pammer
Artur Zgodzinski
Eusebiu Marcu
Pent Ploompuu

Loading…
Cancel
Save