Skip to content

Commit

Permalink
Better validation of instructions in tests (dotnet#45)
Browse files Browse the repository at this point in the history
Fully compare ldstr and also compare any tokens in an instruction.
  • Loading branch information
vitek-karas authored Oct 13, 2021
1 parent f6ed887 commit 41456bf
Showing 1 changed file with 75 additions and 45 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -426,15 +426,15 @@ protected static void VerifyInstructions (MethodDefinition src, MethodDefinition
nameof (ExpectBodyModifiedAttribute),
"instructions",
m => FormatMethodBody (m.Body),
attr => GetStringArrayAttributeValue (attr)!.Select (v => v?.ToLower () ?? "<null>").ToArray ());
attr => GetStringArrayAttributeValue (attr)!.ToArray ());
}

public static string[] FormatMethodBody (MethodBody body)
{
List<(Instruction?, string)> result = new List<(Instruction?, string)> (body.Instructions.Count);
for (int index = 0; index < body.Instructions.Count; index++) {
var instruction = body.Instructions[index];
result.Add ((instruction, FormatInstruction (instruction).ToLowerInvariant ()));
result.Add ((instruction, FormatInstruction (instruction)));
}

HashSet<(Instruction, Instruction)> existingTryBlocks = new HashSet<(Instruction, Instruction)> ();
Expand Down Expand Up @@ -468,51 +468,81 @@ void Append (string text) =>
result.Add ((null, text));
}

static string FormatInstruction (Instruction instr)
{
switch (instr.OpCode.FlowControl) {
case FlowControl.Branch:
case FlowControl.Cond_Branch:
if (instr.Operand is Instruction target)
return $"{instr.OpCode.ToString ()} il_{target.Offset.ToString ("X")}";

break;
}

switch (instr.OpCode.Code) {
case Code.Ldc_I4:
if (instr.Operand is int ivalue)
return $"{instr.OpCode.ToString ()} 0x{ivalue.ToString ("x")}";

throw new NotImplementedException (instr.Operand.GetType ().ToString ());
case Code.Ldc_I4_S:
if (instr.Operand is sbyte bvalue)
return $"{instr.OpCode.ToString ()} 0x{bvalue.ToString ("x")}";

throw new NotImplementedException (instr.Operand.GetType ().ToString ());
case Code.Ldc_I8:
if (instr.Operand is long lvalue)
return $"{instr.OpCode.ToString ()} 0x{lvalue.ToString ("x")}";

throw new NotImplementedException (instr.Operand.GetType ().ToString ());

case Code.Ldc_R4:
if (instr.Operand is float fvalue)
return $"{instr.OpCode.ToString ()} {fvalue.ToString ()}";

throw new NotImplementedException (instr.Operand.GetType ().ToString ());

case Code.Ldc_R8:
if (instr.Operand is double dvalue)
return $"{instr.OpCode.ToString ()} {dvalue.ToString ()}";
static string FormatInstruction(Instruction instr)
{
switch (instr.OpCode.FlowControl)
{
case FlowControl.Branch:
case FlowControl.Cond_Branch:
if (instr.Operand is Instruction target)
return $"{instr.OpCode.ToString()} il_{target.Offset.ToString("x")}";

throw new NotImplementedException (instr.Operand.GetType ().ToString ());
default:
return instr.OpCode.ToString ();
}
}
break;
}

static void VerifyLocals (MethodDefinition src, MethodDefinition linked)
switch (instr.OpCode.Code)
{
case Code.Ldc_I4:
if (instr.Operand is int ivalue)
return $"{instr.OpCode.ToString()} 0x{ivalue.ToString("x")}";

throw new NotImplementedException(instr.Operand.GetType().ToString());
case Code.Ldc_I4_S:
if (instr.Operand is sbyte bvalue)
return $"{instr.OpCode.ToString()} 0x{bvalue.ToString("x")}";

throw new NotImplementedException(instr.Operand.GetType().ToString());
case Code.Ldc_I8:
if (instr.Operand is long lvalue)
return $"{instr.OpCode.ToString()} 0x{lvalue.ToString("x")}";

throw new NotImplementedException(instr.Operand.GetType().ToString());

case Code.Ldc_R4:
if (instr.Operand is float fvalue)
return $"{instr.OpCode.ToString()} {fvalue.ToString()}";

throw new NotImplementedException(instr.Operand.GetType().ToString());

case Code.Ldc_R8:
if (instr.Operand is double dvalue)
return $"{instr.OpCode.ToString()} {dvalue.ToString()}";

throw new NotImplementedException(instr.Operand.GetType().ToString());

case Code.Ldstr:
if (instr.Operand is string svalue)
return $"{instr.OpCode.ToString()} '{svalue}'";

throw new NotImplementedException(instr.Operand.GetType().ToString());

default:
{
string? operandString = null;
switch (instr.OpCode.OperandType)
{
case OperandType.InlineField:
case OperandType.InlineMethod:
case OperandType.InlineType:
case OperandType.InlineTok:
operandString = instr.Operand switch
{
FieldReference fieldRef => fieldRef.FullName,
MethodReference methodRef => methodRef.FullName,
TypeReference typeRef => typeRef.FullName,
_ => null
};
break;
}

if (operandString != null)
return $"{instr.OpCode.ToString()} {operandString}";
else
return instr.OpCode.ToString();
}
}
}
static void VerifyLocals (MethodDefinition src, MethodDefinition linked)
{
VerifyBodyProperties (
src,
Expand Down

0 comments on commit 41456bf

Please sign in to comment.