public void Invocations_MethodCallOnFieldAccess() { const string code = @" namespace Namespace { public class Class1 { private string Field; public void Foo() { var x = Field.ToLower(); // %0 := __id [ this.Field ] // %1 := string.ToLower() [ %0 ] // x := __id [ %1 ] } } }"; UcfgVerifier.VerifyInstructions(code, "Foo"); }
public void Invocation_ArgumentIsMethodResult() { const string code = @" namespace Ns1 { public class Class1 { public void Foo() { Add(GetData()); // %0 := Ns1.Class1.GetData() [ this ] // %1 := Ns1.Class1.Add(int) [ this %0 ] } public int GetData() => 1; public void Add(int value) { } } }"; UcfgVerifier.VerifyInstructions(code, "Foo"); }
public void Void_Method_Simple() { const string code = @" using System; public class Class1 { public void Foo(string s) { Console.WriteLine(s); // Simple (Next:Exit) | Block#0(Jump:#1) // Exit | Block#1(Ret) } }"; var ucfg = UcfgVerifier.GetUcfgForMethod(code, "Foo"); ucfg.Entries.Should().BeEquivalentTo(new[] { "0" }); TestHelper.AssertCollection(ucfg.BasicBlocks, b => ValidateJmpBlock(b, expectedId: "0", expectedJumps: new[] { "1" }), b => ValidateRetBlock(b, expectedId: "1", expectedReturnExpression: ConstValue) ); }
public void Ctor_Calling_Base() { var code = @" class Foo : Bar { // The ctor initializer instructions are executed before the ctor body public Foo() : base(""a"" + 5.ToString()) // %0 := __concat [ const const ] // %1 := Bar.Bar(string) [ this %0 ] { var x = 5; // x := __id [ const ] } } class Bar { public Bar(string s) {} } "; UcfgVerifier.VerifyInstructions(code, "Foo", isCtor: true); }
public void SpecialBlocks_Foreach() { const string code = @" public class Class1 { public void Foo(string[] items) { foreach (var item in items) // Foreach(BinaryBranch) | Basic#0 // BinaryBranch(BinaryBranch,Exit) | Basic#1(Jump:#1,#2) { } } // Exit | Basic#2(Ret) }"; var ucfg = UcfgVerifier.GetUcfgForMethod(code, "Foo"); TestHelper.AssertCollection(ucfg.BasicBlocks, b => ValidateJmpBlock(b, expectedId: "0", expectedJumps: new[] { "1" }), b => ValidateJmpBlock(b, expectedId: "1", expectedJumps: new[] { "1", "2" }), b => ValidateRetBlock(b, expectedId: "2", expectedReturnExpression: ConstValue) ); }
public void Assignments_Array_Set_FieldPropertyMethodNew() { const string code = @" using System.Collections.Generic; namespace Namespace { public class Class1 { public void Foo() { var a = new object[1]; // %0 := new object[] // a := __id [ %0 ] a[0] = Field; // %1 := __id [ this.Field ] // %2 := __arraySet [ a %1 ] a[0] = Property; // %3 := Namespace.Class1.Property.get [ this ] // %4 := __arraySet [ a %3 ] a[0] = GetData(); // %5 := Namespace.Class1.GetData() [ this ] // %6 := __arraySet [ a %5 ] a[0] = new Class1(); // %7 := new Namespace.Class1 // %8 := Namespace.Class1.Class1() [ %7 ] // %9 := __arraySet [ a %7 ] } private string Field = null; private string Property { get; } = null; private object GetData() { return null; } } }"; UcfgVerifier.VerifyInstructions(code, "Foo"); }
public void ArrayCreation_New_AssignToProperty() { const string code = @" namespace Namespace { public class Class1 { public void Foo(string data) { // Initialization in assignent IntProperty = new int[] { 0 }; // %0 := new int[] // %1 := __arraySet [ %0 const ] // %2 := Namespace.Class1.IntProperty.set [ this %0 ] StringProperty = new string[] { data }; // %3 := new string[] // %4 := __arraySet [ %3 data ] // %5 := Namespace.Class1.StringProperty.set [ this %3 ] Class1Property = new Class1[3]; // %6 := new Namespace.Class1[] // %7 := Namespace.Class1.Class1Property.set [ this %6 ] Class1Property = new Class1[2] { null, this }; // %8 := new Namespace.Class1[] // %9 := __arraySet [ %8 const ] // %10 := __arraySet [ %8 this ] // %11 := Namespace.Class1.Class1Property.set [ this %8 ] } private int[] IntProperty { get; set;} public string[] StringProperty { get; set; } public Class1[] Class1Property { get; set; } } }"; UcfgVerifier.VerifyInstructions(code, "Foo"); }
public void Assignments_Simple() { const string code = @" namespace Namespace { public class Class1 { public static string staticField; private string field; public void Foo(string s) { string a, b; a = s; // a := __id [ s ] a = ""boo""; // a := __id [ const ] int i; i = 5; // i := __id [ const ] field = s; // this.field := __id [ s ] this.field = s; // this.field := __id [ s ] staticField = s; // Namespace.Class1.staticField := __id [ s ] Class1.staticField = s; // Namespace.Class1.staticField := __id [ s ] } } }"; UcfgVerifier.VerifyInstructions(code, "Foo"); }
public void SpecialBlocks_Using_Statement() { const string code = @" public class Class1 { public void Foo(Func<IDisposable> factory) { using (var x = factory()) // Jump(Next:UsingEnd) | Basic#0(Jump:#1) { // UsingEnd(Next:Exit) | Basic#1(Jump:#2) } // Exit | Basic#2(Ret:Const) } }"; var ucfg = UcfgVerifier.GetUcfgForMethod(code, "Foo"); TestHelper.AssertCollection(ucfg.BasicBlocks, b => ValidateJmpBlock(b, expectedId: "0", expectedJumps: new[] { "1" }), b => ValidateJmpBlock(b, expectedId: "1", expectedJumps: new[] { "2" }), b => ValidateRetBlock(b, expectedId: "2", expectedReturnExpression: ConstValue) ); }
public void SpecialBlocks_For() { const string code = @" public class Class1 { public void Foo(string[] items) { for (int i = 0; i < items.Length; i++) // For(BinaryBranch) | Basic#0(Jump:#1) // BinaryBranch(Simple,Exit) | Basic#1(Jump:#2,#3) { // Simple(BinaryBranch) | Basic#2(Jump:#1) } } // Exit | Basic#3(Ret) }"; var ucfg = UcfgVerifier.GetUcfgForMethod(code, "Foo"); TestHelper.AssertCollection(ucfg.BasicBlocks, b => ValidateJmpBlock(b, expectedId: "0", expectedJumps: new[] { "1", }), b => ValidateJmpBlock(b, expectedId: "1", expectedJumps: new[] { "2", "3" }), b => ValidateJmpBlock(b, expectedId: "2", expectedJumps: new[] { "1" }), b => ValidateRetBlock(b, expectedId: "3", expectedReturnExpression: ConstValue) ); }
public void Invocations_Explicit_Generic_Interfaces() { const string code = @" namespace Namespace { public class Class1 { public void Foobar(string s, IBar b1, Bar b2, IBar<string> b3) { b1.Foo(s); // %0 := Namespace.IBar.Foo<T>(T) [ b1 s ] b2.Foo(s); // %1 := Namespace.Bar.Foo<T>(T) [ b2 s ] b2.Fooooo(s); // %2 := Namespace.Bar.Fooooo(string) [ b2 s ] b3.Fooooo(s); // %3 := Namespace.IBar<T>.Fooooo(T) [ b3 s ] } } public class Bar : IBar, IBar<string> { void IBar.Foo<T>(T s) { } public void Foo<T>(T s) { } public void Fooooo(string s) { } void IBar<string>.Fooooo(string s) { } } public interface IBar { void Foo<T>(T s); } public interface IBar<T> { void Fooooo(T s); } }"; UcfgVerifier.VerifyInstructions(code, "Foobar"); }
public void Serialize_Some_Method() { var code = @" class C { void Foo(string a, string b) { var x = a + b; if (true) { Bar(a, 1); } else { Bar(b, 2); } } void Bar(string a, int x) { } } "; var dot = UcfgSerializer.Serialize(UcfgVerifier.GetUcfgForMethod(code, "Foo")); dot.Should().BeIgnoringLineEndings(@"digraph ""C.Foo(string, string)"" { ENTRY [shape=record label=""{ENTRY|a|b}""] ENTRY -> 0 0 [shape=record label=""{BLOCK:#0|%0 := __concat [ a, b ]|x := __id [ %0 ]|TERMINATOR: JUMP: #1, #2}""] 0 -> 1 0 -> 2 1 [shape=record label=""{BLOCK:#1|%1 := C.Bar(string, int) [ this, a, CONST ]|TERMINATOR: JUMP: #3}""] 1 -> 3 2 [shape=record label=""{BLOCK:#2|%2 := C.Bar(string, int) [ this, b, CONST ]|TERMINATOR: JUMP: #3}""] 2 -> 3 3 [shape=record label=""{BLOCK:#3|TERMINATOR: RET: CONST}""] 3 -> END END [shape=record label=""{END}""] } "); }
public void Annotation_EntryMethod_AttributeOnStringParameterIsHandled() { const string code = @" namespace Namespace { using System.Web.Mvc; public class FromBodyAttribute : System.Attribute { } public class CartController : Controller { public object Remove([FromBody] string itemId) { var data = itemId; // data := __id [ itemId ] // %0 := __entrypoint [ itemId ] // %1 := __annotate [ Namespace.FromBodyAttribute.FromBodyAttribute() itemId ] // itemId := __annotation [ %1 ] return null; } } }"; var ucfg = UcfgVerifier.VerifyInstructions(code, "Remove"); var entryPoints = UcfgVerifier.GetEntryPointInstructions(ucfg); entryPoints.Count.Should().Be(1); // Entry point location should be the "Remove" token. // Line numbers are 1-based, offsets are 0-based var actualLocation = entryPoints[0].Assigncall.Location; actualLocation.StartLine.Should().Be(10); actualLocation.EndLine.Should().Be(10); actualLocation.StartLineOffset.Should().Be(22); actualLocation.EndLineOffset.Should().Be(28); }
public void Serialize_Some_Method() { var code = @" class C { void Foo(string a, string b) { var x = a + b; if (true) { Bar(a, 1); } else { Bar(b, 2); } } void Bar(string a, int x) { } } "; var dot = UcfgSerializer.Serialize(UcfgVerifier.GetUcfgForMethod(code, "Foo")); dot.Should().BeIgnoringLineEndings(@"digraph ""C.Foo(string, string)"" { ENTRY [shape=record label=""{ENTRY|a|b}""] ENTRY -> 0 0 [shape=record label=""{BLOCK:0|\{ \""name\"": \""%0\"" \} __concat a,b|\{ \""name\"": \""x\"" \} __id %0|TERMINATOR JUMP: 1, 2}""] 0 -> 1 0 -> 2 1 [shape=record label=""{BLOCK:1|\{ \""name\"": \""%1\"" \} C.Bar(string, int) _this_,a,\""\""\""\""|TERMINATOR JUMP: 3}""] 1 -> 3 2 [shape=record label=""{BLOCK:2|\{ \""name\"": \""%2\"" \} C.Bar(string, int) _this_,b,\""\""\""\""|TERMINATOR JUMP: 3}""] 2 -> 3 3 [shape=record label=""{BLOCK:3|TERMINATOR RET: \""\""\""\""}""] 3 -> END END [shape=record label=""{END}""] } "); }
public void Void_Method_Branch1() { const string code = @" using System; public class Class1 { public void Foo(string s) { if (true) // Branch (Next:Jump,Exit) | Block#0(Jump:#1,#2) return; // Jump (Next:Exit) | Block#1(Ret) // Exit | Block#2(Ret) } }"; var ucfg = UcfgVerifier.GetUcfgForMethod(code, "Foo"); ucfg.Entries.Should().BeEquivalentTo(new[] { "0" }); TestHelper.AssertCollection(ucfg.BasicBlocks, b => ValidateJmpBlock(b, expectedId: "0", expectedJumps: new[] { "1", "2" }), b => ValidateRetBlock(b, expectedId: "1", expectedReturnExpression: ConstValue), b => ValidateRetBlock(b, expectedId: "2", expectedReturnExpression: ConstValue) ); }
public void Assignments_Array_Get() { const string code = @" namespace Namespace { public class Class1 { public void Foo(string s, string[] a, string[][] jagged, string[,] multi) { s = a[0]; // %0 := __arrayGet [ a ] // s := __id [ %0 ] s = ((a[0])); // %1 := __arrayGet [ a ] // s := __id [ %1 ] Bar(a[0]); // %2 := __arrayGet [ a ] // %3 := Namespace.Class1.Bar(string) [ this %2 ] s = jagged[0][0]; // %4 := __arrayGet [ jagged ] // %5 := __arrayGet [ %4 ] // s := __id [ %5 ] s = multi[0, 0]; // %6 := __arrayGet [ multi ] // s := __id [ %6 ] } public void Bar(string s) {} } }"; UcfgVerifier.VerifyInstructions(code, "Foo"); }
public void Pointers() { const string code = @" using System; namespace Namespace { public class Class1 { IntPtr ptrField; UIntPtr uPtrField; public void Foo(IntPtr ptrParam, UIntPtr uPtrParam) { int x = 100; // x := __id [ const ] int *ptr = &x; // ptr := __id [ const ] Console.WriteLine((int)ptr); // %0 := __id [ ptr ] // %1 := System.Console.WriteLine(int) [ System.Console %0 ] Console.WriteLine(*ptr); // %2 := System.Console.WriteLine(int) [ System.Console const ] ptrField = ptrParam; // this.ptrField := __id [ const ] uPtrField = uPtrParam; // this.uPtrField := __id [ const ] } } }"; UcfgVerifier.VerifyInstructions(code, "Foo"); }
public void Throw_Exception() { const string code = @" public class Class1 { public string Foo(string s) { if (true) // Branch(Jump,Exit) | Basic#0(Jump:#1,#2) { throw new Exception(); // Jump(Exit) | Basic#1(Jump:#3) } return s; // Jump(Exit) | Basic#2(Ret:s) } // Exit | Basic#3(Ret:Const) }"; var ucfg = UcfgVerifier.GetUcfgForMethod(code, "Foo"); ucfg.Entries.Should().BeEquivalentTo(new[] { "0" }); TestHelper.AssertCollection(ucfg.BasicBlocks, b => ValidateJmpBlock(b, expectedId: "0", expectedJumps: new[] { "1", "2" }), b => ValidateJmpBlock(b, expectedId: "1", expectedJumps: "3"), b => ValidateRetBlock(b, expectedId: "2", expectedReturnExpression: "s"), b => ValidateRetBlock(b, expectedId: "3", expectedReturnExpression: ConstValue)); }
public void Bug171_CreationError_RegressionTest_UnexpectedMergedNamespaceSymbol() { // SimplCommerce\src\Modules\SimplCommerce.Module.PaymentPaypalExpress\Controllers\PaypalExpressController.cs :: GetAccessToken // SimplCommerce\src\SimplCommerce.WebHost\Program.cs :: BuildWebHost2 // At: UcfgExpressionService.Create // This code gives a similar repro, except with "SourceNamespaceSymbol" instead of // "MergedNamespaceSymbol" ( const string code = @" namespace Ns1 { namespace Inner { public class Builder { public static Builder CreateDefaultBuilder() => null; } } } namespace Ns2 { public class Class1 { public void BuildWebHost2(string[] args) { Ns1.Inner.Builder.CreateDefaultBuilder(); // %0 := Ns1.Inner.Builder.CreateDefaultBuilder() [ Ns1.Inner.Builder ] } } }"; UcfgVerifier.VerifyInstructions(code, "BuildWebHost2"); }
public void Invocations_MethodsWithDefaultParameters() { const string code = @" namespace Namespace { public class Class1 { public void Foo() { SendEmailAsync(""body""); // %0 := Namespace.Class1.SendEmailAsync(string, bool) [ this const const ] SendEmailAsync(""body"", isHtml: true); // %1 := Namespace.Class1.SendEmailAsync(string, bool) [ this const const ] SendEmailAsync(""body"", isHtml: false); // %2 := Namespace.Class1.SendEmailAsync(string, bool) [ this const const ] } public System.Threading.Tasks.Task SendEmailAsync(string body, bool isHtml = false) { return null; } } }"; UcfgVerifier.VerifyInstructions(code, "Foo"); }
public void Assignments_Array_Set() { const string code = @" using System.Collections.Generic; namespace Namespace { public class Class1 { public void Foo(string s, string[] a, string[][] jagged, string[,] multi) { a[0] = s; // %0 := __arraySet [ a s ] ((a[0])) = s; // %1 := __arraySet [ a s ] jagged[0][0] = s; // %2 := __arrayGet [ jagged ] // %3 := __arraySet [ %2 s ] multi[0, 0] = s; // %4 := __arraySet [ multi s ] ((jagged[0]))[0] = s; // %5 := __arrayGet [ jagged ] // %6 := __arraySet [ %5 s ] a[0] = a[1]; // %7 := __arrayGet [ a ] // %8 := __arraySet [ a %7 ] } } }"; UcfgVerifier.VerifyInstructions(code, "Foo"); }
public void ArrayCreation_New_AssignToVariable_Object() { const string code = @" namespace Namespace { public class Class1 { public void Foo(object data) { // All valid array syntaxes object[] a1 = new object[3]; // %0 := new object[] // a1 := __id [ %0 ] object[] a2 = new object[2] { data, new Class1() }; // %1 := new object[] // %2 := __arraySet [ %1 data ] // %3 := new Namespace.Class1 // %4 := Namespace.Class1.Class1() [ %3 ] // %5 := __arraySet [ %1 %3 ] // a2 := __id [ %1 ] object[] a3 = new object[] { new object() }; // %6 := new object[] // %7 := new object // %8 := object.Object() [ %7 ] // %9 := __arraySet [ %6 %7 ] // a3 := __id [ %6 ] } } }"; object[] a = { 1, "", null, 2.0, new string[] { } }; UcfgVerifier.VerifyInstructions(code, "Foo"); }
public void ArrayCreation_New_AssignToVariable_String() { const string code = @" namespace Namespace { public class Class1 { public void Foo(string data) { // All valid array syntaxes except x = { data }; string[] a1 = new string[3]; // %0 := new string[] // a1 := __id [ %0 ] string[] a2 = new string[] { null }; // %1 := new string[] // %2 := __arraySet [ %1 const ] // a2 := __id [ %1 ] string[] a3 = new string[2] { ""x"", data }; // %3 := new string[] // %4 := __arraySet [ %3 const ] // %5 := __arraySet [ %3 data ] // a3 := __id [ %3 ] string[] a4 = new[] { data }; // %6 := new string[] // %7 := __arraySet [ %6 data ] // a4 := __id [ %6 ] } } }"; UcfgVerifier.VerifyInstructions(code, "Foo"); }
public void ControllerMethod_Contains_EntryPoint_And_Attributes() { const string code = @" using System.ComponentModel; using System.Web.Mvc; public class Class1 : Controller { public class DummyAttribute : System.Attribute { } private string field; [HttpPost] // should be ignored public void Foo([Description]string s, [Missing]string x, [Dummy] int i, [DummyAttribute]string s2) {} // %0 := __entrypoint [ s x const s2 ] // %1 := __annotate [ System.ComponentModel.DescriptionAttribute.DescriptionAttribute() s ] // s := __annotation [ %1 ] // i is a const so the attribute is ignored // the Missing attribute is unknown and is not included // %2 := __annotate [ Class1.DummyAttribute.DummyAttribute() s2 ] // s2 := __annotation [ %2 ] }"; var ucfg = UcfgVerifier.VerifyInstructions(code, "Foo"); var entryPoints = UcfgVerifier.GetEntryPointInstructions(ucfg); entryPoints.Count.Should().Be(1); // Entry point location should be the "Foo" token. // Line numbers are 1-based, offsets are 0-based var actualLocation = entryPoints[0].Assigncall.Location; actualLocation.StartLine.Should().Be(10); actualLocation.EndLine.Should().Be(10); actualLocation.StartLineOffset.Should().Be(16); actualLocation.EndLineOffset.Should().Be(19); }
public void ArrayCreation_New_AssignToVariable_Int() { const string code = @" namespace Namespace { public class Class1 { public void Foo(int data) { // All valid array syntaxes except x = { data }; int[] a1 = new int[3]; // %0 := new int[] // a1 := __id [ %0 ] int[] a2 = new int[] { 0 }; // %1 := new int[] // %2 := __arraySet [ %1 const ] // a2 := __id [ %1 ] int[] a3 = new int[2] { 0, 1 }; // %3 := new int[] // %4 := __arraySet [ %3 const ] // %5 := __arraySet [ %3 const ] // a3 := __id [ %3 ] int[] a4 = new[] { 42 }; // %6 := new int[] // %7 := __arraySet [ %6 const ] // a4 := __id [ %6 ] } } }"; UcfgVerifier.VerifyInstructions(code, "Foo"); }
public void AddAssignment_Property() { const string code = @" namespace Namespace { public class Class1 { public string fieldString; public string PropertyString { get; set; } public void Foo(string parameterString, string[] values) { var localString = ""foo""; // localString := __id [ const ] PropertyString += (((""foo""))); // %0 := Namespace.Class1.PropertyString.get [ this ] // %1 := __concat [ %0 const ] // %2 := Namespace.Class1.PropertyString.set [ this %1 ] PropertyString += localString; // %3 := Namespace.Class1.PropertyString.get [ this ] // %4 := __concat [ %3 localString ] // %5 := Namespace.Class1.PropertyString.set [ this %4 ] PropertyString += parameterString; // %6 := Namespace.Class1.PropertyString.get [ this ] // %7 := __concat [ %6 parameterString ] // %8 := Namespace.Class1.PropertyString.set [ this %7 ] PropertyString += fieldString; // %9 := Namespace.Class1.PropertyString.get [ this ] // %10 := __id [ this.fieldString ] // %11 := __concat [ %9 %10 ] // %12 := Namespace.Class1.PropertyString.set [ this %11 ] PropertyString += PropertyString; // %13 := Namespace.Class1.PropertyString.get [ this ] // %14 := Namespace.Class1.PropertyString.get [ this ] // %15 := __concat [ %13 %14 ] // %16 := Namespace.Class1.PropertyString.set [ this %15 ] PropertyString += PropertyString += PropertyString += ""123""; // %17 := Namespace.Class1.PropertyString.get [ this ] // %18 := Namespace.Class1.PropertyString.get [ this ] // %19 := Namespace.Class1.PropertyString.get [ this ] // %20 := __concat [ %19 const ] // %21 := Namespace.Class1.PropertyString.set [ this %20 ] // %22 := __concat [ %18 %21 ] // %23 := Namespace.Class1.PropertyString.set [ this %22 ] // %24 := __concat [ %17 %23 ] // %25 := Namespace.Class1.PropertyString.set [ this %24 ] values[0] += Passthrough(PropertyString += ""abc""); // %26 := __arrayGet [ values ] // %27 := Namespace.Class1.PropertyString.get [ this ] // %28 := __concat [ %27 const ] // %29 := Namespace.Class1.PropertyString.set [ this %28 ] // %30 := Namespace.Class1.Passthrough(string) [ this %29 ] // %31 := __concat [ %26 %30 ] // %32 := __arraySet [ values %31 ] } public string Passthrough(string s) => s; } }"; UcfgVerifier.VerifyInstructions(code, "Foo"); }
public void AddAssignment_Field() { const string code = @" namespace Namespace { public class Class1 { public string fieldString; public string PropertyString { get; set; } public void Foo(string parameterString, string[] values) { var localString = ""foo""; // localString := __id [ const ] fieldString += (((""foo""))); // %0 := __id [ this.fieldString ] // %1 := __concat [ %0 const ] // this.fieldString := __id [ %1 ] fieldString += localString; // %2 := __id [ this.fieldString ] // %3 := __concat [ %2 localString ] // this.fieldString := __id [ %3 ] fieldString += parameterString; // %4 := __id [ this.fieldString ] // %5 := __concat [ %4 parameterString ] // this.fieldString := __id [ %5 ] fieldString += fieldString; // %6 := __id [ this.fieldString ] // %7 := __id [ this.fieldString ] // %8 := __concat [ %6 %7 ] // this.fieldString := __id [ %8 ] fieldString += PropertyString; // %9 := __id [ this.fieldString ] // %10 := Namespace.Class1.PropertyString.get [ this ] // %11 := __concat [ %9 %10 ] // this.fieldString := __id [ %11 ] fieldString += fieldString += fieldString += ""123""; // %12 := __id [ this.fieldString ] // %13 := __id [ this.fieldString ] // %14 := __id [ this.fieldString ] // %15 := __concat [ %14 const ] // this.fieldString := __id [ %15 ] // %16 := __id [ this.fieldString ] // %17 := __concat [ %13 %16 ] // this.fieldString := __id [ %17 ] // %18 := __id [ this.fieldString ] // %19 := __concat [ %12 %18 ] // this.fieldString := __id [ %19 ] values[0] += Passthrough(fieldString += ""abc""); // %20 := __arrayGet [ values ] // %21 := __id [ this.fieldString ] // %22 := __concat [ %21 const ] // this.fieldString := __id [ %22 ] // %23 := Namespace.Class1.Passthrough(string) [ this this.fieldString ] // %24 := __concat [ %20 %23 ] // %25 := __arraySet [ values %24 ] } public string Passthrough(string s) => s; } }"; UcfgVerifier.VerifyInstructions(code, "Foo"); }
public void Assignments_Ctors() { const string code = @" namespace Namespace { public class Class1 { public static Class1 staticField; public Class1 field; public string Property { get; set; } public Class1() { } public Class1(string s) { } public Class1(Class1 other) { } public void Foo(string s) { Class1 c; c = new Class1(s); // %0 := new Namespace.Class1 // %1 := Namespace.Class1.Class1(string) [ %0 s ] // c := __id [ %0 ] c = new Class1(); // %2 := new Namespace.Class1 // %3 := Namespace.Class1.Class1() [ %2 ] // c := __id [ %2 ] c = new Class1(new Class1(s)); // %4 := new Namespace.Class1 // %5 := Namespace.Class1.Class1(string) [ %4 s ] // %6 := new Namespace.Class1 // %7 := Namespace.Class1.Class1(Namespace.Class1) [ %6 %4 ] // c := __id [ %6 ] c = new Class1(s) // %8 := new Namespace.Class1 // %9 := Namespace.Class1.Class1(string) [ %8 s ] { Property = s, // %10 := Namespace.Class1.Property.set [ %8 s ] }; // c := __id [ %8 ] field = new Class1(); // %11 := new Namespace.Class1 // %12 := Namespace.Class1.Class1() [ %11 ] // this.field := __id [ %11 ] this.field = new Class1(); // %13 := new Namespace.Class1 // %14 := Namespace.Class1.Class1() [ %13 ] // this.field := __id [ %13 ] staticField = new Class1(); // %15 := new Namespace.Class1 // %16 := Namespace.Class1.Class1() [ %15 ] // Namespace.Class1.staticField := __id [ %15 ] Class1.staticField = new Class1(); // %17 := new Namespace.Class1 // %18 := Namespace.Class1.Class1() [ %17 ] // Namespace.Class1.staticField := __id [ %17 ] var other = new Class1(); // %19 := new Namespace.Class1 // %20 := Namespace.Class1.Class1() [ %19 ] // other := __id [ %19 ] other.field = this; // other.field := __id [ this ] } } }"; UcfgVerifier.VerifyInstructions(code, "Foo"); }
public void Assignments_Invocations() { const string code = @" namespace Namespace { public class BaseClass { public void BaseMethod() {} } public class Class1 : BaseClass { public string field; public void Foo(string s) { string a; a = s.ToLower(); // %0 := string.ToLower() [ s ] // a := __id [ %0 ] a = (s + s).ToLower(); // %1 := __concat [ s s ] // %2 := string.ToLower() [ %1 ] // a := __id [ %2 ] Bar(s.ToLower()); // %3 := string.ToLower() [ s ] // %4 := Namespace.Class1.Bar(string) [ this %3 ] a = string.IsNullOrEmpty(s); // %5 := string.IsNullOrEmpty(string) [ string s ]; // a := __id [ %5 ] a = A(B(C(s))); // %6 := Namespace.Class1.C(string) [ this s ] // %7 := Namespace.Class1.B(int) [ this %6 ] // %8 := Namespace.Class1.A(int) [ this %7 ] // a := __id [ %8 ] int x; x = O(s); // %9 := Namespace.Class1.O(object) [ this s ] // x := __id [ %9 ] this.Bar(s); // %10 := Namespace.Class1.Bar(string) [ this s ] base.BaseMethod(); // %11 := Namespace.BaseClass.BaseMethod() [ this ] var other = new Class1(); // %12 := new Namespace.Class1 // %13 := Namespace.Class1.Class1() [ %12 ] // other := __id [ %12 ] other.Bar(s); // %14 := Namespace.Class1.Bar(string) [ other s ] Bar(field); // %15 := __id [ this.field ] // %16 := Namespace.Class1.Bar(string) [ this %15 ] Bar(other.field); // %17 := __id [ other.field ] // %18 := Namespace.Class1.Bar(string) [ this %17 ] StaticMethod(s); // %19 := Namespace.Class1.StaticMethod(string) [ Namespace.Class1 s ] Class1.StaticMethod(s); // %20 := Namespace.Class1.StaticMethod(string) [ Namespace.Class1 s ] a = field; // %21 := __id [ this.field ] // a := __id [ %21 ] } public void Bar(string s) { } public string A(int x) { return x.ToString(); } public int B(int x) { return x; } public int C(string s) { 5; } public int O(object o) { 5; } public static string StaticMethod(string s) { return s; } } }"; UcfgVerifier.VerifyInstructions(code, "Foo"); }
public void Assignments_Properties() { const string code = @" namespace Namespace { public class Class1 { public static string StaticProperty { get; set; } public string Property { get; set; } public int IntProperty { get; set; } public object ObjectProperty { get; set; } public string Foo(string s) { string a; Property = s; // %0 := Namespace.Class1.Property.set [ this s ] a = Property; // %1 := Namespace.Class1.Property.get [ this ] // a := __id [ %1 ] Property = Property; // %2 := Namespace.Class1.Property.get [ this ] // %3 := Namespace.Class1.Property.set [ this %2 ] Foo(Property); // %4 := Namespace.Class1.Property.get [ this ] // %5 := Namespace.Class1.Foo(string) [ this %4 ] Property = Foo(Property); // %6 := Namespace.Class1.Property.get [ this ] // %7 := Namespace.Class1.Foo(string) [ this %6 ] // %8 := Namespace.Class1.Property.set [ this %7 ] ObjectProperty = s; // %9 := Namespace.Class1.ObjectProperty.set [ this s ] ObjectProperty = 5; // %10 := Namespace.Class1.ObjectProperty.set [ this const ] var x = IntProperty = 5; // %11 := Namespace.Class1.IntProperty.set [ this const ] // x := __id [ %11 ] this.Property = s; // %12 := Namespace.Class1.Property.set [ this s ] var other = new Class1(); // %13 := new Namespace.Class1 // %14 := Namespace.Class1.Class1() [ %13 ] // other := __id [ %13 ] other.Property = s; // %15 := Namespace.Class1.Property.set [ other s ] other.ObjectProperty = other.Property; // %16 := Namespace.Class1.Property.get [ other ] // %17 := Namespace.Class1.ObjectProperty.set [ other %16 ] Class1.StaticProperty = s; // %18 := Namespace.Class1.StaticProperty.set [ Namespace.Class1 s ] StaticProperty = s; // %19 := Namespace.Class1.StaticProperty.set [ Namespace.Class1 s ] a = StaticProperty; // %20 := Namespace.Class1.StaticProperty.get [ Namespace.Class1 ] // a := __id [ %20 ] a = Class1.StaticProperty; // %21 := Namespace.Class1.StaticProperty.get [ Namespace.Class1 ] // a := __id [ %21 ] return s; } } }"; UcfgVerifier.VerifyInstructions(code, "Foo"); }