Work on classes + refactor

Began working o inheritance, polymorphism and constructor init. Correct code is produced for them (though some more work is needed to accurately treat conversions between classes).
Removed commented code.
Added classes to properly deal with constructor init and modified and refactored TranslatedFunction to accomodate for the changes.
This commit is contained in:
AndreiDiaconu1
2019-08-06 16:50:18 +01:00
parent 9018b25177
commit 23694bdd14
9 changed files with 430 additions and 728 deletions

View File

@@ -25,6 +25,7 @@ newtype TInstructionTag =
AssignOperationLoadTag() or
AssignOperationConvertLeftTag() or
AssignOperationOpTag() or
AssignmentConvertRightTag() or
AssignOperationConvertResultTag() or
AssignmentStoreTag() or
CrementLoadTag() or
@@ -114,6 +115,7 @@ string getInstructionTagId(TInstructionTag tag) {
tag = ZeroPadStringStoreTag() and result = "ZeroPadStore" or
tag = AssignOperationLoadTag() and result = "AssignOpLoad" or
tag = AssignOperationConvertLeftTag() and result = "AssignOpConvLeft" or
tag = AssignmentConvertRightTag() and result = "AssignConvRight" or
tag = AssignOperationOpTag() and result = "AssignOpOp" or
tag = AssignOperationConvertResultTag() and result = "AssignOpConvRes" or
tag = AssignmentStoreTag() and result = "AssignStore" or

View File

@@ -278,7 +278,10 @@ class TranslatedFunctionCall extends TranslatedCallExpr, TranslatedDirectCall {
* the constructor call, address will be passed to a variable declaration.
*/
class TranslatedConstructorCall extends TranslatedFunctionCall {
TranslatedConstructorCall() { expr instanceof ObjectCreation }
TranslatedConstructorCall() {
expr instanceof ObjectCreation or
expr instanceof ConstructorInitializer
}
override Instruction getQualifierResult() {
exists(StructorCallContext context |

View File

@@ -307,19 +307,10 @@ newtype TTranslatedElement =
isFirstValueInitializedElementInRange(initList, elementIndex) and
elementCount = getEndOfValueInitializedRange(initList, elementIndex) - elementIndex
} or
// TODO: Convert to C#
// The initialization of a base class from within a constructor.
// TTranslatedConstructorBaseInit(ConstructorBaseInit init) {
// not ignoreExpr(init)
// } or
// // The destruction of a base class from within a destructor.
// TTranslatedDestructorBaseDestruction(DestructorBaseDestruction destruction) {
// not ignoreExpr(destruction)
// } or
// // The destruction of a field from within a destructor.
// TTranslatedDestructorFieldDestruction(DestructorFieldDestruction destruction) {
// not ignoreExpr(destruction)
// } or
// The initialization of a base class from within a constructor.
TTranslatedConstructorInitializer(ConstructorInitializer init) {
not ignoreExpr(init)
} or
// A statement
TTranslatedStmt(Stmt stmt) { translateStmt(stmt) } or
// A function

View File

@@ -1507,19 +1507,22 @@ abstract class TranslatedAssignment extends TranslatedNonConstantExpr {
result = getRightOperand().getFirstInstruction()
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
Type resultType, boolean isLValue) {
(
needsConversion() and
tag = AssignmentConvertRightTag() and
// For now only use `Opcode::Convert` to
// crudely represent conversions. Could
// be useful to represent the whole chain of conversions
opcode instanceof Opcode::Convert and
resultType = expr.getLValue().getType() and
isLValue = false
)
}
override final Instruction getResult() {
//if expr.isPRValueCategory() then (
// If this is C, then the result of an assignment is a prvalue for the new
// value assigned to the left operand. If this is C++, then the result is
// an lvalue, but that lvalue is being loaded as part of this expression.
// EDG doesn't mark this as a load.
result = getStoredValue()
//)
//else (
// This is C++, where the result is an lvalue for the left operand,
// and that lvalue is not being loaded as part of this expression.
//result = getLeftOperand().getResult()
//)
}
abstract Instruction getStoredValue();
@@ -1531,6 +1534,10 @@ abstract class TranslatedAssignment extends TranslatedNonConstantExpr {
final TranslatedExpr getRightOperand() {
result = getTranslatedExpr(expr.getRValue())
}
final predicate needsConversion() {
expr.getLValue().getType() != expr.getRValue().getType()
}
}
class TranslatedAssignExpr extends TranslatedAssignment {
@@ -1543,16 +1550,27 @@ class TranslatedAssignExpr extends TranslatedAssignment {
override Instruction getInstructionSuccessor(InstructionTag tag,
EdgeKind kind) {
tag = AssignmentStoreTag() and
result = getParent().getChildSuccessor(this) and
kind instanceof GotoEdge
(
tag = AssignmentStoreTag() and
result = getParent().getChildSuccessor(this) and
kind instanceof GotoEdge
) or
(
needsConversion() and
tag = AssignmentConvertRightTag() and
result = getLeftOperand().getFirstInstruction() and
kind instanceof GotoEdge
)
}
override Instruction getChildSuccessor(TranslatedElement child) {
// Operands are evaluated right-to-left.
(
child = getRightOperand() and
result = getLeftOperand().getFirstInstruction()
if (needsConversion()) then
result = getInstruction(AssignmentConvertRightTag())
else
result = getLeftOperand().getFirstInstruction()
) or
(
child = getLeftOperand() and
@@ -1562,24 +1580,37 @@ class TranslatedAssignExpr extends TranslatedAssignment {
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
Type resultType, boolean isLValue) {
tag = AssignmentStoreTag() and
opcode instanceof Opcode::Store and
resultType = getResultType() and
isLValue = false
TranslatedAssignment.super.hasInstruction(opcode, tag, resultType, isLValue) or
(
tag = AssignmentStoreTag() and
opcode instanceof Opcode::Store and
resultType = getResultType() and
isLValue = false
)
}
override Instruction getInstructionOperand(InstructionTag tag,
OperandTag operandTag) {
tag = AssignmentStoreTag() and
(
tag = AssignmentStoreTag() and
(
(
operandTag instanceof AddressOperandTag and
result = getLeftOperand().getResult()
) or
(
operandTag instanceof StoreValueOperandTag and
if (needsConversion()) then
result = getInstruction(AssignmentConvertRightTag())
else
result = getRightOperand().getResult()
)
)
) or
(
(
operandTag instanceof AddressOperandTag and
result = getLeftOperand().getResult()
) or
(
operandTag instanceof StoreValueOperandTag and
result = getRightOperand().getResult()
)
tag = AssignmentConvertRightTag() and
operandTag instanceof UnaryOperandTag and
result = getRightOperand().getResult()
)
}
@@ -2016,67 +2047,6 @@ abstract class StructorCallContext extends TranslatedElement {
abstract Instruction getReceiver();
}
// TODO: Reason about how to translate destructors in C# (finalizers + dispose)
///**
// * Represents the IR translation of the destruction of a field from within
// * the destructor of the field's declaring class.
// */
//class TranslatedDestructorFieldDestruction extends TranslatedNonConstantExpr,
// StructorCallContext {
// override DestructorFieldDestruction expr;
//
// override final TranslatedElement getChild(int id) {
// id = 0 and result = getDestructorCall()
// }
//
// override final predicate hasInstruction(Opcode opcode, InstructionTag tag,
// Type resultType, boolean ) {
// tag = OnlyInstructionTag() and
// opcode instanceof Opcode::FieldAddress and
// resultType = expr.getTarget().getUnspecifiedType() and
// = true
// }
//
// override final Instruction getInstructionSuccessor(InstructionTag tag,
// EdgeKind kind) {
// tag = OnlyInstructionTag() and
// kind instanceof GotoEdge and
// result = getDestructorCall().getFirstInstruction()
// }
//
// override final Instruction getChildSuccessor(TranslatedElement child) {
// child = getDestructorCall() and
// result = getParent().getChildSuccessor(this)
// }
//
// override final Instruction getResult() {
// none()
// }
//
// override final Instruction getFirstInstruction() {
// result = getInstruction(OnlyInstructionTag())
// }
//
// override final Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
// tag = OnlyInstructionTag() and
// operandTag instanceof UnaryOperandTag and
// result = getTranslatedFunction(expr.getEnclosingFunction()).getInitializeThisInstruction()
// }
//
// override final Field getInstructionField(InstructionTag tag) {
// tag = OnlyInstructionTag() and
// result = expr.getTarget()
// }
//
// override final Instruction getReceiver() {
// result = getInstruction(OnlyInstructionTag())
// }
//
// private TranslatedExpr getDestructorCall() {
// result = getTranslatedExpr(expr.getExpr())
// }
// }
class TranslatedConditionalExpr extends TranslatedNonConstantExpr,
ConditionContext {
override ConditionalExpr expr;
@@ -2292,374 +2262,6 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr,
}
}
///**
// * IR translation of a `throw` expression.
// */
//abstract class TranslatedThrowExpr extends TranslatedNonConstantExpr {
// override ThrowExpr expr;
//
// override predicate hasInstruction(Opcode opcode, InstructionTag tag,
// Type resultType, boolean isLValue) {
// tag = ThrowTag() and
// opcode = getThrowOpcode() and
// resultType instanceof VoidType and
// isLValue = false
// }
//
// override Instruction getInstructionSuccessor(InstructionTag tag,
// EdgeKind kind) {
// tag = ThrowTag() and
// kind instanceof ExceptionEdge and
// result = getParent().getExceptionSuccessorInstruction()
// }
//
// override Instruction getResult() {
// none()
// }
//
// abstract Opcode getThrowOpcode();
//}
//
///**
// * IR translation of a `throw` expression with an argument
// * (e.g. `throw std::bad_alloc()`).
// */
//class TranslatedThrowValueExpr extends TranslatedThrowExpr,
// InitializationContext {
// TranslatedThrowValueExpr() {
// not expr instanceof ThrowExpr
// }
//
// override TranslatedElement getChild(int id) {
// id = 0 and result = getInitialization()
// }
//
// override Instruction getFirstInstruction() {
// result = getInstruction(InitializerVariableAddressTag())
// }
//
// override predicate hasInstruction(Opcode opcode, InstructionTag tag,
// Type resultType, boolean isLValue) {
// TranslatedThrowExpr.super.hasInstruction(opcode, tag, resultType, isLValue) or
// tag = InitializerVariableAddressTag() and
// opcode instanceof Opcode::VariableAddress and
// resultType = getExceptionType() and
// isLValue = true
// }
//
// override Instruction getInstructionSuccessor(InstructionTag tag,
// EdgeKind kind) {
// result = TranslatedThrowExpr.super.getInstructionSuccessor(tag, kind) or
// (
// tag = InitializerVariableAddressTag() and
// result = getInitialization().getFirstInstruction() and
// kind instanceof GotoEdge
// )
// }
//
// override Instruction getChildSuccessor(TranslatedElement child) {
// child = getInitialization() and
// result = getInstruction(ThrowTag())
// }
//
// override IRVariable getInstructionVariable(InstructionTag tag) {
// tag = InitializerVariableAddressTag() and
// result = getIRTempVariable(expr, ThrowTempVar())
// }
//
// override final predicate hasTempVariable(TempVariableTag tag, Type type) {
// tag = ThrowTempVar() and
// type = getExceptionType()
// }
//
// override final Instruction getInstructionOperand(InstructionTag tag,
// OperandTag operandTag) {
// tag = ThrowTag() and
// (
// (
// operandTag instanceof AddressOperandTag and
// result = getInstruction(InitializerVariableAddressTag())
// ) or
// (
// operandTag instanceof LoadOperandTag and
// result = getEnclosingFunction().getUnmodeledDefinitionInstruction()
// )
// )
// }
//
// override final Type getInstructionOperandType(InstructionTag tag,
// TypedOperandTag operandTag) {
// tag = ThrowTag() and
// operandTag instanceof LoadOperandTag and
// result = getExceptionType()
// }
//
// override Instruction getTargetAddress() {
// result = getInstruction(InitializerVariableAddressTag())
// }
//
// override Type getTargetType() {
// result = getExceptionType()
// }
//
// TranslatedInitialization getInitialization() {
// result = getTranslatedInitialization(
// expr.getExpr())
// }
//
// override final Opcode getThrowOpcode() {
// result instanceof Opcode::ThrowValue
// }
//
// private Type getExceptionType() {
// result = expr.getType()
// }
//}
// TODO: Should be handeled by the normal throw in C#
///**
// * IR translation of a `throw` expression with no argument (e.g. `throw;`).
// */
//class TranslatedReThrowExpr extends TranslatedThrowExpr {
// override ReThrowExpr expr;
//
// override TranslatedElement getChild(int id) {
// none()
// }
//
// override Instruction getFirstInstruction() {
// result = getInstruction(ThrowTag())
// }
//
// override Instruction getChildSuccessor(TranslatedElement child) {
// none()
// }
//
// override final Opcode getThrowOpcode() {
// result instanceof Opcode::ReThrow
// }
//}
// TODO: Probably does not have a translation in C#
///**
// * The IR translation of a built-in operation (i.e. anything that extends
// * `BuiltInOperation`).
// */
//abstract class TranslatedBuiltInOperation extends TranslatedNonConstantExpr {
// override final Instruction getResult() {
// result = getInstruction(OnlyInstructionTag())
// }
//
// override final Instruction getFirstInstruction() {
// if exists(getChild(0)) then
// result = getChild(0).getFirstInstruction()
// else
// result = getInstruction(OnlyInstructionTag())
// }
//
// override final TranslatedElement getChild(int id) {
// result = getTranslatedExpr(expr.getChild(id))
// }
//
// override final Instruction getInstructionSuccessor(InstructionTag tag,
// EdgeKind kind) {
// tag = OnlyInstructionTag() and
// kind instanceof GotoEdge and
// result = getParent().getChildSuccessor(this)
// }
//
// override final Instruction getChildSuccessor(TranslatedElement child) {
// exists(int id |
// child = getChild(id) and
// (
// result = getChild(id + 1).getFirstInstruction() or
// not exists(getChild(id + 1)) and result = getInstruction(OnlyInstructionTag())
// )
// )
// }
//
// override final predicate hasInstruction(Opcode opcode, InstructionTag tag,
// Type resultType, boolean isLValue) {
// tag = OnlyInstructionTag() and
// opcode = getOpcode() and
// resultType = getResultType() and
// isLValue = isResultLValue()
// }
//
// override final Instruction getInstructionOperand(InstructionTag tag,
// OperandTag operandTag) {
// tag = OnlyInstructionTag() and
// exists(int index |
// operandTag = positionalArgumentOperand(index) and
// result = getChild(index).(TranslatedExpr).getResult()
// )
// }
//
// abstract Opcode getOpcode();
//}
// TODO: See how and if we would adapt those to C#
///**
// * The IR translation of a `BuiltInVarArgsStart` expression.
// */
//class TranslatedVarArgsStart extends TranslatedBuiltInOperation {
// override BuiltInVarArgsStart expr;
//
// override final Opcode getOpcode() {
// result instanceof Opcode::VarArgsStart
// }
//}
//
///**
// * The IR translation of a `BuiltInVarArgsEnd` expression.
// */
//class TranslatedVarArgsEnd extends TranslatedBuiltInOperation {
// override BuiltInVarArgsEnd expr;
//
// override final Opcode getOpcode() {
// result instanceof Opcode::VarArgsEnd
// }
//}
//
///**
// * The IR translation of a `BuiltInVarArg` expression.
// */
//class TranslatedVarArg extends TranslatedBuiltInOperation {
// override BuiltInVarArg expr;
//
// override final Opcode getOpcode() {
// result instanceof Opcode::VarArg
// }
//}
//
///**
// * The IR translation of a `BuiltInVarArgCopy` expression.
// */
//class TranslatedVarArgCopy extends TranslatedBuiltInOperation {
// override BuiltInVarArgCopy expr;
//
// override final Opcode getOpcode() {
// result instanceof Opcode::VarArgCopy
// }
//}
//
///**
// * The IR translation of a `new` or `new[]` expression.
// */
//abstract class TranslatedNewExpr extends TranslatedNonConstantExpr,
// InitializationContext {
// override ObjectCreation expr;
//
// override final TranslatedElement getChild(int id) {
// id = 0 and result = getAllocatorCall() or
// id = 1 and result = getInitialization()
// }
//
// final TranslatedInitialization getInitialization() {
// result = getTranslatedInitialization(expr.getInitializer())
// }
//
// override final predicate hasInstruction(Opcode opcode, InstructionTag tag,
// Type resultType, boolean isLValue) {
// none()
// }
//
// override final Instruction getFirstInstruction() {
// result = getAllocatorCall().getFirstInstruction()
// }
//
// override final Instruction getResult() {
// result = getInstruction(OnlyInstructionTag())
// }
//
// override final Instruction getInstructionSuccessor(InstructionTag tag,
// EdgeKind kind) {
// kind instanceof GotoEdge and
// tag = OnlyInstructionTag() and
// if exists(getInitialization()) then
// result = getInitialization().getFirstInstruction()
// else
// result = getParent().getChildSuccessor(this)
// }
//
// override final Type getTargetType() {
// result = expr.getType()
// }
//
// override final Instruction getChildSuccessor(TranslatedElement child) {
// child = getAllocatorCall() and result = getInstruction(OnlyInstructionTag()) or
// child = getInitialization() and result = getParent().getChildSuccessor(this)
// }
//
// override final Instruction getInstructionOperand(InstructionTag tag,
// OperandTag operandTag) {
// tag = OnlyInstructionTag() and
// operandTag instanceof UnaryOperandTag and
// result = getAllocatorCall().getResult()
// }
//
// override final Instruction getTargetAddress() {
// result = getInstruction(OnlyInstructionTag())
// }
//
// private TranslatedAllocatorCall getAllocatorCall() {
// result = getTranslatedAllocatorCall(expr)
// }
//}
///**
// * The IR translation of a `ConditionDeclExpr`, which represents the value of the declared variable
// * after conversion to `bool` in code such as:
// * ```
// * if (int* p = &x) {
// * }
// * ```
// */
// TODO: DOESNT EXIST IN C#
//class TranslatedConditionDeclExpr extends TranslatedNonConstantExpr {
// override ConditionDeclExpr expr;
//
// override final Instruction getFirstInstruction() {
// result = getDecl().getFirstInstruction()
// }
//
// override final TranslatedElement getChild(int id) {
// id = 0 and result = getDecl() or
// id = 1 and result = getConditionExpr()
// }
//
// override Instruction getResult() {
// result = getConditionExpr().getResult()
// }
//
// override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
// none()
// }
//
// override Instruction getChildSuccessor(TranslatedElement child) {
// (
// child = getDecl() and
// result = getConditionExpr().getFirstInstruction()
// ) or
// child = getConditionExpr() and result = getParent().getChildSuccessor(this)
// }
//
// override predicate hasInstruction(Opcode opcode, InstructionTag tag, Type resultType,
// boolean ) {
// none()
// }
//
// private TranslatedConditionDecl getDecl() {
// result = getTranslatedConditionDecl(expr)
// }
//
// private TranslatedExpr getConditionExpr() {
// result = getTranslatedExpr(expr.getVariableAccess().getFullyConverted())
// }
//}
/**
* The IR translation of a lambda expression. This initializes a temporary variable whose type is that of the lambda,
* using the initializer list that represents the captures of the lambda.

View File

@@ -46,18 +46,15 @@ class TranslatedFunction extends TranslatedElement,
}
override final TranslatedElement getChild(int id) {
id = -3 and result = getConstructorInitList() or
id = -2 and result = getBody() or
id = -1 and result = getDestructorDestructionList() or
id = -2 and result = getConstructorInitializer() or
id = -1 and result = getBody() or
id >= 0 and result = getParameter(id)
}
private final TranslatedConstructorInitList getConstructorInitList() {
result = getTranslatedConstructorInitList(callable)
}
private final TranslatedDestructorDestructionList getDestructorDestructionList() {
result = getTranslatedDestructorDestructionList(callable)
private final TranslatedConstructorInitializer getConstructorInitializer() {
exists(ConstructorInitializer ci |
ci = callable.getAChild() and
result = getTranslatedConstructorInitializer(ci))
}
private final TranslatedStmt getBody() {
@@ -97,7 +94,10 @@ class TranslatedFunction extends TranslatedElement,
if exists(getParameter(0)) then
result = getParameter(0).getFirstInstruction()
else
result = getConstructorInitList().getFirstInstruction()
if (exists(getConstructorInitializer())) then
result = getConstructorInitializer().getFirstInstruction()
else
result = getBody().getFirstInstruction()
) or
(
tag = ReturnValueAddressTag() and
@@ -124,22 +124,18 @@ class TranslatedFunction extends TranslatedElement,
if exists(callable.getParameter(paramIndex + 1)) then
result = getParameter(paramIndex + 1).getFirstInstruction()
else
result = getConstructorInitList().getFirstInstruction()
if (exists(getConstructorInitializer())) then
result = getConstructorInitializer().getFirstInstruction()
else
result = getBody().getFirstInstruction()
) or
(
child = getConstructorInitList() and
child = getConstructorInitializer() and
result = getBody().getFirstInstruction()
) or
(
child = getBody() and
result = getReturnSuccessorInstruction()
) or
(
child = getDestructorDestructionList() and
if getReturnType() instanceof VoidType then
result = getInstruction(ReturnTag())
else
result = getInstruction(ReturnValueAddressTag())
)
}
@@ -361,8 +357,7 @@ class TranslatedParameter extends TranslatedElement, TTranslatedParameter {
}
override final Callable getFunction() {
result = param.getCallable() // or
// result = param.getCatchBlock().getEnclosingFunction()
result = param.getCallable()
}
override final Instruction getFirstInstruction() {
@@ -427,149 +422,3 @@ class TranslatedParameter extends TranslatedElement, TTranslatedParameter {
)
}
}
private TranslatedConstructorInitList
getTranslatedConstructorInitList(Callable callable) {
result.getAST() = callable
}
/**
* Represents the IR translation of a constructor initializer list. To simplify
* the implementation of `TranslatedFunction`, a `TranslatedConstructorInitList`
* exists for every function, not just for constructors. Of course, only the
* instances for constructors can actually contain initializers.
*/
class TranslatedConstructorInitList extends TranslatedElement,
InitializationContext, TTranslatedConstructorInitList {
Callable callable;
TranslatedConstructorInitList() {
this = TTranslatedConstructorInitList(callable)
}
override string toString() {
result = "ctor init: " + callable.toString()
}
override Language::AST getAST() {
result = callable
}
// TODO: Is this enough?
override TranslatedElement getChild(int id) {
result = getTranslatedExpr(callable).getChild(id)
// exists(MemberInitializer init |
// init = callable.(Constructor).getInitializer().getRawArgument(id) and
// result = getTranslatedConstructorFieldInitialization(init)
// ) // or
// exists(ConstructorBaseInit baseInit |
// baseInit = callable.(Constructor).getInitializer().getRawArgument(id) and
// result = getTranslatedConstructorBaseInit(baseInit)
// )
}
override Instruction getFirstInstruction() {
if exists(getChild(0)) then
result = getChild(0).getFirstInstruction()
else
result = getParent().getChildSuccessor(this)
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
Type resultType, boolean isLValue) {
none()
}
override Callable getFunction() {
result = callable
}
override Instruction getInstructionSuccessor(InstructionTag tag,
EdgeKind kind) {
none()
}
override Instruction getChildSuccessor(TranslatedElement child) {
exists(int id |
child = getChild(id) and
if exists(getChild(id + 1)) then
result = getChild(id + 1).getFirstInstruction()
else
result = getParent().getChildSuccessor(this)
)
}
override Instruction getTargetAddress() {
result = getTranslatedFunction(callable).getInitializeThisInstruction()
}
override Type getTargetType() {
result = getTranslatedFunction(callable).getThisType()
}
}
private TranslatedDestructorDestructionList
getTranslatedDestructorDestructionList(Callable callable) {
result.getAST() = callable
}
// TODO: Should not exist in C#, keep for now (the fix for getReturnSuccessorInstruction replaces it)
/**
* Represents the IR translation of a destructor's implicit calls to destructors
* for fields and base classes. To simplify the implementation of `TranslatedFunction`,
* a `TranslatedDestructorDestructionList` exists for every function, not just for
* destructors. Of course, only the instances for destructors can actually contain
* destructions.
*/
class TranslatedDestructorDestructionList extends TranslatedElement,
TTranslatedDestructorDestructionList {
Callable callable;
TranslatedDestructorDestructionList() {
this = TTranslatedDestructorDestructionList(callable)
}
override string toString() {
result = "dtor destruction: " + callable.toString()
}
override Language::AST getAST() {
result = callable
}
// TODO: Is this enough?
override TranslatedElement getChild(int id) {
result = getTranslatedExpr(callable).getChild(id)
}
override Instruction getFirstInstruction() {
if exists(getChild(0)) then
result = getChild(0).getFirstInstruction()
else
result = getParent().getChildSuccessor(this)
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
Type resultType, boolean isLValue) {
none()
}
override Callable getFunction() {
result = callable
}
override Instruction getInstructionSuccessor(InstructionTag tag,
EdgeKind kind) {
none()
}
override Instruction getChildSuccessor(TranslatedElement child) {
exists(int id |
child = getChild(id) and
if exists(getChild(id + 1)) then
result = getChild(id + 1).getFirstInstruction()
else
result = getParent().getChildSuccessor(this)
)
}
}

View File

@@ -220,6 +220,17 @@ class TranslatedObjectInitialization extends TranslatedInitialization,
resultType = expr.getType() and
isLValue = false
)
or
(
needsConversion() and
tag = AssignmentConvertRightTag() and
// For now only use `Opcode::Convert` to
// crudely represent conversions. Could
// be useful to represent the whole chain of conversions
opcode instanceof Opcode::Convert and
resultType = getContext().getTargetType() and
isLValue = false
)
}
override final Instruction getFirstInstruction() {
@@ -238,6 +249,11 @@ class TranslatedObjectInitialization extends TranslatedInitialization,
tag = InitializerStoreTag() and
result = getParent().getChildSuccessor(this)
)
or
(
tag = AssignmentConvertRightTag() and
result = getInstruction(InitializerStoreTag())
)
)
}
@@ -247,21 +263,40 @@ class TranslatedObjectInitialization extends TranslatedInitialization,
if (exists(getInitializerExpr())) then
result = getInitializerExpr().getFirstInstruction()
else
result = getInstruction(InitializerStoreTag())
if needsConversion() then
result = getInstruction(AssignmentConvertRightTag())
else
result = getInstruction(InitializerStoreTag())
) or
(
child = getInitializerExpr() and
result = getInstruction(InitializerStoreTag())
if (needsConversion()) then
result = getInstruction(AssignmentConvertRightTag())
else
result = getInstruction(InitializerStoreTag())
)
}
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
tag = InitializerStoreTag() and
(
operandTag instanceof AddressOperandTag and
result = getParent().(InitializationContext).getTargetAddress()
or
operandTag instanceof StoreValueOperandTag and
tag = InitializerStoreTag() and
(
(
operandTag instanceof AddressOperandTag and
result = getParent().(InitializationContext).getTargetAddress()
) or
(
operandTag instanceof StoreValueOperandTag and
if (needsConversion()) then
result = getInstruction(AssignmentConvertRightTag())
else
result = getInstruction(NewObjTag())
)
)
) or
(
tag = AssignmentConvertRightTag() and
operandTag instanceof UnaryOperandTag and
result = getInstruction(NewObjTag())
)
}
@@ -278,6 +313,10 @@ class TranslatedObjectInitialization extends TranslatedInitialization,
// The newly allocated object will be the target of the constructor call
result = getInstruction(NewObjTag())
}
private predicate needsConversion() {
expr.getType() != getContext().getTargetType()
}
}
///**
@@ -652,7 +691,8 @@ class TranslatedElementValueInitialization extends TranslatedElementInitializati
}
}
abstract class TranslatedStructorCallFromStructor extends TranslatedElement, StructorCallContext {
// TODO: Possibly refactor into something simpler
abstract class TranslatedConstructorCallFromConstructor extends TranslatedElement, StructorCallContext {
Call call;
override final Language::AST getAST() {
@@ -660,8 +700,7 @@ abstract class TranslatedStructorCallFromStructor extends TranslatedElement, Str
}
final override TranslatedElement getChild(int id) {
id = 0 and
result = getStructorCall()
id = 0 and result = getStructorCall()
}
final override Callable getFunction() { result = call.getEnclosingCallable() }
@@ -674,37 +713,66 @@ abstract class TranslatedStructorCallFromStructor extends TranslatedElement, Str
final TranslatedExpr getStructorCall() { result = getTranslatedExpr(call) }
}
/**
* Represents the IR translation of a call to a base class constructor or
* destructor from within a derived class constructor or destructor.
*/
abstract class TranslatedBaseStructorCall extends TranslatedStructorCallFromStructor {
final override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) }
final override predicate hasInstruction(
TranslatedConstructorInitializer getTranslatedConstructorInitializer(ConstructorInitializer ci) {
result.getAST() = ci
}
/**
* Represents the IR translation of a call to a base class constructor
* or another constructor in same class from a class constructor.
*/
class TranslatedConstructorInitializer extends TranslatedConstructorCallFromConstructor,
TTranslatedConstructorInitializer {
TranslatedConstructorInitializer() {
this = TTranslatedConstructorInitializer(call)
}
override string toString() {
result = "constuructor init: " + call.toString()
}
override Instruction getFirstInstruction() {
if (needsConversion()) then
result = getInstruction(OnlyInstructionTag())
else
result = getStructorCall().getFirstInstruction()
}
override predicate hasInstruction(
Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue
) {
needsConversion() and
tag = OnlyInstructionTag() and
opcode instanceof Opcode::ConvertToBase and
resultType = call.getTarget().getDeclaringType() and
isLValue = true
}
final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
tag = OnlyInstructionTag() and
kind instanceof GotoEdge and
result = getStructorCall().getFirstInstruction()
}
final override Instruction getReceiver() { result = getInstruction(OnlyInstructionTag()) }
override Instruction getReceiver() {
if (needsConversion()) then
result = getInstruction(OnlyInstructionTag())
else
result = getTranslatedFunction(getFunction()).getInitializeThisInstruction()
}
final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
tag = OnlyInstructionTag() and
operandTag instanceof UnaryOperandTag and
result = getTranslatedFunction(getFunction()).getInitializeThisInstruction()
}
final override predicate getInstructionInheritance(
predicate needsConversion() {
call.getTarget().getDeclaringType() != getFunction().getDeclaringType()
}
override predicate getInstructionInheritance(
InstructionTag tag, Class baseClass, Class derivedClass
) {
tag = OnlyInstructionTag() and
@@ -712,72 +780,3 @@ abstract class TranslatedBaseStructorCall extends TranslatedStructorCallFromStru
derivedClass = getFunction().getDeclaringType()
}
}
//abstract class TranslatedConstructorCallFromConstructor extends TranslatedStructorCallFromStructor,
// TTranslatedConstructorBaseInit {
// TranslatedConstructorCallFromConstructor() {
// this = TTranslatedConstructorBaseInit(call)
// }
//}
//
//TranslatedConstructorCallFromConstructor getTranslatedConstructorBaseInit(ConstructorBaseInit init) {
// result.getAST() = init
//}
//
///**
// * Represents the IR translation of a delegating constructor call from within a constructor.
// */
//class TranslatedConstructorDelegationInit extends TranslatedConstructorCallFromConstructor {
// override ConstructorDelegationInit call;
//
// override final string toString() {
// result = "delegation construct: " + call.toString()
// }
//
// override final Instruction getFirstInstruction() {
// result = getStructorCall().getFirstInstruction()
// }
//
// override final predicate hasInstruction(Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue) {
// none()
// }
//
// override final Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
// none()
// }
//
// override final Instruction getReceiver() {
// result = getTranslatedFunction(getFunction()).getInitializeThisInstruction()
// }
//}
//
///**
// * Represents the IR translation of a call to a base class constructor from within a
// * derived class constructor
// */
//class TranslatedConstructorBaseInit extends TranslatedConstructorCallFromConstructor, TranslatedBaseStructorCall {
// TranslatedConstructorBaseInit() {
// not call instanceof ConstructorDelegationInit
// }
//
// override final string toString() {
// result = "construct base: " + call.toString()
// }
//}
//
//TranslatedDestructorBaseDestruction getTranslatedDestructorBaseDestruction(DestructorBaseDestruction destruction) {
// result.getAST() = destruction
//}
//
///**
// * Represents the IR translation of a call to a base class destructor from within a
// * derived class destructor.
// */
//class TranslatedDestructorBaseDestruction extends TranslatedBaseStructorCall, TTranslatedDestructorBaseDestruction {
// TranslatedDestructorBaseDestruction() {
// this = TTranslatedDestructorBaseDestruction(call)
// }
//
// override final string toString() {
// result = "destroy base: " + call.toString()
// }
//}

