зеркало из https://github.com/github/codeql.git
C# IR: Add support for multiple decls and updates
Added support for multiple declarations and updates in a for stmt. Added test cases and updated the expected output.
This commit is contained in:
Родитель
ad4715fd52
Коммит
d9f3c14c9c
|
@ -179,7 +179,7 @@ private module Cached {
|
|||
exists(TranslatedElement bodyOrUpdate |
|
||||
bodyOrUpdate = s.getBody()
|
||||
or
|
||||
bodyOrUpdate = s.getUpdate()
|
||||
bodyOrUpdate = s.getUpdate(_)
|
||||
|
|
||||
inLoop = bodyOrUpdate.getAChild*()
|
||||
) and
|
||||
|
|
|
@ -10,7 +10,7 @@ private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
|
|||
|
||||
/**
|
||||
* The IR translation of a call to a function. The function can be a normal function
|
||||
* (ie. `MethodCall`) or a constructor call (ie. `ObjectCreation`). Notice that the
|
||||
* (eg. `MethodCall`) or a constructor call (eg. `ObjectCreation`). Notice that the
|
||||
* AST generated translated calls are tied to an expression (unlike compiler generated ones,
|
||||
* which can be attached to either a statement or an expression).
|
||||
*/
|
||||
|
|
|
@ -651,43 +651,70 @@ class TranslatedForStmt extends TranslatedLoop {
|
|||
override ForStmt stmt;
|
||||
|
||||
override TranslatedElement getChild(int id) {
|
||||
id = 0 and result = this.getDeclAndInit()
|
||||
initializerIndices(id) and result = this.getDeclAndInit(id)
|
||||
or
|
||||
id = 1 and result = this.getCondition()
|
||||
updateIndices(id) and result = this.getUpdate(id - initializersNo())
|
||||
or
|
||||
id = 2 and result = this.getUpdate()
|
||||
id = initializersNo() + updatesNo() and result = this.getCondition()
|
||||
or
|
||||
id = 3 and result = this.getBody()
|
||||
id = initializersNo() + updatesNo() + 1 and result = this.getBody()
|
||||
}
|
||||
|
||||
private TranslatedLocalDeclaration getDeclAndInit() {
|
||||
result = getTranslatedLocalDeclaration(stmt.getAnInitializer())
|
||||
private TranslatedLocalDeclaration getDeclAndInit(int index) {
|
||||
result = getTranslatedLocalDeclaration(stmt.getInitializer(index))
|
||||
}
|
||||
|
||||
private predicate hasInitialization() { exists(stmt.getAnInitializer()) }
|
||||
|
||||
TranslatedExpr getUpdate() { result = getTranslatedExpr(stmt.getAnUpdate()) }
|
||||
TranslatedExpr getUpdate(int index) { result = getTranslatedExpr(stmt.getUpdate(index)) }
|
||||
|
||||
private predicate hasUpdate() { exists(stmt.getAnUpdate()) }
|
||||
|
||||
private int initializersNo() { result = count(stmt.getAnInitializer()) }
|
||||
|
||||
private int updatesNo() { result = count(stmt.getAnUpdate()) }
|
||||
|
||||
private predicate initializerIndices(int index) { index in [0 .. initializersNo() - 1] }
|
||||
|
||||
private predicate updateIndices(int index) {
|
||||
index in [initializersNo() .. initializersNo() + updatesNo() - 1]
|
||||
}
|
||||
|
||||
override Instruction getFirstInstruction() {
|
||||
if this.hasInitialization()
|
||||
then result = this.getDeclAndInit().getFirstInstruction()
|
||||
then result = this.getDeclAndInit(0).getFirstInstruction()
|
||||
else result = this.getFirstConditionInstruction()
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
child = this.getDeclAndInit() and
|
||||
exists(int index |
|
||||
this.hasInitialization() and
|
||||
child = this.getDeclAndInit(index) and
|
||||
index < initializersNo() - 1 and
|
||||
result = this.getDeclAndInit(index + 1).getFirstInstruction()
|
||||
)
|
||||
or
|
||||
this.hasInitialization() and
|
||||
child = this.getDeclAndInit(initializersNo() - 1) and
|
||||
result = this.getFirstConditionInstruction()
|
||||
or
|
||||
(
|
||||
child = this.getBody() and
|
||||
if this.hasUpdate()
|
||||
then result = this.getUpdate().getFirstInstruction()
|
||||
then result = this.getUpdate(0).getFirstInstruction()
|
||||
else result = this.getFirstConditionInstruction()
|
||||
)
|
||||
or
|
||||
child = this.getUpdate() and result = this.getFirstConditionInstruction()
|
||||
exists(int index |
|
||||
this.hasUpdate() and
|
||||
child = this.getUpdate(index) and
|
||||
index < updatesNo() - 1 and
|
||||
result = this.getUpdate(index + 1).getFirstInstruction()
|
||||
)
|
||||
or
|
||||
this.hasUpdate() and
|
||||
child = this.getUpdate(updatesNo() - 1) and
|
||||
result = this.getFirstConditionInstruction()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
* (both AST generated and compiler generated).
|
||||
*/
|
||||
|
||||
|
||||
import csharp
|
||||
private import semmle.code.csharp.ir.implementation.Opcode
|
||||
private import semmle.code.csharp.ir.implementation.internal.OperandTag
|
||||
|
@ -18,129 +17,112 @@ abstract class TranslatedCallBase extends TranslatedElement {
|
|||
override final TranslatedElement getChild(int id) {
|
||||
// We choose the child's id in the order of evaluation.
|
||||
// Note: some calls do need qualifiers, though instructions for them have already
|
||||
// been generated; eg. a constructor does not need to generate a qualifier,
|
||||
// been generated; eg. a constructor does not need to generate a qualifier,
|
||||
// though the `this` argument exists and is the result of the instruction
|
||||
// that allocated the new object. For those calls, `getQualifier()` should
|
||||
// be void.
|
||||
id = -1 and result = getQualifier() or
|
||||
id = -1 and result = getQualifier()
|
||||
or
|
||||
result = getArgument(id)
|
||||
}
|
||||
|
||||
override final Instruction getFirstInstruction() {
|
||||
if exists(getQualifier()) then
|
||||
result = getQualifier().getFirstInstruction()
|
||||
else
|
||||
result = getInstruction(CallTargetTag())
|
||||
final override Instruction getFirstInstruction() {
|
||||
if exists(getQualifier())
|
||||
then result = getQualifier().getFirstInstruction()
|
||||
else result = getInstruction(CallTargetTag())
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isLValue) {
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue
|
||||
) {
|
||||
tag = CallTag() and
|
||||
opcode instanceof Opcode::Call and
|
||||
resultType = getCallResultType() and
|
||||
isLValue = false
|
||||
or
|
||||
hasSideEffect() and
|
||||
tag = CallSideEffectTag() and
|
||||
(
|
||||
tag = CallTag() and
|
||||
opcode instanceof Opcode::Call and
|
||||
resultType = getCallResultType() and
|
||||
isLValue = false
|
||||
) or
|
||||
(
|
||||
hasSideEffect() and
|
||||
tag = CallSideEffectTag() and
|
||||
(
|
||||
if hasWriteSideEffect() then (
|
||||
opcode instanceof Opcode::CallSideEffect and
|
||||
resultType instanceof Language::UnknownType
|
||||
)
|
||||
else (
|
||||
opcode instanceof Opcode::CallReadSideEffect and
|
||||
resultType instanceof Language::UnknownType
|
||||
)
|
||||
) and
|
||||
isLValue = false
|
||||
) or
|
||||
(
|
||||
tag = CallTargetTag() and
|
||||
opcode instanceof Opcode::FunctionAddress and
|
||||
// Since the DB does not have a function type,
|
||||
// we just use the UnknownType
|
||||
resultType instanceof Language::UnknownType and
|
||||
isLValue = true
|
||||
)
|
||||
if hasWriteSideEffect()
|
||||
then (
|
||||
opcode instanceof Opcode::CallSideEffect and
|
||||
resultType instanceof Language::UnknownType
|
||||
) else (
|
||||
opcode instanceof Opcode::CallReadSideEffect and
|
||||
resultType instanceof Language::UnknownType
|
||||
)
|
||||
) and
|
||||
isLValue = false
|
||||
or
|
||||
tag = CallTargetTag() and
|
||||
opcode instanceof Opcode::FunctionAddress and
|
||||
// Since the DB does not have a function type,
|
||||
// we just use the UnknownType
|
||||
resultType instanceof Language::UnknownType and
|
||||
isLValue = true
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
(
|
||||
child = getQualifier() and
|
||||
result = getInstruction(CallTargetTag())
|
||||
) or
|
||||
child = getQualifier() and
|
||||
result = getInstruction(CallTargetTag())
|
||||
or
|
||||
exists(int argIndex |
|
||||
child = getArgument(argIndex) and
|
||||
if exists(getArgument(argIndex + 1)) then
|
||||
result = getArgument(argIndex + 1).getFirstInstruction()
|
||||
else
|
||||
result = getInstruction(CallTag())
|
||||
if exists(getArgument(argIndex + 1))
|
||||
then result = getArgument(argIndex + 1).getFirstInstruction()
|
||||
else result = getInstruction(CallTag())
|
||||
)
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag,
|
||||
EdgeKind kind) {
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
kind instanceof GotoEdge and
|
||||
(
|
||||
(
|
||||
tag = CallTag() and
|
||||
if hasSideEffect() then
|
||||
result = getInstruction(CallSideEffectTag())
|
||||
else
|
||||
result = getParent().getChildSuccessor(this)
|
||||
) or
|
||||
(
|
||||
hasSideEffect() and
|
||||
tag = CallSideEffectTag() and
|
||||
result = getParent().getChildSuccessor(this)
|
||||
) or
|
||||
(
|
||||
tag = CallTargetTag() and
|
||||
kind instanceof GotoEdge and
|
||||
result = getFirstArgumentOrCallInstruction()
|
||||
if hasSideEffect()
|
||||
then result = getInstruction(CallSideEffectTag())
|
||||
else result = getParent().getChildSuccessor(this)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override Instruction getInstructionOperand(InstructionTag tag,
|
||||
OperandTag operandTag) {
|
||||
(
|
||||
tag = CallTag() and
|
||||
(
|
||||
(
|
||||
operandTag instanceof CallTargetOperandTag and
|
||||
result = getInstruction(CallTargetTag())
|
||||
) or
|
||||
(
|
||||
operandTag instanceof ThisArgumentOperandTag and
|
||||
result = getQualifierResult()
|
||||
) or
|
||||
exists(PositionalArgumentOperandTag argTag |
|
||||
argTag = operandTag and
|
||||
result = getArgument(argTag.getArgIndex()).getResult()
|
||||
)
|
||||
)
|
||||
) or
|
||||
(
|
||||
tag = CallSideEffectTag() and
|
||||
or
|
||||
hasSideEffect() and
|
||||
operandTag instanceof SideEffectOperandTag and
|
||||
result = getUnmodeledDefinitionInstruction()
|
||||
tag = CallSideEffectTag() and
|
||||
result = getParent().getChildSuccessor(this)
|
||||
or
|
||||
tag = CallTargetTag() and
|
||||
kind instanceof GotoEdge and
|
||||
result = getFirstArgumentOrCallInstruction()
|
||||
)
|
||||
}
|
||||
|
||||
override final Type getInstructionOperandType(InstructionTag tag,
|
||||
TypedOperandTag operandTag) {
|
||||
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
tag = CallTag() and
|
||||
(
|
||||
operandTag instanceof CallTargetOperandTag and
|
||||
result = getInstruction(CallTargetTag())
|
||||
or
|
||||
operandTag instanceof ThisArgumentOperandTag and
|
||||
result = getQualifierResult()
|
||||
or
|
||||
exists(PositionalArgumentOperandTag argTag |
|
||||
argTag = operandTag and
|
||||
result = getArgument(argTag.getArgIndex()).getResult()
|
||||
)
|
||||
)
|
||||
or
|
||||
tag = CallSideEffectTag() and
|
||||
hasSideEffect() and
|
||||
operandTag instanceof SideEffectOperandTag and
|
||||
result = getUnmodeledDefinitionInstruction()
|
||||
}
|
||||
|
||||
final override Type getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) {
|
||||
tag = CallSideEffectTag() and
|
||||
hasSideEffect() and
|
||||
operandTag instanceof SideEffectOperandTag and
|
||||
result instanceof Language::UnknownType
|
||||
}
|
||||
|
||||
Instruction getResult() {
|
||||
result = getInstruction(CallTag())
|
||||
}
|
||||
Instruction getResult() { result = getInstruction(CallTag()) }
|
||||
|
||||
/**
|
||||
* Gets the result type of the call.
|
||||
|
@ -152,16 +134,14 @@ abstract class TranslatedCallBase extends TranslatedElement {
|
|||
* function (of the element this call is attached to).
|
||||
*/
|
||||
abstract Instruction getUnmodeledDefinitionInstruction();
|
||||
|
||||
|
||||
/**
|
||||
* Holds if the call has a `this` argument.
|
||||
*/
|
||||
predicate hasQualifier() {
|
||||
exists(getQualifier())
|
||||
}
|
||||
predicate hasQualifier() { exists(getQualifier()) }
|
||||
|
||||
/**
|
||||
* Gets the expr for the qualifier of the call.
|
||||
* Gets the expr for the qualifier of the call.
|
||||
*/
|
||||
abstract TranslatedExprBase getQualifier();
|
||||
|
||||
|
@ -186,10 +166,9 @@ abstract class TranslatedCallBase extends TranslatedElement {
|
|||
* argument. Otherwise, returns the call instruction.
|
||||
*/
|
||||
final Instruction getFirstArgumentOrCallInstruction() {
|
||||
if hasArguments() then
|
||||
result = getArgument(0).getFirstInstruction()
|
||||
else
|
||||
result = getInstruction(CallTag())
|
||||
if hasArguments()
|
||||
then result = getArgument(0).getFirstInstruction()
|
||||
else result = getInstruction(CallTag())
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -199,21 +178,15 @@ abstract class TranslatedCallBase extends TranslatedElement {
|
|||
exists(getArgument(0))
|
||||
}
|
||||
|
||||
predicate hasReadSideEffect() {
|
||||
any()
|
||||
}
|
||||
predicate hasReadSideEffect() { any() }
|
||||
|
||||
predicate hasWriteSideEffect() {
|
||||
any()
|
||||
}
|
||||
predicate hasWriteSideEffect() { any() }
|
||||
|
||||
private predicate hasSideEffect() {
|
||||
hasReadSideEffect() or hasWriteSideEffect()
|
||||
}
|
||||
private predicate hasSideEffect() { hasReadSideEffect() or hasWriteSideEffect() }
|
||||
|
||||
override Instruction getPrimaryInstructionForSideEffect(InstructionTag tag) {
|
||||
hasSideEffect() and
|
||||
tag = CallSideEffectTag() and
|
||||
result = getResult()
|
||||
hasSideEffect() and
|
||||
tag = CallSideEffectTag() and
|
||||
result = getResult()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@ private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedExpr
|
|||
private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedCondition
|
||||
private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
|
||||
|
||||
|
||||
/**
|
||||
* Represents the context of the condition, ie. provides
|
||||
* information about the instruction that follows a conditional branch.
|
||||
|
@ -23,30 +22,25 @@ abstract class ConditionContext extends TranslatedElement {
|
|||
}
|
||||
|
||||
/**
|
||||
* Abstract class that serves as a Base for the classes that deal with both the AST generated conditions
|
||||
* Abstract class that serves as a Base for the classes that deal with both the AST generated conditions
|
||||
* and the compiler generated ones (captures the common patterns).
|
||||
*/
|
||||
abstract class ConditionBase extends TranslatedElement {
|
||||
final ConditionContext getConditionContext() {
|
||||
result = getParent()
|
||||
}
|
||||
final ConditionContext getConditionContext() { result = getParent() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract class that serves as a Base for the classes that deal with both the AST generated _value_ conditions
|
||||
* Abstract class that serves as a Base for the classes that deal with both the AST generated _value_ conditions
|
||||
* and the compiler generated ones (captures the common patterns).
|
||||
*/
|
||||
abstract class ValueConditionBase extends ConditionBase {
|
||||
override TranslatedElement getChild(int id) {
|
||||
id = 0 and result = getValueExpr()
|
||||
}
|
||||
override TranslatedElement getChild(int id) { id = 0 and result = getValueExpr() }
|
||||
|
||||
override Instruction getFirstInstruction() {
|
||||
result = getValueExpr().getFirstInstruction()
|
||||
}
|
||||
override Instruction getFirstInstruction() { result = getValueExpr().getFirstInstruction() }
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isLValue) {
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue
|
||||
) {
|
||||
tag = ValueConditionConditionalBranchTag() and
|
||||
opcode instanceof Opcode::ConditionalBranch and
|
||||
resultType instanceof VoidType and
|
||||
|
@ -58,23 +52,18 @@ abstract class ValueConditionBase extends ConditionBase {
|
|||
result = getInstruction(ValueConditionConditionalBranchTag())
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag,
|
||||
EdgeKind kind) {
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
tag = ValueConditionConditionalBranchTag() and
|
||||
(
|
||||
(
|
||||
kind instanceof TrueEdge and
|
||||
result = getConditionContext().getChildTrueSuccessor(this)
|
||||
) or
|
||||
(
|
||||
kind instanceof FalseEdge and
|
||||
result = getConditionContext().getChildFalseSuccessor(this)
|
||||
)
|
||||
kind instanceof TrueEdge and
|
||||
result = getConditionContext().getChildTrueSuccessor(this)
|
||||
or
|
||||
kind instanceof FalseEdge and
|
||||
result = getConditionContext().getChildFalseSuccessor(this)
|
||||
)
|
||||
}
|
||||
|
||||
override Instruction getInstructionOperand(InstructionTag tag,
|
||||
OperandTag operandTag) {
|
||||
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
tag = ValueConditionConditionalBranchTag() and
|
||||
operandTag instanceof ConditionOperandTag and
|
||||
result = valueExprResult()
|
||||
|
@ -84,9 +73,9 @@ abstract class ValueConditionBase extends ConditionBase {
|
|||
* Gets the instruction that represents the result of the value expression.
|
||||
*/
|
||||
abstract Instruction valueExprResult();
|
||||
|
||||
/**
|
||||
|
||||
/**
|
||||
* Gets the `TranslatedElements that represents the value expression.
|
||||
*/
|
||||
abstract TranslatedElement getValueExpr();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Contains an abstract class that serves as a Base for the classes that deal with both the AST
|
||||
* Contains an abstract class that serves as a Base for the classes that deal with both the AST
|
||||
* generated declarations and the compiler generated ones (captures the common patterns).
|
||||
*/
|
||||
|
||||
|
@ -13,55 +13,47 @@ private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedExpr
|
|||
private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedInitialization
|
||||
private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
|
||||
|
||||
|
||||
abstract class LocalVariableDeclarationBase extends TranslatedElement {
|
||||
override TranslatedElement getChild(int id) {
|
||||
id = 0 and result = getInitialization()
|
||||
override TranslatedElement getChild(int id) { id = 0 and result = getInitialization() }
|
||||
|
||||
override Instruction getFirstInstruction() { result = getVarAddress() }
|
||||
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue
|
||||
) {
|
||||
tag = InitializerVariableAddressTag() and
|
||||
opcode instanceof Opcode::VariableAddress and
|
||||
resultType = getVarType() and
|
||||
isLValue = true
|
||||
or
|
||||
hasUninitializedInstruction() and
|
||||
tag = InitializerStoreTag() and
|
||||
opcode instanceof Opcode::Uninitialized and
|
||||
resultType = getVarType() and
|
||||
isLValue = false
|
||||
}
|
||||
|
||||
override Instruction getFirstInstruction() {
|
||||
result = getVarAddress()
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isLValue) {
|
||||
(
|
||||
tag = InitializerVariableAddressTag() and
|
||||
opcode instanceof Opcode::VariableAddress and
|
||||
resultType = getVarType() and
|
||||
isLValue = true
|
||||
) or
|
||||
(
|
||||
hasUninitializedInstruction() and
|
||||
tag = InitializerStoreTag() and
|
||||
opcode instanceof Opcode::Uninitialized and
|
||||
resultType = getVarType() and
|
||||
isLValue = false
|
||||
)
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag,
|
||||
EdgeKind kind) {
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
(
|
||||
tag = InitializerVariableAddressTag() and
|
||||
kind instanceof GotoEdge and
|
||||
if hasUninitializedInstruction() then
|
||||
result = getInstruction(InitializerStoreTag())
|
||||
if hasUninitializedInstruction()
|
||||
then result = getInstruction(InitializerStoreTag())
|
||||
else
|
||||
if isInitializedByElement() then
|
||||
if isInitializedByElement()
|
||||
then
|
||||
// initialization is done by an element
|
||||
result = getParent().getChildSuccessor(this)
|
||||
else
|
||||
result = getInitialization().getFirstInstruction()
|
||||
) or
|
||||
else result = getInitialization().getFirstInstruction()
|
||||
)
|
||||
or
|
||||
hasUninitializedInstruction() and
|
||||
kind instanceof GotoEdge and
|
||||
tag = InitializerStoreTag() and
|
||||
(
|
||||
hasUninitializedInstruction() and
|
||||
kind instanceof GotoEdge and
|
||||
tag = InitializerStoreTag() and
|
||||
(
|
||||
result = getInitialization().getFirstInstruction() or
|
||||
not exists(getInitialization()) and result = getParent().getChildSuccessor(this)
|
||||
)
|
||||
result = getInitialization().getFirstInstruction()
|
||||
or
|
||||
not exists(getInitialization()) and result = getParent().getChildSuccessor(this)
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -75,11 +67,11 @@ abstract class LocalVariableDeclarationBase extends TranslatedElement {
|
|||
operandTag instanceof AddressOperandTag and
|
||||
result = getVarAddress()
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Holds if the declaration should have an `Uninitialized` instruction.
|
||||
* Compiler generated elements should override this predicate and
|
||||
* make it empty, since we always initialize the vars declared during the
|
||||
* make it empty, since we always initialize the vars declared during the
|
||||
* desugaring process.
|
||||
*/
|
||||
predicate hasUninitializedInstruction() {
|
||||
|
@ -89,29 +81,27 @@ abstract class LocalVariableDeclarationBase extends TranslatedElement {
|
|||
) and
|
||||
not isInitializedByElement()
|
||||
}
|
||||
|
||||
Instruction getVarAddress() {
|
||||
result = getInstruction(InitializerVariableAddressTag())
|
||||
}
|
||||
|
||||
|
||||
Instruction getVarAddress() { result = getInstruction(InitializerVariableAddressTag()) }
|
||||
|
||||
/**
|
||||
* Gets the declared variable. For compiler generated elements, this
|
||||
* Gets the declared variable. For compiler generated elements, this
|
||||
* should be empty (since we treat temp vars differently).
|
||||
*/
|
||||
abstract LocalVariable getDeclVar();
|
||||
|
||||
|
||||
/**
|
||||
* Gets the type of the declared variable.
|
||||
*/
|
||||
abstract Type getVarType();
|
||||
|
||||
|
||||
/**
|
||||
* Gets the initialization, if there is one.
|
||||
* For compiler generated elements we don't treat the initialization
|
||||
* as a different step, but do it during the declaration.
|
||||
*/
|
||||
abstract TranslatedElement getInitialization();
|
||||
|
||||
|
||||
/**
|
||||
* Holds if a declaration is not explicitly initialized,
|
||||
* but will be implicitly initialized by an element.
|
||||
|
|
|
@ -11,4 +11,4 @@ abstract class TranslatedExprBase extends TranslatedElement {
|
|||
* Gets the instruction that produces the result of the expression.
|
||||
*/
|
||||
abstract Instruction getResult();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,251 @@
|
|||
import csharp
|
||||
|
||||
private int getMaxCallArgIndex() {
|
||||
result = max(int argIndex |
|
||||
exists(Call call | exists(call.getArgument(argIndex)))
|
||||
or
|
||||
// Quick fix so that generated calls (`Invoke` etc) will have the
|
||||
// correct number of parameters; it is an overestimation,
|
||||
// since we don't care about all the callables, so it
|
||||
// should be restricted more
|
||||
exists(Callable callable | callable.getNumberOfParameters() = argIndex)
|
||||
)
|
||||
}
|
||||
|
||||
private newtype TOperandTag =
|
||||
TAddressOperand() or
|
||||
TBufferSizeOperand() or
|
||||
TSideEffectOperand() or
|
||||
TLoadOperand() or
|
||||
TStoreValueOperand() or
|
||||
TUnaryOperand() or
|
||||
TLeftOperand() or
|
||||
TRightOperand() or
|
||||
TConditionOperand() or
|
||||
TUnmodeledUseOperand() or
|
||||
TCallTargetOperand() or
|
||||
TThisArgumentOperand() or
|
||||
TPositionalArgumentOperand(int argIndex) { argIndex in [0 .. getMaxCallArgIndex()] } or
|
||||
TChiTotalOperand() or
|
||||
TChiPartialOperand()
|
||||
|
||||
/**
|
||||
* Identifies the kind of operand on an instruction. Each `Instruction` has at
|
||||
* most one operand of any single `OperandTag`. The set of `OperandTag`s used by
|
||||
* an `Instruction` is determined by the instruction's opcode.
|
||||
*/
|
||||
abstract class OperandTag extends TOperandTag {
|
||||
abstract string toString();
|
||||
|
||||
abstract int getSortOrder();
|
||||
|
||||
string getLabel() { result = "" }
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand that consumes a memory result (e.g. the `LoadOperand` on a `Load` instruction).
|
||||
*/
|
||||
abstract class MemoryOperandTag extends OperandTag { }
|
||||
|
||||
/**
|
||||
* An operand that consumes a register (non-memory) result.
|
||||
*/
|
||||
abstract class RegisterOperandTag extends OperandTag { }
|
||||
|
||||
/**
|
||||
* A memory operand whose type may be different from the result type of its definition instruction.
|
||||
*/
|
||||
abstract class TypedOperandTag extends MemoryOperandTag { }
|
||||
|
||||
// Note: individual subtypes are listed in the order that the operands should
|
||||
// appear in the operand list of the instruction when printing.
|
||||
/**
|
||||
* The address operand of an instruction that loads or stores a value from
|
||||
* memory (e.g. `Load`, `Store`, `InitializeParameter`, `IndirectReadSideEffect`).
|
||||
*/
|
||||
class AddressOperandTag extends RegisterOperandTag, TAddressOperand {
|
||||
final override string toString() { result = "Address" }
|
||||
|
||||
final override int getSortOrder() { result = 0 }
|
||||
|
||||
final override string getLabel() { result = "&:" }
|
||||
}
|
||||
|
||||
AddressOperandTag addressOperand() { result = TAddressOperand() }
|
||||
|
||||
/**
|
||||
* The buffer size operand of an instruction that represents a read or write of
|
||||
* a buffer.
|
||||
*/
|
||||
class BufferSizeOperand extends RegisterOperandTag, TBufferSizeOperand {
|
||||
final override string toString() { result = "BufferSize" }
|
||||
|
||||
final override int getSortOrder() { result = 1 }
|
||||
}
|
||||
|
||||
/**
|
||||
* The operand representing the read side effect of a `SideEffectInstruction`.
|
||||
*/
|
||||
class SideEffectOperandTag extends TypedOperandTag, TSideEffectOperand {
|
||||
final override string toString() { result = "SideEffect" }
|
||||
|
||||
final override int getSortOrder() { result = 2 }
|
||||
}
|
||||
|
||||
SideEffectOperandTag sideEffectOperand() { result = TSideEffectOperand() }
|
||||
|
||||
/**
|
||||
* The source value operand of an instruction that loads a value from memory (e.g. `Load`,
|
||||
* `ReturnValue`, `ThrowValue`).
|
||||
*/
|
||||
class LoadOperandTag extends TypedOperandTag, TLoadOperand {
|
||||
final override string toString() { result = "Load" }
|
||||
|
||||
final override int getSortOrder() { result = 3 }
|
||||
}
|
||||
|
||||
LoadOperandTag loadOperand() { result = TLoadOperand() }
|
||||
|
||||
/**
|
||||
* The source value operand of a `Store` instruction.
|
||||
*/
|
||||
class StoreValueOperandTag extends RegisterOperandTag, TStoreValueOperand {
|
||||
final override string toString() { result = "StoreValue" }
|
||||
|
||||
final override int getSortOrder() { result = 4 }
|
||||
}
|
||||
|
||||
StoreValueOperandTag storeValueOperand() { result = TStoreValueOperand() }
|
||||
|
||||
/**
|
||||
* The sole operand of a unary instruction (e.g. `Convert`, `Negate`, `Copy`).
|
||||
*/
|
||||
class UnaryOperandTag extends RegisterOperandTag, TUnaryOperand {
|
||||
final override string toString() { result = "Unary" }
|
||||
|
||||
final override int getSortOrder() { result = 5 }
|
||||
}
|
||||
|
||||
UnaryOperandTag unaryOperand() { result = TUnaryOperand() }
|
||||
|
||||
/**
|
||||
* The left operand of a binary instruction (e.g. `Add`, `CompareEQ`).
|
||||
*/
|
||||
class LeftOperandTag extends RegisterOperandTag, TLeftOperand {
|
||||
final override string toString() { result = "Left" }
|
||||
|
||||
final override int getSortOrder() { result = 6 }
|
||||
}
|
||||
|
||||
LeftOperandTag leftOperand() { result = TLeftOperand() }
|
||||
|
||||
/**
|
||||
* The right operand of a binary instruction (e.g. `Add`, `CompareEQ`).
|
||||
*/
|
||||
class RightOperandTag extends RegisterOperandTag, TRightOperand {
|
||||
final override string toString() { result = "Right" }
|
||||
|
||||
final override int getSortOrder() { result = 7 }
|
||||
}
|
||||
|
||||
RightOperandTag rightOperand() { result = TRightOperand() }
|
||||
|
||||
/**
|
||||
* The condition operand of a `ConditionalBranch` or `Switch` instruction.
|
||||
*/
|
||||
class ConditionOperandTag extends RegisterOperandTag, TConditionOperand {
|
||||
final override string toString() { result = "Condition" }
|
||||
|
||||
final override int getSortOrder() { result = 8 }
|
||||
}
|
||||
|
||||
ConditionOperandTag conditionOperand() { result = TConditionOperand() }
|
||||
|
||||
/**
|
||||
* An operand of the special `UnmodeledUse` instruction, representing a value
|
||||
* whose set of uses is unknown.
|
||||
*/
|
||||
class UnmodeledUseOperandTag extends MemoryOperandTag, TUnmodeledUseOperand {
|
||||
final override string toString() { result = "UnmodeledUse" }
|
||||
|
||||
final override int getSortOrder() { result = 9 }
|
||||
}
|
||||
|
||||
UnmodeledUseOperandTag unmodeledUseOperand() { result = TUnmodeledUseOperand() }
|
||||
|
||||
/**
|
||||
* The operand representing the target function of an `Call` instruction.
|
||||
*/
|
||||
class CallTargetOperandTag extends RegisterOperandTag, TCallTargetOperand {
|
||||
final override string toString() { result = "CallTarget" }
|
||||
|
||||
final override int getSortOrder() { result = 10 }
|
||||
|
||||
final override string getLabel() { result = "func:" }
|
||||
}
|
||||
|
||||
CallTargetOperandTag callTargetOperand() { result = TCallTargetOperand() }
|
||||
|
||||
/**
|
||||
* An operand representing an argument to a function call. This includes both
|
||||
* positional arguments (represented by `PositionalArgumentOperand`) and the
|
||||
* implicit `this` argument, if any (represented by `ThisArgumentOperand`).
|
||||
*/
|
||||
abstract class ArgumentOperandTag extends RegisterOperandTag { }
|
||||
|
||||
/**
|
||||
* An operand representing the implicit 'this' argument to a member function
|
||||
* call.
|
||||
*/
|
||||
class ThisArgumentOperandTag extends ArgumentOperandTag, TThisArgumentOperand {
|
||||
ThisArgumentOperandTag() { this = TThisArgumentOperand() }
|
||||
|
||||
final override string toString() { result = "Arg(this)" }
|
||||
|
||||
final override int getSortOrder() { result = 11 }
|
||||
|
||||
final override string getLabel() { result = "this:" }
|
||||
}
|
||||
|
||||
ThisArgumentOperandTag thisArgumentOperand() { result = TThisArgumentOperand() }
|
||||
|
||||
/**
|
||||
* An operand representing an argument to a function call.
|
||||
*/
|
||||
class PositionalArgumentOperandTag extends ArgumentOperandTag, TPositionalArgumentOperand {
|
||||
int argIndex;
|
||||
|
||||
PositionalArgumentOperandTag() { this = TPositionalArgumentOperand(argIndex) }
|
||||
|
||||
final override string toString() { result = "Arg(" + argIndex + ")" }
|
||||
|
||||
final override int getSortOrder() { result = 12 + argIndex }
|
||||
|
||||
final override string getLabel() { result = argIndex.toString() + ":" }
|
||||
|
||||
final int getArgIndex() { result = argIndex }
|
||||
}
|
||||
|
||||
PositionalArgumentOperandTag positionalArgumentOperand(int argIndex) {
|
||||
result = TPositionalArgumentOperand(argIndex)
|
||||
}
|
||||
|
||||
class ChiTotalOperandTag extends MemoryOperandTag, TChiTotalOperand {
|
||||
final override string toString() { result = "ChiTotal" }
|
||||
|
||||
final override int getSortOrder() { result = 13 }
|
||||
|
||||
final override string getLabel() { result = "total:" }
|
||||
}
|
||||
|
||||
ChiTotalOperandTag chiTotalOperand() { result = TChiTotalOperand() }
|
||||
|
||||
class ChiPartialOperandTag extends MemoryOperandTag, TChiPartialOperand {
|
||||
final override string toString() { result = "ChiPartial" }
|
||||
|
||||
final override int getSortOrder() { result = 14 }
|
||||
|
||||
final override string getLabel() { result = "partial:" }
|
||||
}
|
||||
|
||||
ChiPartialOperandTag chiPartialOperand() { result = TChiPartialOperand() }
|
|
@ -1048,6 +1048,9 @@ stmts.cs:
|
|||
# 71| r0_6(glval<Int32>) = VariableAddress[i] :
|
||||
# 71| r0_7(Int32) = Constant[0] :
|
||||
# 71| mu0_8(Int32) = Store : &:r0_6, r0_7
|
||||
# 71| r0_9(glval<Int32>) = VariableAddress[j] :
|
||||
# 71| r0_10(Int32) = Constant[10] :
|
||||
# 71| mu0_11(Int32) = Store : &:r0_9, r0_10
|
||||
#-----| Goto -> Block 2
|
||||
|
||||
# 68| Block 1
|
||||
|
@ -1058,53 +1061,86 @@ stmts.cs:
|
|||
# 71| Block 2
|
||||
# 71| r2_0(glval<Int32>) = VariableAddress[i] :
|
||||
# 71| r2_1(Int32) = Load : &:r2_0, ~mu0_2
|
||||
# 71| r2_2(Int32) = Constant[10] :
|
||||
# 71| r2_3(Boolean) = CompareLE : r2_1, r2_2
|
||||
# 71| v2_4(Void) = ConditionalBranch : r2_3
|
||||
#-----| False -> Block 1
|
||||
# 71| r2_2(glval<Int32>) = VariableAddress[j] :
|
||||
# 71| r2_3(Int32) = Load : &:r2_2, ~mu0_2
|
||||
# 71| r2_4(Boolean) = CompareLT : r2_1, r2_3
|
||||
# 71| v2_5(Void) = ConditionalBranch : r2_4
|
||||
#-----| False -> Block 4
|
||||
#-----| True -> Block 3
|
||||
|
||||
# 73| Block 3
|
||||
# 73| r3_0(glval<Int32>) = VariableAddress[x] :
|
||||
# 73| r3_1(Int32) = Load : &:r3_0, ~mu0_2
|
||||
# 73| r3_2(Int32) = Constant[1] :
|
||||
# 73| r3_3(Int32) = Sub : r3_1, r3_2
|
||||
# 73| r3_4(glval<Int32>) = VariableAddress[x] :
|
||||
# 73| mu3_5(Int32) = Store : &:r3_4, r3_3
|
||||
# 71| r3_6(glval<Int32>) = VariableAddress[i] :
|
||||
# 71| r3_7(Int32) = Load : &:r3_6, ~mu0_2
|
||||
# 71| r3_8(Int32) = Constant[1] :
|
||||
# 71| r3_9(Int32) = Add : r3_7, r3_8
|
||||
# 71| mu3_10(Int32) = Store : &:r3_6, r3_9
|
||||
# 73| r3_0(glval<Int32>) = VariableAddress[x] :
|
||||
# 73| r3_1(Int32) = Load : &:r3_0, ~mu0_2
|
||||
# 73| r3_2(Int32) = Constant[1] :
|
||||
# 73| r3_3(Int32) = Sub : r3_1, r3_2
|
||||
# 73| r3_4(glval<Int32>) = VariableAddress[x] :
|
||||
# 73| mu3_5(Int32) = Store : &:r3_4, r3_3
|
||||
# 71| r3_6(glval<Int32>) = VariableAddress[i] :
|
||||
# 71| r3_7(Int32) = Load : &:r3_6, ~mu0_2
|
||||
# 71| r3_8(Int32) = Constant[1] :
|
||||
# 71| r3_9(Int32) = Add : r3_7, r3_8
|
||||
# 71| mu3_10(Int32) = Store : &:r3_6, r3_9
|
||||
# 71| r3_11(glval<Int32>) = VariableAddress[j] :
|
||||
# 71| r3_12(Int32) = Load : &:r3_11, ~mu0_2
|
||||
# 71| r3_13(Int32) = Constant[1] :
|
||||
# 71| r3_14(Int32) = Sub : r3_12, r3_13
|
||||
# 71| mu3_15(Int32) = Store : &:r3_11, r3_14
|
||||
#-----| Goto (back edge) -> Block 2
|
||||
|
||||
# 77| System.Void test_stmts.doWhile()
|
||||
# 77| Block 0
|
||||
# 77| v0_0(Void) = EnterFunction :
|
||||
# 77| mu0_1(null) = AliasedDefinition :
|
||||
# 77| mu0_2(null) = UnmodeledDefinition :
|
||||
# 79| r0_3(glval<Int32>) = VariableAddress[x] :
|
||||
# 79| r0_4(Int32) = Constant[0] :
|
||||
# 79| mu0_5(Int32) = Store : &:r0_3, r0_4
|
||||
# 76| Block 4
|
||||
# 76| r4_0(glval<Int32>) = VariableAddress[a] :
|
||||
# 76| r4_1(Int32) = Constant[0] :
|
||||
# 76| mu4_2(Int32) = Store : &:r4_0, r4_1
|
||||
# 76| r4_3(glval<Int32>) = VariableAddress[b] :
|
||||
# 76| r4_4(Int32) = Constant[10] :
|
||||
# 76| mu4_5(Int32) = Store : &:r4_3, r4_4
|
||||
#-----| Goto -> Block 5
|
||||
|
||||
# 77| Block 5
|
||||
# 77| r5_0(glval<Int32>) = VariableAddress[a] :
|
||||
# 77| r5_1(Int32) = Load : &:r5_0, ~mu0_2
|
||||
# 77| r5_2(glval<Int32>) = VariableAddress[b] :
|
||||
# 77| r5_3(Int32) = Load : &:r5_2, ~mu0_2
|
||||
# 77| r5_4(Boolean) = CompareLT : r5_1, r5_3
|
||||
# 77| v5_5(Void) = ConditionalBranch : r5_4
|
||||
#-----| False -> Block 1
|
||||
#-----| True -> Block 6
|
||||
|
||||
# 79| Block 6
|
||||
# 79| r6_0(glval<Int32>) = VariableAddress[a] :
|
||||
# 79| r6_1(Int32) = Load : &:r6_0, ~mu0_2
|
||||
# 79| r6_2(Int32) = Constant[1] :
|
||||
# 79| r6_3(Int32) = Add : r6_1, r6_2
|
||||
# 79| mu6_4(Int32) = Store : &:r6_0, r6_3
|
||||
#-----| Goto (back edge) -> Block 5
|
||||
|
||||
# 83| System.Void test_stmts.doWhile()
|
||||
# 83| Block 0
|
||||
# 83| v0_0(Void) = EnterFunction :
|
||||
# 83| mu0_1(null) = AliasedDefinition :
|
||||
# 83| mu0_2(null) = UnmodeledDefinition :
|
||||
# 85| r0_3(glval<Int32>) = VariableAddress[x] :
|
||||
# 85| r0_4(Int32) = Constant[0] :
|
||||
# 85| mu0_5(Int32) = Store : &:r0_3, r0_4
|
||||
#-----| Goto -> Block 2
|
||||
|
||||
# 77| Block 1
|
||||
# 77| v1_0(Void) = ReturnVoid :
|
||||
# 77| v1_1(Void) = UnmodeledUse : mu*
|
||||
# 77| v1_2(Void) = ExitFunction :
|
||||
# 83| Block 1
|
||||
# 83| v1_0(Void) = ReturnVoid :
|
||||
# 83| v1_1(Void) = UnmodeledUse : mu*
|
||||
# 83| v1_2(Void) = ExitFunction :
|
||||
|
||||
# 82| Block 2
|
||||
# 82| r2_0(glval<Int32>) = VariableAddress[x] :
|
||||
# 82| r2_1(Int32) = Load : &:r2_0, ~mu0_2
|
||||
# 82| r2_2(Int32) = Constant[1] :
|
||||
# 82| r2_3(Int32) = Add : r2_1, r2_2
|
||||
# 82| r2_4(glval<Int32>) = VariableAddress[x] :
|
||||
# 82| mu2_5(Int32) = Store : &:r2_4, r2_3
|
||||
# 84| r2_6(glval<Int32>) = VariableAddress[x] :
|
||||
# 84| r2_7(Int32) = Load : &:r2_6, ~mu0_2
|
||||
# 84| r2_8(Int32) = Constant[10] :
|
||||
# 84| r2_9(Boolean) = CompareLT : r2_7, r2_8
|
||||
# 84| v2_10(Void) = ConditionalBranch : r2_9
|
||||
# 88| Block 2
|
||||
# 88| r2_0(glval<Int32>) = VariableAddress[x] :
|
||||
# 88| r2_1(Int32) = Load : &:r2_0, ~mu0_2
|
||||
# 88| r2_2(Int32) = Constant[1] :
|
||||
# 88| r2_3(Int32) = Add : r2_1, r2_2
|
||||
# 88| r2_4(glval<Int32>) = VariableAddress[x] :
|
||||
# 88| mu2_5(Int32) = Store : &:r2_4, r2_3
|
||||
# 90| r2_6(glval<Int32>) = VariableAddress[x] :
|
||||
# 90| r2_7(Int32) = Load : &:r2_6, ~mu0_2
|
||||
# 90| r2_8(Int32) = Constant[10] :
|
||||
# 90| r2_9(Boolean) = CompareLT : r2_7, r2_8
|
||||
# 90| v2_10(Void) = ConditionalBranch : r2_9
|
||||
#-----| False -> Block 1
|
||||
#-----| True (back edge) -> Block 2
|
||||
|
||||
|
|
|
@ -68,9 +68,15 @@ public class test_stmts
|
|||
public static void forStmt()
|
||||
{
|
||||
int x = 0;
|
||||
for (int i = 0; i <= 10; i++)
|
||||
for (int i = 0, j = 10; i < j; i++, j--)
|
||||
{
|
||||
x = x - 1;
|
||||
}
|
||||
|
||||
int a = 0, b = 10;
|
||||
for (; a < b; )
|
||||
{
|
||||
x = x - 1;
|
||||
a++;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче