C# IR: Initializers

Add support for collection initializers.
Instead of using `AssignExpr` for the translation of object initializers, `MemberInitializer` is now used.
This commit is contained in:
AndreiDiaconu1
2019-09-03 16:26:39 +01:00
parent 0528d8ef39
commit 241a40c145
4 changed files with 119 additions and 8 deletions

View File

@@ -4,6 +4,7 @@ private import semmle.code.csharp.ir.implementation.internal.OperandTag
private import InstructionTag
private import TranslatedElement
private import TranslatedExpr
private import TranslatedInitialization
private import semmle.code.csharp.ir.Util
private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedCallBase
private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
@@ -50,7 +51,13 @@ class TranslatedFunctionCall extends TranslatedNonConstantExpr, TranslatedCall {
result = getTranslatedExpr(expr.(QualifiableExpr).getQualifier())
}
override Instruction getQualifierResult() { result = this.getQualifier().getResult() }
override Instruction getQualifierResult() {
// since `ElementInitializer`s do not have a qualifier, the qualifier's result is retrieved
// from the enclosing initialization context
if expr.getParent() instanceof CollectionInitializer
then result = getTranslatedExpr(expr.getParent()).(InitializationContext).getTargetAddress()
else result = this.getQualifier().getResult()
}
override Type getCallResultType() { result = expr.getTarget().getReturnType() }

View File

@@ -485,11 +485,7 @@ class TranslatedObjectInitializerExpr extends TranslatedNonConstantExpr, Initial
}
override TranslatedElement getChild(int id) {
exists(AssignExpr assign |
result = getTranslatedExpr(expr.getChild(id)) and
expr.getAChild() = assign and
assign.getIndex() = id
)
result = getTranslatedExpr(expr.getMemberInitializer(id))
}
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
@@ -503,9 +499,54 @@ class TranslatedObjectInitializerExpr extends TranslatedNonConstantExpr, Initial
)
}
override Instruction getTargetAddress() { result = this.getParent().getInstruction(NewObjTag()) }
override Instruction getTargetAddress() {
// The target address is the address of the newly allocated object,
// which can be retrieved from the parent `TranslatedObjectCreation`.
result = this.getParent().getInstruction(NewObjTag())
}
override Type getTargetType() { none() }
override Type getTargetType() {
result = this.getParent().getInstruction(NewObjTag()).getResultType()
}
}
class TranslatedCollectionInitializer extends TranslatedNonConstantExpr, InitializationContext {
override CollectionInitializer expr;
override Instruction getResult() { none() }
override Instruction getFirstInstruction() { result = this.getChild(0).getFirstInstruction() }
override predicate hasInstruction(
Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue
) {
none()
}
override TranslatedElement getChild(int id) {
result = getTranslatedExpr(expr.getElementInitializer(id))
}
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
override Instruction getChildSuccessor(TranslatedElement child) {
exists(int index |
child = this.getChild(index) and
if exists(this.getChild(index + 1))
then result = this.getChild(index + 1).getFirstInstruction()
else result = this.getParent().getChildSuccessor(this)
)
}
override Instruction getTargetAddress() {
// The target address is the address of the newly allocated object,
// which can be retrieved from the parent `TranslatedObjectCreation`.
result = this.getParent().getInstruction(NewObjTag())
}
override Type getTargetType() {
result = this.getParent().getInstruction(NewObjTag()).getResultType()
}
}
/**

View File

@@ -0,0 +1,19 @@
using System.Collections.Generic;
public class Collections
{
class MyClass
{
public string a;
public string b;
}
public static void Main()
{
var dict = new Dictionary<int, MyClass>()
{
{ 0, new MyClass { a="Hello", b="World" } },
{ 1, new MyClass { a="Foo", b="Bar" } }
};
}
}

View File

@@ -161,6 +161,50 @@ casts.cs:
# 11| v0_20(Void) = UnmodeledUse : mu*
# 11| v0_21(Void) = ExitFunction :
collections.cs:
# 11| System.Void Collections.Main()
# 11| Block 0
# 11| v0_0(Void) = EnterFunction :
# 11| mu0_1(null) = AliasedDefinition :
# 11| mu0_2(null) = UnmodeledDefinition :
# 13| r0_3(glval<Dictionary<Int32,MyClass>>) = VariableAddress[dict] :
# 13| r0_4(Dictionary<Int32,MyClass>) = NewObj :
# 13| r0_5(glval<null>) = FunctionAddress[Dictionary] :
# 13| v0_6(Void) = Call : func:r0_5, this:r0_4
# 13| mu0_7(null) = ^CallSideEffect : ~mu0_2
# 15| r0_8(glval<null>) = FunctionAddress[Add] :
# 15| r0_9(Int32) = Constant[0] :
# 15| r0_10(MyClass) = NewObj :
# 15| r0_11(glval<null>) = FunctionAddress[MyClass] :
# 15| v0_12(Void) = Call : func:r0_11, this:r0_10
# 15| mu0_13(null) = ^CallSideEffect : ~mu0_2
# 15| r0_14(String) = StringConstant["Hello"] :
# 15| r0_15(glval<String>) = FieldAddress[a] : r0_10
# 15| mu0_16(String) = Store : &:r0_15, r0_14
# 15| r0_17(String) = StringConstant["World"] :
# 15| r0_18(glval<String>) = FieldAddress[b] : r0_10
# 15| mu0_19(String) = Store : &:r0_18, r0_17
# 15| v0_20(Void) = Call : func:r0_8, this:r0_4, 0:r0_9, 1:r0_10
# 15| mu0_21(null) = ^CallSideEffect : ~mu0_2
# 16| r0_22(glval<null>) = FunctionAddress[Add] :
# 16| r0_23(Int32) = Constant[1] :
# 16| r0_24(MyClass) = NewObj :
# 16| r0_25(glval<null>) = FunctionAddress[MyClass] :
# 16| v0_26(Void) = Call : func:r0_25, this:r0_24
# 16| mu0_27(null) = ^CallSideEffect : ~mu0_2
# 16| r0_28(String) = StringConstant["Foo"] :
# 16| r0_29(glval<String>) = FieldAddress[a] : r0_24
# 16| mu0_30(String) = Store : &:r0_29, r0_28
# 16| r0_31(String) = StringConstant["Bar"] :
# 16| r0_32(glval<String>) = FieldAddress[b] : r0_24
# 16| mu0_33(String) = Store : &:r0_32, r0_31
# 16| v0_34(Void) = Call : func:r0_22, this:r0_4, 0:r0_23, 1:r0_24
# 16| mu0_35(null) = ^CallSideEffect : ~mu0_2
# 13| mu0_36(Dictionary<Int32,MyClass>) = Store : &:r0_3, r0_4
# 11| v0_37(Void) = ReturnVoid :
# 11| v0_38(Void) = UnmodeledUse : mu*
# 11| v0_39(Void) = ExitFunction :
constructor_init.cs:
# 5| System.Void BaseClass..ctor()
# 5| Block 0