The type of a binary numeric operation with non-primitive arguments is computed incorrectly. Specifically, this occurs for bitwise operations involving enum values.
I believe the incorrect logic is in the method Microsoft.Cci.IlToCodeModel.TypeInferencer.GetBinaryNumericOperationType at TypeInferencer.cs:46.
Here is a test case which displays the bug:
Actual output:
Target type: System.Windows.Forms.Keys
Source type: Microsoft.Cci.DummyTypeReference
Source operand types: System.Windows.Forms.Keys and System.Int32
Expected output:
Target type: System.Windows.Forms.Keys
Source type: System.Windows.Forms.Keys
Source operand types: System.Windows.Forms.Keys and System.Int32
Example.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using Microsoft.Cci;
using Microsoft.Cci.Immutable;
namespace Examples
{
class Example
{
public static void Main(String[] args)
{
// Hardcoded path to the .exe file of this.
string path = "Example.exe";
// Load Assembly
var host = new PeReader.DefaultHost();
IUnit unit = host.LoadUnitFrom(path);
if (unit is Microsoft.Cci.Dummy)
{
throw new Exception("Failed to load from " + path);
}
var assembly = Microsoft.Cci.ILToCodeModel.Decompiler
.GetCodeModelFromMetadataModel(host, unit as IAssembly, null);
// Drill down to where the bug is...
var testMethod = assembly.AllTypes
.First(t => t.ToString().Equals("Examples.Example"))
.Methods.First(m => m.Name.ToString().Equals("TestMethod"));
var decl = (testMethod.Body as ISourceMethodBody)
.Block.Statements
.First(s => s is ILocalDeclarationStatement)
as ILocalDeclarationStatement;
var src = decl.InitialValue as IBitwiseOr;
var target = decl.LocalVariable;
// The assignment is with var, so these two should be the same...
Console.WriteLine("Target type: " + target.Type);
// ... but actually the source type is Dummy.
Console.WriteLine("Source type: " + src.Type);
Console.WriteLine("Source operand types: " + src.LeftOperand.Type
+ " and " + src.RightOperand.Type);
}
public static System.Windows.Forms.Keys GetKey()
{
return System.Windows.Forms.Keys.F4;
}
public static void TestMethod()
{
var modifiedKey = GetKey()
| System.Windows.Forms.Keys.Alt;
var otherKey = modifiedKey;
Console.WriteLine(modifiedKey & otherKey);
}
}
}