View File

@@ -0,0 +1,35 @@
public class BaseClass
{
int num;
public BaseClass()
{
}
public BaseClass(int i)
{
num = i;
}
}
public class DerivedClass : BaseClass
{
public DerivedClass() : base()
{
}
public DerivedClass(int i) : base(i)
{
}
public DerivedClass(int i, int j): this(i)
{
}
static void Main()
{
DerivedClass obj1= new DerivedClass();
DerivedClass obj2 = new DerivedClass(1);
DerivedClass obj3 = new DerivedClass(1, 2);
}
}

View File

@@ -0,0 +1,37 @@
public class A
{
public virtual int function()
{
return 0;
}
}
class B : A
{
}
class C : B
{
public override int function()
{
return 1;
}
}
class Program
{
static void Main()
{
B objB = new B();
objB.function();
// Check conversion works
A objA;
objA = objB;
objA.function();
A objC = new C();
objC.function();
}
}

View File

@@ -135,6 +135,120 @@ array.cs:
# 9| v0_85(Void) = UnmodeledUse : mu*
# 9| v0_86(Void) = ExitFunction :
constructor_init.cs:
# 5| BaseClass
# 5| Block 0
# 5| v0_0(Void) = EnterFunction :
# 5| mu0_1(null) = AliasedDefinition :
# 5| mu0_2(null) = UnmodeledDefinition :
# 5| r0_3(glval<BaseClass>) = InitializeThis :
# 6| v0_4(Void) = NoOp :
# 5| v0_5(Void) = ReturnVoid :
# 5| v0_6(Void) = UnmodeledUse : mu*
# 5| v0_7(Void) = ExitFunction :
# 9| BaseClass
# 9| Block 0
# 9| v0_0(Void) = EnterFunction :
# 9| mu0_1(null) = AliasedDefinition :
# 9| mu0_2(null) = UnmodeledDefinition :
# 9| r0_3(glval<BaseClass>) = InitializeThis :
# 9| r0_4(glval<Int32>) = VariableAddress[i] :
# 9| mu0_5(Int32) = InitializeParameter[i] : &:r0_4
# 11| r0_6(glval<Int32>) = VariableAddress[i] :
# 11| r0_7(Int32) = Load : &:r0_6, ~mu0_2
# 11| r0_8(BaseClass) = CopyValue : r0_3
# 11| r0_9(glval<Int32>) = FieldAddress[BaseClass.num] : r0_8
# 11| mu0_10(Int32) = Store : &:r0_9, r0_7
# 9| v0_11(Void) = ReturnVoid :
# 9| v0_12(Void) = UnmodeledUse : mu*
# 9| v0_13(Void) = ExitFunction :
# 17| DerivedClass
# 17| Block 0
# 17| v0_0(Void) = EnterFunction :
# 17| mu0_1(null) = AliasedDefinition :
# 17| mu0_2(null) = UnmodeledDefinition :
# 17| r0_3(glval<DerivedClass>) = InitializeThis :
# 17| r0_4(glval<BaseClass>) = ConvertToBase[DerivedClass : BaseClass] : r0_3
# 17| r0_5(glval<BaseClass>) = FunctionAddress[BaseClass.BaseClass()] :
# 17| r0_6(BaseClass) = Call : func:r0_5, this:r0_4
# 17| mu0_7(null) = ^CallSideEffect : ~mu0_2
# 18| v0_8(Void) = NoOp :
# 17| v0_9(Void) = ReturnVoid :
# 17| v0_10(Void) = UnmodeledUse : mu*
# 17| v0_11(Void) = ExitFunction :
# 21| DerivedClass
# 21| Block 0
# 21| v0_0(Void) = EnterFunction :
# 21| mu0_1(null) = AliasedDefinition :
# 21| mu0_2(null) = UnmodeledDefinition :
# 21| r0_3(glval<DerivedClass>) = InitializeThis :
# 21| r0_4(glval<Int32>) = VariableAddress[i] :
# 21| mu0_5(Int32) = InitializeParameter[i] : &:r0_4
# 21| r0_6(glval<BaseClass>) = ConvertToBase[DerivedClass : BaseClass] : r0_3
# 21| r0_7(glval<BaseClass>) = FunctionAddress[BaseClass.BaseClass(int)] :
# 21| r0_8(glval<Int32>) = VariableAddress[i] :
# 21| r0_9(Int32) = Load : &:r0_8, ~mu0_2
# 21| r0_10(BaseClass) = Call : func:r0_7, this:r0_6, 0:r0_9
# 21| mu0_11(null) = ^CallSideEffect : ~mu0_2
# 22| v0_12(Void) = NoOp :
# 21| v0_13(Void) = ReturnVoid :
# 21| v0_14(Void) = UnmodeledUse : mu*
# 21| v0_15(Void) = ExitFunction :
# 25| DerivedClass
# 25| Block 0
# 25| v0_0(Void) = EnterFunction :
# 25| mu0_1(null) = AliasedDefinition :
# 25| mu0_2(null) = UnmodeledDefinition :
# 25| r0_3(glval<DerivedClass>) = InitializeThis :
# 25| r0_4(glval<Int32>) = VariableAddress[i] :
# 25| mu0_5(Int32) = InitializeParameter[i] : &:r0_4
# 25| r0_6(glval<Int32>) = VariableAddress[j] :
# 25| mu0_7(Int32) = InitializeParameter[j] : &:r0_6
# 25| r0_8(glval<DerivedClass>) = FunctionAddress[DerivedClass.DerivedClass(int)] :
# 25| r0_9(glval<Int32>) = VariableAddress[i] :
# 25| r0_10(Int32) = Load : &:r0_9, ~mu0_2
# 25| r0_11(DerivedClass) = Call : func:r0_8, this:r0_3, 0:r0_10
# 25| mu0_12(null) = ^CallSideEffect : ~mu0_2
# 26| v0_13(Void) = NoOp :
# 25| v0_14(Void) = ReturnVoid :
# 25| v0_15(Void) = UnmodeledUse : mu*
# 25| v0_16(Void) = ExitFunction :
# 29| Main
# 29| Block 0
# 29| v0_0(Void) = EnterFunction :
# 29| mu0_1(null) = AliasedDefinition :
# 29| mu0_2(null) = UnmodeledDefinition :
# 29| r0_3(glval<DerivedClass>) = InitializeThis :
# 31| r0_4(glval<DerivedClass>) = VariableAddress[obj1] :
# 31| r0_5(DerivedClass) = NewObj :
# 31| r0_6(glval<DerivedClass>) = FunctionAddress[DerivedClass.DerivedClass()] :
# 31| r0_7(DerivedClass) = Call : func:r0_6, this:r0_5
# 31| mu0_8(null) = ^CallSideEffect : ~mu0_2
# 31| mu0_9(DerivedClass) = Store : &:r0_4, r0_5
# 32| r0_10(glval<DerivedClass>) = VariableAddress[obj2] :
# 32| r0_11(DerivedClass) = NewObj :
# 32| r0_12(glval<DerivedClass>) = FunctionAddress[DerivedClass.DerivedClass(int)] :
# 32| r0_13(Int32) = Constant[1] :
# 32| r0_14(DerivedClass) = Call : func:r0_12, this:r0_11, 0:r0_13
# 32| mu0_15(null) = ^CallSideEffect : ~mu0_2
# 32| mu0_16(DerivedClass) = Store : &:r0_10, r0_11
# 33| r0_17(glval<DerivedClass>) = VariableAddress[obj3] :
# 33| r0_18(DerivedClass) = NewObj :
# 33| r0_19(glval<DerivedClass>) = FunctionAddress[DerivedClass.DerivedClass(int, int)] :
# 33| r0_20(Int32) = Constant[1] :
# 33| r0_21(Int32) = Constant[2] :
# 33| r0_22(DerivedClass) = Call : func:r0_19, this:r0_18, 0:r0_20, 1:r0_21
# 33| mu0_23(null) = ^CallSideEffect : ~mu0_2
# 33| mu0_24(DerivedClass) = Store : &:r0_17, r0_18
# 29| v0_25(Void) = ReturnVoid :
# 29| v0_26(Void) = UnmodeledUse : mu*
# 29| v0_27(Void) = ExitFunction :
crement.cs:
# 2| Main
# 2| Block 0
@@ -218,6 +332,76 @@ func_with_param_call.cs:
# 8| v0_13(Void) = UnmodeledUse : mu*
# 8| v0_14(Void) = ExitFunction :
inheritance_polymorphism.cs:
# 3| function
# 3| Block 0
# 3| v0_0(Void) = EnterFunction :
# 3| mu0_1(null) = AliasedDefinition :
# 3| mu0_2(null) = UnmodeledDefinition :
# 3| r0_3(glval<A>) = InitializeThis :
# 5| r0_4(glval<Int32>) = VariableAddress[#return] :
# 5| r0_5(Int32) = Constant[0] :
# 5| mu0_6(Int32) = Store : &:r0_4, r0_5
# 3| r0_7(glval<Int32>) = VariableAddress[#return] :
# 3| v0_8(Void) = ReturnValue : &:r0_7, ~mu0_2
# 3| v0_9(Void) = UnmodeledUse : mu*
# 3| v0_10(Void) = ExitFunction :
# 15| function
# 15| Block 0
# 15| v0_0(Void) = EnterFunction :
# 15| mu0_1(null) = AliasedDefinition :
# 15| mu0_2(null) = UnmodeledDefinition :
# 15| r0_3(glval<C>) = InitializeThis :
# 17| r0_4(glval<Int32>) = VariableAddress[#return] :
# 17| r0_5(Int32) = Constant[1] :
# 17| mu0_6(Int32) = Store : &:r0_4, r0_5
# 15| r0_7(glval<Int32>) = VariableAddress[#return] :
# 15| v0_8(Void) = ReturnValue : &:r0_7, ~mu0_2
# 15| v0_9(Void) = UnmodeledUse : mu*
# 15| v0_10(Void) = ExitFunction :
# 23| Main
# 23| Block 0
# 23| v0_0(Void) = EnterFunction :
# 23| mu0_1(null) = AliasedDefinition :
# 23| mu0_2(null) = UnmodeledDefinition :
# 23| r0_3(glval<Program>) = InitializeThis :
# 25| r0_4(glval<B>) = VariableAddress[objB] :
# 25| r0_5(B) = NewObj :
# 25| r0_6(glval<B>) = FunctionAddress[B.B()] :
# 25| r0_7(B) = Call : func:r0_6, this:r0_5
# 25| mu0_8(null) = ^CallSideEffect : ~mu0_2
# 25| mu0_9(B) = Store : &:r0_4, r0_5
# 26| r0_10(glval<B>) = VariableAddress[objB] :
# 26| r0_11(glval<Int32>) = FunctionAddress[A.function()] :
# 26| r0_12(Int32) = Call : func:r0_11, this:r0_10
# 26| mu0_13(null) = ^CallSideEffect : ~mu0_2
# 29| r0_14(glval<A>) = VariableAddress[objA] :
# 29| mu0_15(A) = Uninitialized[objA] : &:r0_14
# 30| r0_16(glval<B>) = VariableAddress[objB] :
# 30| r0_17(A) = Convert : r0_16
# 30| r0_18(glval<A>) = VariableAddress[objA] :
# 30| mu0_19(A) = Store : &:r0_18, r0_17
# 31| r0_20(glval<A>) = VariableAddress[objA] :
# 31| r0_21(glval<Int32>) = FunctionAddress[A.function()] :
# 31| r0_22(Int32) = Call : func:r0_21, this:r0_20
# 31| mu0_23(null) = ^CallSideEffect : ~mu0_2
# 33| r0_24(glval<A>) = VariableAddress[objC] :
# 33| r0_25(C) = NewObj :
# 33| r0_26(glval<C>) = FunctionAddress[C.C()] :
# 33| r0_27(C) = Call : func:r0_26, this:r0_25
# 33| mu0_28(null) = ^CallSideEffect : ~mu0_2
# 33| r0_29(A) = Convert : r0_25
# 33| mu0_30(C) = Store : &:r0_24, r0_29
# 34| r0_31(glval<A>) = VariableAddress[objC] :
# 34| r0_32(glval<Int32>) = FunctionAddress[A.function()] :
# 34| r0_33(Int32) = Call : func:r0_32, this:r0_31
# 34| mu0_34(null) = ^CallSideEffect : ~mu0_2
# 23| v0_35(Void) = ReturnVoid :
# 23| v0_36(Void) = UnmodeledUse : mu*
# 23| v0_37(Void) = ExitFunction :
obj_creation.cs:
# 5| MyClass
# 5| Block 0