mirror of
https://github.com/github/codeql.git
synced 2026-04-28 02:05:14 +02:00
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:
@@ -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() }
|
||||
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
19
csharp/ql/test/library-tests/ir/ir/collections.cs
Normal file
19
csharp/ql/test/library-tests/ir/ir/collections.cs
Normal 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" } }
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user