mirror of
https://github.com/github/codeql.git
synced 2026-04-28 02:05:14 +02:00
General tidy up and refactor
Refactored the C++ specific names Tidied the code Updated TODOs
This commit is contained in:
committed by
AndreiDiaconu1
parent
c733bc0ae9
commit
025d68f07a
@@ -11,9 +11,9 @@ class IRConfiguration extends TIRConfiguration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if IR should be created for method `method`. By default, holds for all method.
|
||||
* Holds if IR should be created for callable `callable`. By default, holds for all callables.
|
||||
*/
|
||||
predicate shouldCreateIRForFunction(Callable callable) {
|
||||
predicate shouldCreateIRForCallable(Callable callable) {
|
||||
any()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
/*
|
||||
* Temporary file that has stubs for various functionalities in the IR conversion.
|
||||
*/
|
||||
|
||||
|
||||
import csharp
|
||||
|
||||
class Locatable extends Element {
|
||||
@@ -18,7 +23,7 @@ class ArrayInitWithMod extends ArrayInitializer {
|
||||
|
||||
class ObjectInitializerMod extends ObjectInitializer {
|
||||
private predicate isInitialized(Field field) {
|
||||
not (field.isReadOnly()) and // TODO: Think this is the only instance where a field is not initializable
|
||||
not (field.isReadOnly()) and // TODO: Is this the only instance whena field can not be init?
|
||||
this.getAMemberInitializer().getTargetVariable() = field
|
||||
}
|
||||
|
||||
@@ -29,6 +34,7 @@ class ObjectInitializerMod extends ObjectInitializer {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: See if we need to adapt this for C#
|
||||
abstract class SideEffectCallable extends Callable {
|
||||
/**
|
||||
* Holds if the function never reads from memory that was defined before entry to the function.
|
||||
|
||||
@@ -1 +1 @@
|
||||
import implementation.aliased_ssa.gvn.ValueNumbering
|
||||
import implementation.raw.gvn.ValueNumbering
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// TODO: FIX THE SWITCH STMT
|
||||
// TODO: Fix the switch
|
||||
|
||||
import csharp
|
||||
|
||||
|
||||
@@ -11,14 +11,11 @@ abstract class ValueCategory extends TValueCategory {
|
||||
abstract class RValue extends ValueCategory {
|
||||
}
|
||||
|
||||
class LValue extends ValueCategory {
|
||||
override string toString() {
|
||||
result = "lvalue"
|
||||
}
|
||||
abstract class LValue extends ValueCategory {
|
||||
}
|
||||
|
||||
ValueCategory getExprValueCategory(Expr expr) {
|
||||
(
|
||||
result instanceof LValue
|
||||
)
|
||||
}
|
||||
//ValueCategory getExprValueCategory(Expr expr) {
|
||||
// (
|
||||
// result instanceof LValue
|
||||
// )
|
||||
//}
|
||||
|
||||
@@ -4,35 +4,35 @@ import csharp
|
||||
|
||||
private newtype TIRFunction =
|
||||
MkIRFunction(Callable callable) {
|
||||
Construction::functionHasIR(callable)
|
||||
Construction::callableHasIR(callable)
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the IR for a function.
|
||||
*/
|
||||
class IRFunction extends TIRFunction {
|
||||
Callable func;
|
||||
Callable callable;
|
||||
|
||||
IRFunction() {
|
||||
this = MkIRFunction(func)
|
||||
this = MkIRFunction(callable)
|
||||
}
|
||||
|
||||
final string toString() {
|
||||
result = "IR: " + func.toString()
|
||||
result = "IR: " + callable.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the function whose IR is represented.
|
||||
*/
|
||||
final Callable getFunction() {
|
||||
result = func
|
||||
final Callable getCallable() {
|
||||
result = callable
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the location of the function.
|
||||
*/
|
||||
final Location getLocation() {
|
||||
result = func.getLocation()
|
||||
result = callable.getLocation()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -50,7 +50,7 @@ abstract class IRVariable extends TIRVariable {
|
||||
* Gets the IR for the function that references this variable.
|
||||
*/
|
||||
final IRFunction getEnclosingIRFunction() {
|
||||
result.getFunction() = callable
|
||||
result.getCallable() = callable
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -61,7 +61,7 @@ module InstructionSanity {
|
||||
message = "Instruction '" + instr.getOpcode().toString() + "' is missing an expected operand with tag '" +
|
||||
tag.toString() + "' in function '$@'." and
|
||||
func = instr.getEnclosingIRFunction() and
|
||||
funcText = func.getFunction().getName()
|
||||
funcText = func.getCallable().getName()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -192,7 +192,7 @@ module InstructionSanity {
|
||||
* This check ensures we don't have too _few_ back edges.
|
||||
*/
|
||||
query predicate containsLoopOfForwardEdges(IRFunction f) {
|
||||
f.getFunction().fromSource() and
|
||||
f.getCallable().fromSource() and
|
||||
exists(IRBlock block |
|
||||
forwardEdge+(block, block) and
|
||||
block.getEnclosingIRFunction() = f
|
||||
@@ -213,7 +213,7 @@ module InstructionSanity {
|
||||
entry = f.getEntryBlock() and
|
||||
entry.getASuccessor+() = block and
|
||||
not forwardEdge+(entry, block) and
|
||||
not exists(GotoStmt s | s.getEnclosingCallable() = f.getFunction())
|
||||
not exists(GotoStmt s | s.getEnclosingCallable() = f.getCallable())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -316,18 +316,19 @@ class Instruction extends Construction::TInstruction {
|
||||
|
||||
bindingset[type]
|
||||
private string getValueCategoryString(string type) {
|
||||
if isGLValue() then
|
||||
result = "glval<" + type + ">"
|
||||
if isLValue() then
|
||||
result = "lval<" + type + ">"
|
||||
else
|
||||
result = type
|
||||
}
|
||||
|
||||
// TODO: Memory model in C#?
|
||||
string getResultTypeString() {
|
||||
exists(string valcat |
|
||||
valcat = getValueCategoryString(getResultType().toString()) and
|
||||
if (getResultType() instanceof UnknownType and
|
||||
not isGLValue())/* and
|
||||
exists(getResultSize()))*/ then ( // TODO: SIZES HERE??
|
||||
not isLValue())/* and
|
||||
exists(getResultSize()))*/ then (
|
||||
result = valcat + "[" + /*getResultSize().toString()*/8.toString() + "]"
|
||||
)
|
||||
else
|
||||
@@ -393,7 +394,7 @@ class Instruction extends Construction::TInstruction {
|
||||
* Gets the function that contains this instruction.
|
||||
*/
|
||||
final Callable getEnclosingCallable() {
|
||||
result = getEnclosingIRFunction().getFunction()
|
||||
result = getEnclosingIRFunction().getCallable()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -460,18 +461,18 @@ class Instruction extends Construction::TInstruction {
|
||||
* result of the `Load` instruction is a prvalue of type `int`, representing
|
||||
* the integer value loaded from variable `x`.
|
||||
*/
|
||||
final predicate isGLValue() {
|
||||
final predicate isLValue() {
|
||||
Construction::instructionHasType(this, _, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the size of the result produced by this instruction, in bytes. If the
|
||||
* result does not have a known constant size, this predicate does not hold.
|
||||
*
|
||||
* If `this.isGLValue()` holds for this instruction, the value of
|
||||
* `getResultSize()` will always be the size of a pointer.
|
||||
*/
|
||||
// TODO: HOW TO DEAL WITH SIZES???
|
||||
// TODO: Memory model in C#
|
||||
// /**
|
||||
// * Gets the size of the result produced by this instruction, in bytes. If the
|
||||
// * result does not have a known constant size, this predicate does not hold.
|
||||
// *
|
||||
// * If `this.isGLValue()` holds for this instruction, the value of
|
||||
// * `getResultSize()` will always be the size of a pointer.
|
||||
// */
|
||||
// final int getResultSize() {
|
||||
// if isGLValue() then (
|
||||
// // a glvalue is always pointer-sized.
|
||||
@@ -1085,12 +1086,12 @@ class InheritanceConversionInstruction extends UnaryInstruction {
|
||||
result = derivedClass.toString() + " : " + baseClass.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `ClassDerivation` for the inheritance relationship between
|
||||
* the base and derived classes. This predicate does not hold if the
|
||||
* conversion is to an indirect virtual base class.
|
||||
*/
|
||||
// TODO: WHAT IS THE EQUIV IN C#
|
||||
// TODO: WHAT IS THE EQUIV IN C#
|
||||
// /**
|
||||
// * Gets the `ClassDerivation` for the inheritance relationship between
|
||||
// * the base and derived classes. This predicate does not hold if the
|
||||
// * conversion is to an indirect virtual base class.
|
||||
// */
|
||||
// final ClassDerivation getDerivation() {
|
||||
// result.getBaseClass() = baseClass and result.getDerivedClass() = derivedClass
|
||||
// }
|
||||
|
||||
@@ -116,8 +116,8 @@ class Operand extends TOperand {
|
||||
* not hold, the value of the operand represents a value whose type is
|
||||
* given by `getResultType()`.
|
||||
*/
|
||||
predicate isGLValue() {
|
||||
getDefinitionInstruction().isGLValue()
|
||||
predicate isLValue() {
|
||||
getDefinitionInstruction().isLValue()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -125,7 +125,7 @@ class Operand extends TOperand {
|
||||
* a known constant size, this predicate does not hold.
|
||||
*/
|
||||
int getSize() {
|
||||
result = 8 //getType().getSize() TODO: SIZE IN C#
|
||||
result = 8 //getType().getSize() TODO: C# memory layout
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,7 +138,7 @@ class MemoryOperand extends Operand {
|
||||
this = TPhiOperand(_, _, _, _)
|
||||
}
|
||||
|
||||
override predicate isGLValue() {
|
||||
override predicate isLValue() {
|
||||
// A `MemoryOperand` can never be a glvalue
|
||||
none()
|
||||
}
|
||||
@@ -389,7 +389,8 @@ class SideEffectOperand extends TypedOperand {
|
||||
if getType() instanceof UnknownType then
|
||||
result = Construction::getInstructionOperandSize(useInstr, tag)
|
||||
else
|
||||
result = 8 //getType().getSize() TODO; SIZES IN C#??
|
||||
// TODO: Memory layout in C#
|
||||
result = 8 //getType().getSize()
|
||||
}
|
||||
|
||||
override MemoryAccessKind getMemoryAccess() {
|
||||
|
||||
@@ -22,7 +22,7 @@ class PrintIRConfiguration extends TPrintIRConfiguration {
|
||||
}
|
||||
}
|
||||
|
||||
private predicate shouldPrintFunction(Callable func) {
|
||||
private predicate shouldPrintCallable(Callable func) {
|
||||
exists(PrintIRConfiguration config |
|
||||
config.shouldPrintFunction(func)
|
||||
)
|
||||
@@ -32,8 +32,8 @@ private predicate shouldPrintFunction(Callable func) {
|
||||
* Override of `IRConfiguration` to only create IR for the functions that are to be dumped.
|
||||
*/
|
||||
private class FilteredIRConfiguration extends IRConfiguration {
|
||||
override predicate shouldCreateIRForFunction(Callable func) {
|
||||
shouldPrintFunction(func)
|
||||
override predicate shouldCreateIRForCallable(Callable func) {
|
||||
shouldPrintCallable(func)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,13 +51,13 @@ private string getAdditionalBlockProperty(IRBlock block, string key) {
|
||||
|
||||
private newtype TPrintableIRNode =
|
||||
TPrintableIRFunction(IRFunction irFunc) {
|
||||
shouldPrintFunction(irFunc.getFunction())
|
||||
shouldPrintCallable(irFunc.getCallable())
|
||||
} or
|
||||
TPrintableIRBlock(IRBlock block) {
|
||||
shouldPrintFunction(block.getEnclosingFunction())
|
||||
shouldPrintCallable(block.getEnclosingFunction())
|
||||
} or
|
||||
TPrintableInstruction(Instruction instr) {
|
||||
shouldPrintFunction(instr.getEnclosingCallable())
|
||||
shouldPrintCallable(instr.getEnclosingCallable())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -132,7 +132,7 @@ class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction {
|
||||
|
||||
override string getLabel() {
|
||||
// TODO: C++ USED THE PRINT MODULE, NOT SURE TOsTRING DOES THE JOB
|
||||
result = irFunc.getFunction().toString()
|
||||
result = irFunc.getCallable().toString()
|
||||
}
|
||||
|
||||
override int getOrder() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
private import internal.ConstantAnalysisInternal
|
||||
private import semmle.code.sharp.ir.internal.IntegerConstant
|
||||
private import semmle.code.csharp.ir.internal.IntegerConstant
|
||||
private import ConstantAnalysis
|
||||
import IR
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ InstructionTag getInstructionTag(Instruction instruction) {
|
||||
|
||||
import Cached
|
||||
cached private module Cached {
|
||||
cached predicate functionHasIR(Callable callable) {
|
||||
cached predicate callableHasIR(Callable callable) {
|
||||
exists(getTranslatedFunction(callable)) and
|
||||
callable.fromSource()
|
||||
}
|
||||
@@ -162,24 +162,6 @@ cached private module Cached {
|
||||
instruction = inLoop.getInstruction(tag)
|
||||
)
|
||||
)
|
||||
//or
|
||||
// TODO: TRANSLATE TO FOREACH
|
||||
// Range-based for loop:
|
||||
// Any edge from within the update of the loop to the condition of
|
||||
// the loop is a back edge.
|
||||
// exists(TranslatedRangeBasedForStmt s, TranslatedCondition condition |
|
||||
// s instanceof TranslatedRangeBasedForStmt and
|
||||
// condition = s.getCondition() and
|
||||
// result = condition.getFirstInstruction() and
|
||||
// exists(TranslatedElement inUpdate, InstructionTag tag |
|
||||
// result = inUpdate.getInstructionSuccessor(tag, kind) and
|
||||
// exists(TranslatedElement update |
|
||||
// update = s.getUpdate() |
|
||||
// inUpdate = update.getAChild*()
|
||||
// ) and
|
||||
// instruction = inUpdate.getInstruction(tag)
|
||||
// )
|
||||
// )
|
||||
or
|
||||
// Goto statement:
|
||||
// As a conservative approximation, any edge out of `goto` is a back edge
|
||||
@@ -208,9 +190,9 @@ cached private module Cached {
|
||||
result = getInstructionTranslatedElement(instruction).getAST()
|
||||
}
|
||||
|
||||
cached predicate instructionHasType(Instruction instruction, Type type, boolean isGLValue) {
|
||||
cached predicate instructionHasType(Instruction instruction, Type type, boolean isLValue) {
|
||||
getInstructionTranslatedElement(instruction)
|
||||
.hasInstruction(_, getInstructionTag(instruction), type, isGLValue)
|
||||
.hasInstruction(_, getInstructionTag(instruction), type, isLValue)
|
||||
}
|
||||
|
||||
cached Opcode getInstructionOpcode(Instruction instruction) {
|
||||
@@ -219,7 +201,7 @@ cached private module Cached {
|
||||
}
|
||||
|
||||
cached IRFunction getInstructionEnclosingIRFunction(Instruction instruction) {
|
||||
result.getFunction() = getInstructionTranslatedElement(instruction).getCallable()
|
||||
result.getCallable() = getInstructionTranslatedElement(instruction).getCallable()
|
||||
}
|
||||
|
||||
cached IRVariable getInstructionVariable(Instruction instruction) {
|
||||
|
||||
@@ -2,10 +2,10 @@ import csharp
|
||||
import semmle.code.csharp.ir.Util
|
||||
|
||||
|
||||
// TODO:IN C# DOES IT MAKE SENSE TO HAVE BOTH?
|
||||
// TODO: Both exists needed?
|
||||
private predicate fieldIsInitialized(Field field) {
|
||||
exists(ObjectInitializer initList |
|
||||
exists(int i |field = initList.getMemberInitializer(i).getInitializedMember())
|
||||
exists(int i | field = initList.getMemberInitializer(i).getInitializedMember())
|
||||
) or
|
||||
exists(MemberInitializer init |
|
||||
field = init.getInitializedMember()
|
||||
@@ -87,14 +87,7 @@ newtype TInstructionTag =
|
||||
} or
|
||||
InitializerElementDefaultValueStoreTag(int elementIndex) {
|
||||
elementIsInitialized(elementIndex)
|
||||
} // or
|
||||
// TODO: ASM NOT PRESENT IN C#
|
||||
// AsmTag() or
|
||||
// AsmInputTag(int elementIndex) {
|
||||
// exists(AsmStmt asm |
|
||||
// exists(asm.getChild(elementIndex))
|
||||
// )
|
||||
// }
|
||||
}
|
||||
|
||||
class InstructionTag extends TInstructionTag {
|
||||
final string toString() {
|
||||
@@ -154,7 +147,7 @@ string getInstructionTagId(TInstructionTag tag) {
|
||||
tag = CatchTag() and result = "Catch" or
|
||||
tag = ThrowTag() and result = "Throw" or
|
||||
tag = UnwindTag() and result = "Unwind" or
|
||||
// TODO: WHY?
|
||||
// TODO: Reread
|
||||
// exists(Field field, Class cls, int index, string tagName |
|
||||
// field = cls.getCanonicalMember(index) and
|
||||
// (
|
||||
@@ -172,9 +165,5 @@ string getInstructionTagId(TInstructionTag tag) {
|
||||
tag = InitializerElementDefaultValueStoreTag(index) and tagName = "InitElemDefValStore"
|
||||
) and
|
||||
result = tagName + "(" + index + ")"
|
||||
) // or TODO: ASM HERE?
|
||||
// tag = AsmTag() and result = "Asm" or
|
||||
// exists(int index |
|
||||
// tag = AsmInputTag(index) and result = "AsmInputTag(" + index + ")"
|
||||
// )
|
||||
)
|
||||
}
|
||||
|
||||
@@ -30,12 +30,12 @@ abstract class TranslatedCall extends TranslatedExpr {
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
Type resultType, boolean isLValue) {
|
||||
(
|
||||
tag = CallTag() and
|
||||
opcode instanceof Opcode::Call and
|
||||
resultType = getCallResultType() and
|
||||
isGLValue = false
|
||||
isLValue = false
|
||||
) or
|
||||
(
|
||||
hasSideEffect() and
|
||||
@@ -50,7 +50,7 @@ abstract class TranslatedCall extends TranslatedExpr {
|
||||
resultType instanceof VoidType
|
||||
)
|
||||
) and
|
||||
isGLValue = false
|
||||
isLValue = false
|
||||
)
|
||||
}
|
||||
|
||||
@@ -241,8 +241,8 @@ abstract class TranslatedDirectCall extends TranslatedCall {
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
TranslatedCall.super.hasInstruction(opcode, tag, resultType, isGLValue) or
|
||||
Type resultType, boolean isLValue) {
|
||||
TranslatedCall.super.hasInstruction(opcode, tag, resultType, isLValue) or
|
||||
(
|
||||
tag = CallTargetTag() and
|
||||
opcode instanceof Opcode::FunctionAddress and
|
||||
@@ -250,7 +250,7 @@ abstract class TranslatedDirectCall extends TranslatedCall {
|
||||
// its address was taken, so we'll just use glval<Unknown> instead of
|
||||
// glval<FunctionType>.
|
||||
resultType instanceof UnknownType and
|
||||
isGLValue = true
|
||||
isLValue = true
|
||||
)
|
||||
}
|
||||
|
||||
@@ -281,7 +281,9 @@ abstract class TranslatedCallExpr extends TranslatedNonConstantExpr,
|
||||
}
|
||||
|
||||
override final TranslatedExpr getQualifier() {
|
||||
result = getTranslatedExpr(expr.getChild(-1)) // TODO: CHECK getQUALIFIER() SAME AS THIS
|
||||
// TODO: Was getQualifier in the C++ implementation, make sure
|
||||
// meaning is kept
|
||||
result = getTranslatedExpr(expr.getChild(-1))
|
||||
}
|
||||
|
||||
override final TranslatedExpr getArgument(int index) {
|
||||
@@ -289,19 +291,6 @@ abstract class TranslatedCallExpr extends TranslatedNonConstantExpr,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the IR translation of a call through a function pointer.
|
||||
*/
|
||||
// TODO: PROB NOT IN C#
|
||||
//class TranslatedExprCall extends TranslatedCallExpr {
|
||||
// override ExprCall expr;
|
||||
//
|
||||
//
|
||||
// override TranslatedExpr getCallTarget() {
|
||||
// result = getTranslatedExpr(expr.getExpr().getFullyConverted())
|
||||
// }
|
||||
//}
|
||||
|
||||
/**
|
||||
* Represents the IR translation of a direct function call.
|
||||
*/
|
||||
@@ -322,12 +311,11 @@ class TranslatedFunctionCall extends TranslatedCallExpr, TranslatedDirectCall {
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the IR translation of a call to a constructor.
|
||||
* Represents the IR translation of a call to a constructor (can't call destructor explicitly in C#.
|
||||
*/
|
||||
class TranslatedStructorCall extends TranslatedFunctionCall {
|
||||
TranslatedStructorCall() {
|
||||
expr instanceof ObjectCreation // or
|
||||
// expr instanceof DestructorCall TODO: ILLEGAL TO EXPLICITILY CALL DESTRUCTOR
|
||||
expr instanceof ObjectCreation
|
||||
}
|
||||
|
||||
override Instruction getQualifierResult() {
|
||||
|
||||
@@ -59,7 +59,7 @@ abstract class TranslatedFlexibleCondition extends TranslatedCondition,
|
||||
}
|
||||
|
||||
override final predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
Type resultType, boolean isLValue) {
|
||||
none()
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ abstract class TranslatedBinaryLogicalOperation extends
|
||||
}
|
||||
|
||||
override final predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
Type resultType, boolean isLValue) {
|
||||
none()
|
||||
}
|
||||
|
||||
@@ -211,11 +211,11 @@ class TranslatedValueCondition extends TranslatedCondition,
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
Type resultType, boolean isLValue) {
|
||||
tag = ValueConditionConditionalBranchTag() and
|
||||
opcode instanceof Opcode::ConditionalBranch and
|
||||
resultType instanceof VoidType and
|
||||
isGLValue = false
|
||||
isLValue = false
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
|
||||
@@ -21,6 +21,7 @@ TranslatedDeclarationEntry getTranslatedDeclarationEntry(Declaration entry) {
|
||||
* it can also be the declaration of a static local variable, an extern
|
||||
* variable, or an extern function.
|
||||
*/
|
||||
// TODO: Make sure local decls are handeld correctly (seem to be)
|
||||
abstract class TranslatedDeclarationEntry extends TranslatedElement, TTranslatedDeclarationEntry {
|
||||
Declaration entry;
|
||||
|
||||
@@ -30,7 +31,6 @@ abstract class TranslatedDeclarationEntry extends TranslatedElement, TTranslated
|
||||
|
||||
override final Callable getCallable() {
|
||||
exists(LocalVariableDeclStmt stmt |
|
||||
// TODO: NOT SURE HOW SOUNDS THIS IS; DO WE MEAN JUST
|
||||
stmt.getAVariableDeclExpr().getVariable() = entry and
|
||||
result = stmt.getEnclosingCallable()
|
||||
)
|
||||
@@ -56,11 +56,11 @@ class TranslatedNonVariableDeclarationEntry extends TranslatedDeclarationEntry {
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
Type resultType, boolean isLValue) {
|
||||
opcode instanceof Opcode::NoOp and
|
||||
tag = OnlyInstructionTag() and
|
||||
resultType instanceof VoidType and
|
||||
isGLValue = false
|
||||
isLValue = false
|
||||
}
|
||||
|
||||
override Instruction getFirstInstruction() {
|
||||
@@ -102,19 +102,19 @@ abstract class TranslatedVariableDeclaration extends TranslatedElement, Initiali
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
Type resultType, boolean isLValue) {
|
||||
(
|
||||
tag = InitializerVariableAddressTag() and
|
||||
opcode instanceof Opcode::VariableAddress and
|
||||
resultType = getVariableType(getVariable()) and
|
||||
isGLValue = true
|
||||
isLValue = true
|
||||
) or
|
||||
(
|
||||
hasUninitializedInstruction() and
|
||||
tag = InitializerStoreTag() and
|
||||
opcode instanceof Opcode::Uninitialized and
|
||||
resultType = getVariableType(getVariable()) and
|
||||
isGLValue = false
|
||||
isLValue = false
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -16,9 +16,8 @@ private import semmle.code.csharp.ir.Util
|
||||
/**
|
||||
* Gets the built-in `int` type.
|
||||
*/
|
||||
// TODO: NOT SURE ABOUT THIS
|
||||
Type getIntType() {
|
||||
result.(IntType).isValueType()
|
||||
IntType getIntType() {
|
||||
any()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -28,8 +27,6 @@ Type getIntType() {
|
||||
*/
|
||||
private Element getRealParent(Expr expr) {
|
||||
result = expr.getParent()
|
||||
// or
|
||||
// result.(Destructor).getADestruction() = expr
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -61,7 +58,8 @@ private predicate ignoreExprAndDescendants(Expr expr) {
|
||||
// node as its qualifier, but that `FieldAccess` does not have a child of its own.
|
||||
// We'll ignore that `FieldAccess`, and supply the receiver as part of the calling
|
||||
// context, much like we do with constructor calls.
|
||||
//TODO: SORT OUT THE DESTRUCTOR STUFF
|
||||
|
||||
// TODO: Deal with C# finalizers and Dispose methods at some point
|
||||
// expr.getParent().(DestructorCall).getParent() instanceof DestructorFieldDestruction or
|
||||
// exists(NewArrayExpr newExpr |
|
||||
// // REVIEW: Ignore initializers for `NewArrayExpr` until we determine how to
|
||||
@@ -75,6 +73,7 @@ private predicate ignoreExprAndDescendants(Expr expr) {
|
||||
* Holds if `expr` (not including its descendants) should be ignored for the
|
||||
* purposes of IR generation.
|
||||
*/
|
||||
// TODO: See what exprs should be ignored for C# IR generation
|
||||
private predicate ignoreExprOnly(Expr expr) {
|
||||
// exists(NewOrNewArrayExpr newExpr |
|
||||
// // Ignore the allocator call, because we always synthesize it. Don't ignore
|
||||
@@ -92,11 +91,11 @@ private predicate ignoreExpr(Expr expr) {
|
||||
ignoreExprAndDescendants(expr)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `func` contains an AST that cannot be translated into IR. This is mostly used to work
|
||||
* around extractor bugs. Once the relevant extractor bugs are fixed, this predicate can be removed.
|
||||
*/
|
||||
// TODO: PROBABLY OK TO COMMENT FOR NOW
|
||||
// TODO: Probably ok to ignore for now
|
||||
///**
|
||||
// * Holds if `func` contains an AST that cannot be translated into IR. This is mostly used to work
|
||||
// * around extractor bugs. Once the relevant extractor bugs are fixed, this predicate can be removed.
|
||||
// */
|
||||
//private predicate isInvalidFunction(Callable callable) {
|
||||
// exists(Literal literal |
|
||||
// // Constructor field inits within a compiler-generated copy constructor have a source expression
|
||||
@@ -121,11 +120,10 @@ private predicate ignoreExpr(Expr expr) {
|
||||
* Holds if `func` should be translated to IR.
|
||||
*/
|
||||
private predicate translateFunction(Callable callable) {
|
||||
// not callable.isFromUninstantiatedTemplate(_) and
|
||||
// callable.hasEntryPoint() and
|
||||
/*not isInvalidFunction(callable) and*/
|
||||
// not isInvalidFunction(callable)
|
||||
exists(callable.getEntryPoint()) and
|
||||
exists(IRConfiguration config |
|
||||
config.shouldCreateIRForFunction(callable)
|
||||
config.shouldCreateIRForCallable(callable)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -186,25 +184,16 @@ private predicate usedAsCondition(Expr expr) {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `expr` has an lvalue-to-rvalue conversion that should be ignored
|
||||
* when generating IR. This occurs for conversion from an lvalue of function type
|
||||
* to an rvalue of function pointer type. The conversion is represented in the
|
||||
* AST as an lvalue-to-rvalue conversion, but the IR represents both a function
|
||||
* lvalue and a function pointer prvalue the same.
|
||||
*/
|
||||
// TODO: probably not needed for C#
|
||||
// TODO: Should be enough to translate loads only if they are accesses for now
|
||||
///**
|
||||
// * Holds if `expr` has an lvalue-to-rvalue conversion that should be ignored
|
||||
// * when generating IR. This occurs for conversion from an lvalue of function type
|
||||
// * to an rvalue of function pointer type. The conversion is represented in the
|
||||
// * AST as an lvalue-to-rvalue conversion, but the IR represents both a function
|
||||
// * lvalue and a function pointer prvalue the same.
|
||||
// */
|
||||
predicate ignoreLoad(Expr expr) {
|
||||
// expr.hasLValueToRValueConversion() and
|
||||
// (
|
||||
// expr instanceof ThisExpr or
|
||||
// expr instanceof FunctionAccess or
|
||||
// expr.(PointerDereferenceExpr).getOperand().getFullyConverted().getType().
|
||||
// getUnspecifiedType() instanceof FunctionPointerType or
|
||||
// expr.(ReferenceDereferenceExpr).getExpr().getType().
|
||||
// getUnspecifiedType() instanceof FunctionReferenceType
|
||||
// )
|
||||
any()
|
||||
not (expr instanceof Access)
|
||||
}
|
||||
|
||||
newtype TTranslatedElement =
|
||||
@@ -217,9 +206,9 @@ newtype TTranslatedElement =
|
||||
// A separate element to handle the lvalue-to-rvalue conversion step of an
|
||||
// expression.
|
||||
TTranslatedLoad(Expr expr) {
|
||||
// TODO: THINK THIS SHOULD BE ENOUGH, ONLY OCC (C# 6.0) WHEN WE WANT A CONV. IS A VAR ACCESS
|
||||
expr instanceof Access and
|
||||
not ignoreExpr(expr) // and
|
||||
not ignoreExpr(expr) and
|
||||
// TODO: Should be enough to translate loads only if they are accesses for now
|
||||
not ignoreLoad(expr)
|
||||
// not isNativeCondition(expr) and
|
||||
// not isFlexibleCondition(expr) and
|
||||
// expr.hasLValueToRValueConversion() and
|
||||
@@ -254,7 +243,7 @@ newtype TTranslatedElement =
|
||||
not usedAsCondition(expr)
|
||||
} or
|
||||
// An expression used as an initializer.
|
||||
// TODO: CHECK IF USED INITIALIZERS ARE ACTUALLY RIGHT !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
// TODO: Make sure the initializers here are right
|
||||
TTranslatedInitialization(Expr expr) {
|
||||
not ignoreExpr(expr) and
|
||||
(
|
||||
@@ -293,7 +282,6 @@ newtype TTranslatedElement =
|
||||
exists(ObjectInitializer initList |
|
||||
not ignoreExpr(initList) and
|
||||
ast = initList and
|
||||
// TODO: OPTIMIZE
|
||||
expr = any(int i |
|
||||
field = initList.getMemberInitializer(i).getInitializedMember() |
|
||||
initList.getMemberInitializer(i)).getRValue()
|
||||
@@ -302,7 +290,7 @@ newtype TTranslatedElement =
|
||||
not ignoreExpr(init) and
|
||||
ast = init and
|
||||
field = init.getInitializedMember() and
|
||||
// TODO: WAS GETEXPR, I THINK GETRVALUE DOES THE SAME SINCE IT IS THE RVALUE OF THE ASSIGNMENT
|
||||
// TODO: Was .getExpr, getRValue should be the correspondent for C#
|
||||
expr = init.getRValue()
|
||||
)
|
||||
} or
|
||||
@@ -331,7 +319,7 @@ newtype TTranslatedElement =
|
||||
getEndOfValueInitializedRange(initList, elementIndex) -
|
||||
elementIndex
|
||||
} or
|
||||
// TODO: NEXT 3 CASES NEED TO BE ADAPTED TO C#
|
||||
// TODO: Convert to C#
|
||||
// The initialization of a base class from within a constructor.
|
||||
// TTranslatedConstructorBaseInit(ConstructorBaseInit init) {
|
||||
// not ignoreExpr(init)
|
||||
@@ -364,8 +352,7 @@ newtype TTranslatedElement =
|
||||
TTranslatedParameter(Parameter param) {
|
||||
exists(Callable func |
|
||||
(
|
||||
func = param.getCallable() // or
|
||||
// func = param.getCatchBlock().getEnclosingFunction() TODO: C# does not support params in catch blocks
|
||||
func = param.getCallable()
|
||||
) and
|
||||
translateFunction(func)
|
||||
)
|
||||
@@ -395,13 +382,7 @@ newtype TTranslatedElement =
|
||||
// An allocation size for a `new` or `new[]` expression
|
||||
TTranslatedAllocationSize(ObjectCreation newExpr) {
|
||||
not ignoreExpr(newExpr)
|
||||
} //or
|
||||
|
||||
// The declaration/initialization part of a `ConditionDeclExpr`
|
||||
// TODO: ILLEGAL IN C#
|
||||
// TTranslatedConditionDecl(ConditionDeclExpr expr) {
|
||||
// not ignoreExpr(expr)
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index of the first explicitly initialized element in `initList`
|
||||
@@ -529,7 +510,7 @@ abstract class TranslatedElement extends TTranslatedElement {
|
||||
* `VoidType`.
|
||||
*/
|
||||
abstract predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue);
|
||||
Type resultType, boolean isLValue);
|
||||
|
||||
/**
|
||||
* Gets the `Function` that contains this element.
|
||||
|
||||
@@ -113,7 +113,7 @@ abstract class TranslatedCoreExpr extends TranslatedExpr {
|
||||
final boolean isResultGLValue() {
|
||||
// if(
|
||||
// expr.hasValue()
|
||||
//// expr.isGLValueCategory() or
|
||||
//// expr.Category() or
|
||||
//// // If this TranslatedExpr doesn't produce the result, then it must represent
|
||||
//// // a glvalue that is then loaded by a TranslatedLoad.
|
||||
//// not producesExprResult()
|
||||
@@ -140,7 +140,7 @@ class TranslatedConditionValue extends TranslatedCoreExpr, ConditionContext,
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
Type resultType, boolean isLValue) {
|
||||
(
|
||||
(
|
||||
tag = ConditionValueTrueTempAddressTag() or
|
||||
@@ -149,7 +149,7 @@ class TranslatedConditionValue extends TranslatedCoreExpr, ConditionContext,
|
||||
) and
|
||||
opcode instanceof Opcode::VariableAddress and
|
||||
resultType = getResultType() and
|
||||
isGLValue = true
|
||||
isLValue = true
|
||||
) or
|
||||
(
|
||||
(
|
||||
@@ -158,7 +158,7 @@ class TranslatedConditionValue extends TranslatedCoreExpr, ConditionContext,
|
||||
) and
|
||||
opcode instanceof Opcode::Constant and
|
||||
resultType = getResultType() and
|
||||
isGLValue = isResultGLValue()
|
||||
isLValue = isResultGLValue()
|
||||
) or
|
||||
(
|
||||
(
|
||||
@@ -167,13 +167,13 @@ class TranslatedConditionValue extends TranslatedCoreExpr, ConditionContext,
|
||||
) and
|
||||
opcode instanceof Opcode::Store and
|
||||
resultType = getResultType() and
|
||||
isGLValue = isResultGLValue()
|
||||
isLValue = isResultGLValue()
|
||||
) or
|
||||
(
|
||||
tag = ConditionValueResultLoadTag() and
|
||||
opcode instanceof Opcode::Load and
|
||||
resultType = getResultType() and
|
||||
isGLValue = isResultGLValue()
|
||||
isLValue = isResultGLValue()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -323,15 +323,15 @@ class TranslatedLoad extends TranslatedExpr, TTranslatedLoad {
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
Type resultType, boolean isLValue) {
|
||||
tag = LoadTag() and
|
||||
opcode instanceof Opcode::Load and
|
||||
resultType = expr.getType() and
|
||||
// TODO: FIX LVALUE RVALUE STUFF
|
||||
if expr.hasValue() then
|
||||
isGLValue = true
|
||||
isLValue = true
|
||||
else
|
||||
isGLValue = false
|
||||
isLValue = false
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag,
|
||||
@@ -404,7 +404,7 @@ class TranslatedLoad extends TranslatedExpr, TTranslatedLoad {
|
||||
// }
|
||||
//
|
||||
// override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
// Type resultType, boolean isGLValue) {
|
||||
// Type resultType, boolean ) {
|
||||
// none()
|
||||
// }
|
||||
//
|
||||
@@ -452,8 +452,8 @@ class TranslatedLoad extends TranslatedExpr, TTranslatedLoad {
|
||||
// }
|
||||
//
|
||||
// override final predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
// Type resultType, boolean isGLValue) {
|
||||
// isGLValue = false and
|
||||
// Type resultType, boolean ) {
|
||||
// = false and
|
||||
// (
|
||||
// (
|
||||
// tag = CrementLoadTag() and
|
||||
@@ -651,11 +651,11 @@ class TranslatedArrayExpr extends TranslatedNonConstantExpr {
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
Type resultType, boolean isLValue) {
|
||||
tag = OnlyInstructionTag() and
|
||||
opcode instanceof Opcode::PointerAdd and
|
||||
resultType = getBaseOperand().getResultType() and
|
||||
isGLValue = false
|
||||
isLValue = false
|
||||
}
|
||||
|
||||
override Instruction getInstructionOperand(InstructionTag tag,
|
||||
@@ -706,7 +706,7 @@ abstract class TranslatedTransparentExpr extends TranslatedNonConstantExpr {
|
||||
}
|
||||
|
||||
override final predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
Type resultType, boolean isLValue) {
|
||||
none()
|
||||
}
|
||||
|
||||
@@ -764,11 +764,11 @@ class TranslatedThisExpr extends TranslatedNonConstantExpr {
|
||||
}
|
||||
|
||||
override final predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
Type resultType, boolean isLValue) {
|
||||
tag = OnlyInstructionTag() and
|
||||
opcode instanceof Opcode::CopyValue and
|
||||
resultType = expr.getType() and
|
||||
isGLValue = false
|
||||
isLValue = false
|
||||
}
|
||||
|
||||
override final Instruction getResult() {
|
||||
@@ -847,11 +847,11 @@ class TranslatedNonFieldVariableAccess extends TranslatedVariableAccess {
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
Type resultType, boolean isLValue) {
|
||||
tag = OnlyInstructionTag() and
|
||||
opcode instanceof Opcode::VariableAddress and
|
||||
resultType = getResultType() and
|
||||
isGLValue = true
|
||||
isLValue = true
|
||||
}
|
||||
|
||||
override IRVariable getInstructionVariable(InstructionTag tag) {
|
||||
@@ -876,11 +876,11 @@ class TranslatedFieldAccess extends TranslatedVariableAccess {
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
Type resultType, boolean isLValue) {
|
||||
tag = OnlyInstructionTag() and
|
||||
opcode instanceof Opcode::FieldAddress and
|
||||
resultType = getResultType() and
|
||||
isGLValue = true
|
||||
isLValue = true
|
||||
}
|
||||
|
||||
override Field getInstructionField(InstructionTag tag) {
|
||||
@@ -912,11 +912,11 @@ class TranslatedFunctionAccess extends TranslatedNonConstantExpr {
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
Type resultType, boolean isLValue) {
|
||||
tag = OnlyInstructionTag() and
|
||||
opcode instanceof Opcode::FunctionAddress and
|
||||
resultType = expr.getType() and
|
||||
isGLValue = true
|
||||
isLValue = true
|
||||
}
|
||||
|
||||
override Callable getInstructionCallable(InstructionTag tag) {
|
||||
@@ -968,16 +968,16 @@ abstract class TranslatedConstantExpr extends TranslatedCoreExpr, TTranslatedVal
|
||||
}
|
||||
|
||||
override final predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
Type resultType, boolean isLValue) {
|
||||
tag = OnlyInstructionTag() and
|
||||
opcode = getOpcode() and
|
||||
resultType = getResultType() and
|
||||
// TODO: FIX GL VAL
|
||||
// if(expr.isGLValueCategory() or expr.hasLValueToRValueConversion()) then
|
||||
// isGLValue = true
|
||||
// TODO: Fix lvalue stuff here
|
||||
// if(expr.Category() or expr.hasLValueToRValueConversion()) then
|
||||
// isLValue = true
|
||||
// else
|
||||
// isGLValue = false
|
||||
isGLValue = false
|
||||
// isLValue = false
|
||||
isLValue = false
|
||||
}
|
||||
|
||||
override final Instruction getInstructionSuccessor(InstructionTag tag,
|
||||
@@ -1034,11 +1034,11 @@ abstract class TranslatedSingleInstructionExpr extends
|
||||
abstract Opcode getOpcode();
|
||||
|
||||
override final predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
Type resultType, boolean isLValue) {
|
||||
opcode = getOpcode() and
|
||||
tag = OnlyInstructionTag() and
|
||||
resultType = getResultType() and
|
||||
isGLValue = isResultGLValue()
|
||||
isLValue = isResultGLValue()
|
||||
}
|
||||
|
||||
override final Instruction getResult() {
|
||||
@@ -1127,11 +1127,11 @@ abstract class TranslatedSingleInstructionConversion extends TranslatedConversio
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
Type resultType, boolean isLValue) {
|
||||
tag = OnlyInstructionTag() and
|
||||
opcode = getOpcode() and
|
||||
resultType = getResultType() and
|
||||
isGLValue = isResultGLValue()
|
||||
isLValue = isResultGLValue()
|
||||
}
|
||||
|
||||
override Instruction getResult() {
|
||||
@@ -1151,11 +1151,11 @@ abstract class TranslatedSingleInstructionConversion extends TranslatedConversio
|
||||
abstract Opcode getOpcode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the translation of a conversion expression that generates a
|
||||
* `Convert` instruction.
|
||||
*/
|
||||
// TODO: DEAL WITH CONVERSIONS
|
||||
// TODO: Deal with conversions
|
||||
///**
|
||||
// * Represents the translation of a conversion expression that generates a
|
||||
// * `Convert` instruction.
|
||||
// */
|
||||
//class TranslatedSimpleConversion extends TranslatedSingleInstructionConversion {
|
||||
// TranslatedSimpleConversion() {
|
||||
// expr instanceof ArithmeticConversion or
|
||||
@@ -1174,34 +1174,11 @@ abstract class TranslatedSingleInstructionConversion extends TranslatedConversio
|
||||
// }
|
||||
//}
|
||||
|
||||
/**
|
||||
* Represents the translation of a dynamic_cast expression.
|
||||
*/
|
||||
//class TranslatedDynamicCast extends TranslatedSingleInstructionConversion {
|
||||
// TranslatedDynamicCast() {
|
||||
// expr instanceof DynamicCast
|
||||
// }
|
||||
//
|
||||
// override Opcode getOpcode() {
|
||||
// exists(Type resultType |
|
||||
// resultType = getResultType() and
|
||||
// if resultType instanceof PointerType then (
|
||||
// if resultType.(PointerType).getBaseType() instanceof VoidType then
|
||||
// result instanceof Opcode::DynamicCastToVoid
|
||||
// else
|
||||
// result instanceof Opcode::CheckedConvertOrNull
|
||||
// )
|
||||
// else
|
||||
// result instanceof Opcode::CheckedConvertOrThrow
|
||||
// )
|
||||
// }
|
||||
//}
|
||||
|
||||
/**
|
||||
* Represents the translation of a `BaseClassConversion` or `DerivedClassConversion`
|
||||
* expression.
|
||||
*/
|
||||
// TODO: DEAL WITH CONVERSIONS
|
||||
// TODO: Deal with conversions
|
||||
///**
|
||||
// * Represents the translation of a `BaseClassConversion` or `DerivedClassConversion`
|
||||
// * expression.
|
||||
// */
|
||||
//class TranslatedInheritanceConversion extends TranslatedSingleInstructionConversion {
|
||||
// override InheritanceConversion expr;
|
||||
//
|
||||
@@ -1252,8 +1229,8 @@ abstract class TranslatedSingleInstructionConversion extends TranslatedConversio
|
||||
// }
|
||||
//
|
||||
// override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
// Type resultType, boolean isGLValue) {
|
||||
// isGLValue = false and
|
||||
// Type resultType, boolean ) {
|
||||
// = false and
|
||||
// (
|
||||
// (
|
||||
// tag = BoolConversionConstantTag() and
|
||||
@@ -1306,11 +1283,7 @@ private Opcode binaryArithmeticOpcode(BinaryArithmeticOperation expr) {
|
||||
expr instanceof SubExpr and result instanceof Opcode::Sub or
|
||||
expr instanceof MulExpr and result instanceof Opcode::Mul or
|
||||
expr instanceof DivExpr and result instanceof Opcode::Div or
|
||||
expr instanceof RemExpr and result instanceof Opcode::Rem // or
|
||||
// TODO: WHAT ARE THE EQUIVS HERE
|
||||
// expr instanceof PointerAddExpr and result instanceof Opcode::PointerAdd or
|
||||
// expr instanceof PointerSubExpr and result instanceof Opcode::PointerSub or
|
||||
// expr instanceof PointerDiffExpr and result instanceof Opcode::PointerDiff
|
||||
expr instanceof RemExpr and result instanceof Opcode::Rem
|
||||
}
|
||||
|
||||
private Opcode comparisonOpcode(ComparisonOperation expr) {
|
||||
@@ -1500,11 +1473,11 @@ class TranslatedAssignExpr extends TranslatedAssignment {
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
Type resultType, boolean isLValue) {
|
||||
tag = AssignmentStoreTag() and
|
||||
opcode instanceof Opcode::Store and
|
||||
resultType = getResultType() and
|
||||
isGLValue = false
|
||||
isLValue = false
|
||||
}
|
||||
|
||||
override Instruction getInstructionOperand(InstructionTag tag,
|
||||
@@ -1584,17 +1557,7 @@ class TranslatedAssignOperation extends TranslatedAssignment {
|
||||
|
||||
private Type getConvertedLeftOperandType() {
|
||||
if(expr instanceof AssignLShiftExpr or
|
||||
expr instanceof AssignRShiftExpr) then (// or
|
||||
// TODO: DEAL WITH POINTERS!!!
|
||||
// expr instanceof AssignPointerAddExpr or
|
||||
// expr instanceof AssignPointerSubExpr) then (
|
||||
// // No need to convert for a shift. Technically, the left side should
|
||||
// // undergo integral promotion, and then the result would be converted back
|
||||
// // to the destination type. There's not much point to this, though,
|
||||
// // because the result will be the same for any well-defined program
|
||||
// // anyway. If we really want to model this case perfectly, we'll need the
|
||||
// // extractor to tell us what the promoted type of the left operand would
|
||||
// // be.
|
||||
expr instanceof AssignRShiftExpr) then (
|
||||
result = getLeftOperand().getResultType()
|
||||
) else (
|
||||
// The right operand has already been converted to the type of the op.
|
||||
@@ -1623,8 +1586,8 @@ class TranslatedAssignOperation extends TranslatedAssignment {
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
isGLValue = false and
|
||||
Type resultType, boolean isLValue) {
|
||||
isLValue = false and
|
||||
(
|
||||
(
|
||||
tag = AssignOperationLoadTag() and
|
||||
@@ -1727,13 +1690,14 @@ class TranslatedAssignOperation extends TranslatedAssignment {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The IR translation of the allocation size argument passed to `operator new`
|
||||
* in a `new` expression.
|
||||
*
|
||||
* We have to synthesize this because not all `NewExpr` nodes have an allocator
|
||||
* call, and even the ones that do pass an `ErrorExpr` as the argument.
|
||||
*/
|
||||
// TODO: Fix allocations
|
||||
///**
|
||||
// * The IR translation of the allocation size argument passed to `operator new`
|
||||
// * in a `new` expression.
|
||||
// *
|
||||
// * We have to synthesize this because not all `NewExpr` nodes have an allocator
|
||||
// * call, and even the ones that do pass an `ErrorExpr` as the argument.
|
||||
// */
|
||||
//abstract class TranslatedAllocationSize extends TranslatedExpr,
|
||||
// TTranslatedAllocationSize {
|
||||
// override NewOrNewArrayExpr expr;
|
||||
@@ -1759,13 +1723,13 @@ class TranslatedAssignOperation extends TranslatedAssignment {
|
||||
// result.getAST() = newExpr
|
||||
//}
|
||||
|
||||
/**
|
||||
* The IR translation of a constant allocation size.
|
||||
*
|
||||
* The allocation size for a `new` expression is always a constant. The
|
||||
* allocation size for a `new[]` expression is a constant if the array extent
|
||||
* is a compile-time constant.
|
||||
*/
|
||||
///**
|
||||
// * The IR translation of a constant allocation size.
|
||||
// *
|
||||
// * The allocation size for a `new` expression is always a constant. The
|
||||
// * allocation size for a `new[]` expression is a constant if the array extent
|
||||
// * is a compile-time constant.
|
||||
// */
|
||||
//class TranslatedConstantAllocationSize extends TranslatedAllocationSize {
|
||||
// TranslatedConstantAllocationSize() {
|
||||
// not exists(expr.(NewArrayExpr).getExtent())
|
||||
@@ -1776,11 +1740,11 @@ class TranslatedAssignOperation extends TranslatedAssignment {
|
||||
// }
|
||||
//
|
||||
// override final predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
// Type resultType, boolean isGLValue) {
|
||||
// Type resultType, boolean ) {
|
||||
// tag = AllocationSizeTag() and
|
||||
// opcode instanceof Opcode::Constant and
|
||||
// resultType = expr.getAllocator().getParameter(0).getUnspecifiedType() and
|
||||
// isGLValue = false
|
||||
// = false
|
||||
// }
|
||||
//
|
||||
// override final Instruction getInstructionSuccessor(InstructionTag tag,
|
||||
@@ -1804,13 +1768,13 @@ class TranslatedAssignOperation extends TranslatedAssignment {
|
||||
// }
|
||||
//}
|
||||
|
||||
/**
|
||||
* The IR translation of a non-constant allocation size.
|
||||
*
|
||||
* This class is used for the allocation size of a `new[]` expression where the
|
||||
* array extent is not known at compile time. It performs the multiplication of
|
||||
* the extent by the element size.
|
||||
*/
|
||||
///**
|
||||
// * The IR translation of a non-constant allocation size.
|
||||
// *
|
||||
// * This class is used for the allocation size of a `new[]` expression where the
|
||||
// * array extent is not known at compile time. It performs the multiplication of
|
||||
// * the extent by the element size.
|
||||
// */
|
||||
//class TranslatedNonConstantAllocationSize extends TranslatedAllocationSize {
|
||||
// override NewArrayExpr expr;
|
||||
//
|
||||
@@ -1823,8 +1787,8 @@ class TranslatedAssignOperation extends TranslatedAssignment {
|
||||
// }
|
||||
//
|
||||
// override final predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
// Type resultType, boolean isGLValue) {
|
||||
// isGLValue = false and
|
||||
// Type resultType, boolean ) {
|
||||
// = false and
|
||||
// resultType = expr.getAllocator().getParameter(0).getUnspecifiedType() and
|
||||
// (
|
||||
// // Convert the extent to `size_t`, because the AST doesn't do this already.
|
||||
@@ -1888,10 +1852,10 @@ class TranslatedAssignOperation extends TranslatedAssignment {
|
||||
// }
|
||||
//}
|
||||
|
||||
/**
|
||||
* The IR translation of a call to `operator new` as part of a `new` or `new[]`
|
||||
* expression.
|
||||
*/
|
||||
///**
|
||||
// * The IR translation of a call to `operator new` as part of a `new` or `new[]`
|
||||
// * expression.
|
||||
// */
|
||||
//class TranslatedAllocatorCall extends TTranslatedAllocatorCall,
|
||||
// TranslatedDirectCall {
|
||||
// override NewOrNewArrayExpr expr;
|
||||
@@ -1957,10 +1921,11 @@ abstract class StructorCallContext extends TranslatedElement {
|
||||
abstract Instruction getReceiver();
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the IR translation of the destruction of a field from within
|
||||
* the destructor of the field's declaring class.
|
||||
*/
|
||||
// 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;
|
||||
@@ -1970,11 +1935,11 @@ abstract class StructorCallContext extends TranslatedElement {
|
||||
// }
|
||||
//
|
||||
// override final predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
// Type resultType, boolean isGLValue) {
|
||||
// Type resultType, boolean ) {
|
||||
// tag = OnlyInstructionTag() and
|
||||
// opcode instanceof Opcode::FieldAddress and
|
||||
// resultType = expr.getTarget().getUnspecifiedType() and
|
||||
// isGLValue = true
|
||||
// = true
|
||||
// }
|
||||
//
|
||||
// override final Instruction getInstructionSuccessor(InstructionTag tag,
|
||||
@@ -2032,7 +1997,7 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr,
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
Type resultType, boolean isLValue) {
|
||||
not resultIsVoid() and
|
||||
(
|
||||
(
|
||||
@@ -2043,7 +2008,7 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr,
|
||||
) and
|
||||
opcode instanceof Opcode::VariableAddress and
|
||||
resultType = getResultType() and
|
||||
isGLValue = true
|
||||
isLValue = true
|
||||
) or
|
||||
(
|
||||
(
|
||||
@@ -2052,13 +2017,13 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr,
|
||||
) and
|
||||
opcode instanceof Opcode::Store and
|
||||
resultType = getResultType() and
|
||||
isGLValue = false
|
||||
isLValue = false
|
||||
) or
|
||||
(
|
||||
tag = ConditionValueResultLoadTag() and
|
||||
opcode instanceof Opcode::Load and
|
||||
resultType = getResultType() and
|
||||
isGLValue = isResultGLValue()
|
||||
isLValue = isResultGLValue()
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -2240,11 +2205,11 @@ abstract class TranslatedThrowExpr extends TranslatedNonConstantExpr {
|
||||
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
Type resultType, boolean isLValue) {
|
||||
tag = ThrowTag() and
|
||||
opcode = getThrowOpcode() and
|
||||
resultType instanceof VoidType and
|
||||
isGLValue = false
|
||||
isLValue = false
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag,
|
||||
@@ -2280,12 +2245,12 @@ class TranslatedThrowValueExpr extends TranslatedThrowExpr,
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
TranslatedThrowExpr.super.hasInstruction(opcode, tag, resultType, isGLValue) or
|
||||
Type resultType, boolean isLValue) {
|
||||
TranslatedThrowExpr.super.hasInstruction(opcode, tag, resultType, isLValue) or
|
||||
tag = InitializerVariableAddressTag() and
|
||||
opcode instanceof Opcode::VariableAddress and
|
||||
resultType = getExceptionType() and
|
||||
isGLValue = true
|
||||
isLValue = true
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag,
|
||||
@@ -2357,9 +2322,10 @@ class TranslatedThrowValueExpr extends TranslatedThrowExpr,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* IR translation of a `throw` expression with no argument (e.g. `throw;`).
|
||||
*/
|
||||
// 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;
|
||||
//
|
||||
@@ -2380,65 +2346,66 @@ class TranslatedThrowValueExpr extends TranslatedThrowExpr,
|
||||
// }
|
||||
//}
|
||||
|
||||
/**
|
||||
* 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 isGLValue) {
|
||||
tag = OnlyInstructionTag() and
|
||||
opcode = getOpcode() and
|
||||
resultType = getResultType() and
|
||||
isGLValue = isResultGLValue()
|
||||
}
|
||||
|
||||
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: 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 = isResultGLValue()
|
||||
// }
|
||||
//
|
||||
// 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: BIG CHUNK TO CONVERT TO C#
|
||||
// TODO: See how and if we would adapt those to C#
|
||||
///**
|
||||
// * The IR translation of a `BuiltInVarArgsStart` expression.
|
||||
// */
|
||||
@@ -2496,11 +2463,11 @@ abstract class TranslatedBuiltInOperation extends TranslatedNonConstantExpr {
|
||||
// }
|
||||
//
|
||||
// override final predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
// Type resultType, boolean isGLValue) {
|
||||
// Type resultType, boolean ) {
|
||||
// tag = OnlyInstructionTag() and
|
||||
// opcode instanceof Opcode::Convert and
|
||||
// resultType = getResultType() and
|
||||
// isGLValue = false
|
||||
// = false
|
||||
// }
|
||||
//
|
||||
// override final Instruction getFirstInstruction() {
|
||||
@@ -2613,7 +2580,7 @@ abstract class TranslatedBuiltInOperation extends TranslatedNonConstantExpr {
|
||||
// }
|
||||
//
|
||||
// override predicate hasInstruction(Opcode opcode, InstructionTag tag, Type resultType,
|
||||
// boolean isGLValue) {
|
||||
// boolean ) {
|
||||
// none()
|
||||
// }
|
||||
//
|
||||
@@ -2672,24 +2639,24 @@ class TranslatedLambdaExpr extends TranslatedNonConstantExpr, InitializationCont
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, Type resultType,
|
||||
boolean isGLValue) {
|
||||
boolean isLValue) {
|
||||
(
|
||||
tag = InitializerVariableAddressTag() and
|
||||
opcode instanceof Opcode::VariableAddress and
|
||||
resultType = getResultType() and
|
||||
isGLValue = true
|
||||
isLValue = true
|
||||
) or
|
||||
(
|
||||
tag = InitializerStoreTag() and
|
||||
opcode instanceof Opcode::Uninitialized and
|
||||
resultType = getResultType() and
|
||||
isGLValue = false
|
||||
isLValue = false
|
||||
) or
|
||||
(
|
||||
tag = LoadTag() and
|
||||
opcode instanceof Opcode::Load and
|
||||
resultType = getResultType() and
|
||||
isGLValue = false
|
||||
isLValue = false
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2744,54 +2711,3 @@ class TranslatedLambdaExpr extends TranslatedNonConstantExpr, InitializationCont
|
||||
result = getTranslatedInitialization(expr.getChild(0))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The IR translation of `StmtExpr` (the GNU statement expression extension to C/C++), such as
|
||||
* ``` ({ doSomething(); a + b; })```
|
||||
*/
|
||||
// TODO: C++ SPECIFIC
|
||||
//class TranslatedStmtExpr extends TranslatedNonConstantExpr {
|
||||
// override StmtExpr expr;
|
||||
//
|
||||
// override final Instruction getFirstInstruction() {
|
||||
// result = getStmt().getFirstInstruction()
|
||||
// }
|
||||
//
|
||||
// override final TranslatedElement getChild(int id) {
|
||||
// id = 0 and result = getStmt()
|
||||
// }
|
||||
//
|
||||
// override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
// tag instanceof OnlyInstructionTag and
|
||||
// kind instanceof GotoEdge and
|
||||
// result = getParent().getChildSuccessor(this)
|
||||
// }
|
||||
//
|
||||
// override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
// child = getStmt() and
|
||||
// result = getInstruction(OnlyInstructionTag())
|
||||
// }
|
||||
//
|
||||
// override predicate hasInstruction(Opcode opcode, InstructionTag tag, Type resultType,
|
||||
// boolean isGLValue) {
|
||||
// opcode instanceof Opcode::CopyValue and
|
||||
// tag instanceof OnlyInstructionTag and
|
||||
// resultType = expr.getType() and
|
||||
// isGLValue = false
|
||||
// }
|
||||
//
|
||||
// override Instruction getResult() {
|
||||
// result = getInstruction(OnlyInstructionTag())
|
||||
// }
|
||||
//
|
||||
// override Instruction getInstructionOperand(InstructionTag tag,
|
||||
// OperandTag operandTag) {
|
||||
// tag instanceof OnlyInstructionTag and
|
||||
// operandTag instanceof UnaryOperandTag and
|
||||
// result = getTranslatedExpr(expr.getResultExpr().getFullyConverted()).getResult()
|
||||
// }
|
||||
//
|
||||
// TranslatedStmt getStmt() {
|
||||
// result = getTranslatedStmt(expr.getStmt())
|
||||
// }
|
||||
//}
|
||||
|
||||
@@ -10,7 +10,7 @@ private import TranslatedExpr
|
||||
private import TranslatedInitialization
|
||||
private import TranslatedStmt
|
||||
|
||||
//TODO: FIX CONSTRUCTORS AND DESTRUCTORS
|
||||
//TODO: Reason about constructors and destructors
|
||||
|
||||
/**
|
||||
* Gets the `TranslatedFunction` that represents function `callable`.
|
||||
@@ -145,43 +145,43 @@ class TranslatedFunction extends TranslatedElement,
|
||||
}
|
||||
|
||||
override final predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
Type resultType, boolean isLValue) {
|
||||
(
|
||||
(
|
||||
tag = EnterFunctionTag() and
|
||||
opcode instanceof Opcode::EnterFunction and
|
||||
resultType instanceof VoidType and
|
||||
isGLValue = false
|
||||
isLValue = false
|
||||
) or
|
||||
(
|
||||
tag = UnmodeledDefinitionTag() and
|
||||
opcode instanceof Opcode::UnmodeledDefinition and
|
||||
resultType instanceof VoidType and
|
||||
isGLValue = false
|
||||
isLValue = false
|
||||
) or
|
||||
(
|
||||
tag = AliasedDefinitionTag() and
|
||||
opcode instanceof Opcode::AliasedDefinition and
|
||||
resultType instanceof VoidType and
|
||||
isGLValue = false
|
||||
isLValue = false
|
||||
) or
|
||||
(
|
||||
tag = InitializeThisTag() and
|
||||
opcode instanceof Opcode::InitializeThis and
|
||||
resultType = getThisType() and
|
||||
isGLValue = true
|
||||
isLValue = true
|
||||
) or
|
||||
(
|
||||
tag = ReturnValueAddressTag() and
|
||||
opcode instanceof Opcode::VariableAddress and
|
||||
resultType = getReturnType() and
|
||||
not resultType instanceof VoidType and
|
||||
isGLValue = true
|
||||
isLValue = true
|
||||
) or
|
||||
(
|
||||
tag = ReturnTag() and
|
||||
resultType instanceof VoidType and
|
||||
isGLValue = false and
|
||||
isLValue = false and
|
||||
if getReturnType() instanceof VoidType then
|
||||
opcode instanceof Opcode::ReturnVoid
|
||||
else
|
||||
@@ -191,7 +191,7 @@ class TranslatedFunction extends TranslatedElement,
|
||||
tag = UnwindTag() and
|
||||
opcode instanceof Opcode::Unwind and
|
||||
resultType instanceof VoidType and
|
||||
isGLValue = false and
|
||||
isLValue = false and
|
||||
(
|
||||
// Only generate the `Unwind` instruction if there is any exception
|
||||
// handling present in the function.
|
||||
@@ -207,13 +207,13 @@ class TranslatedFunction extends TranslatedElement,
|
||||
tag = UnmodeledUseTag() and
|
||||
opcode instanceof Opcode::UnmodeledUse and
|
||||
resultType instanceof VoidType and
|
||||
isGLValue = false
|
||||
isLValue = false
|
||||
) or
|
||||
(
|
||||
tag = ExitFunctionTag() and
|
||||
opcode instanceof Opcode::ExitFunction and
|
||||
resultType instanceof VoidType and
|
||||
isGLValue = false
|
||||
isLValue = false
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -274,7 +274,6 @@ class TranslatedFunction extends TranslatedElement,
|
||||
* Gets the instruction to which control should flow after a `return`
|
||||
* statement. In C#, this should be the instruction which generates `VariableAddress[#return]`.
|
||||
*/
|
||||
// TODO: TIDY
|
||||
final Instruction getReturnSuccessorInstruction() {
|
||||
result = getInstruction(ReturnValueAddressTag())
|
||||
}
|
||||
@@ -306,12 +305,6 @@ class TranslatedFunction extends TranslatedElement,
|
||||
* Holds only if the function is an instance member function, constructor, or destructor.
|
||||
*/
|
||||
final Type getThisType() {
|
||||
// exists(MemberFunction mfunc |
|
||||
// mfunc = callable and
|
||||
// not mfunc.isStatic() and
|
||||
// result = mfunc.getDeclaringType()
|
||||
// )
|
||||
// TODO: ALL ARE MEMBERS
|
||||
result = callable.getDeclaringType()
|
||||
}
|
||||
|
||||
@@ -379,18 +372,18 @@ class TranslatedParameter extends TranslatedElement, TTranslatedParameter {
|
||||
}
|
||||
|
||||
override final predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
Type resultType, boolean isLValue) {
|
||||
(
|
||||
tag = InitializerVariableAddressTag() and
|
||||
opcode instanceof Opcode::VariableAddress and
|
||||
resultType = getVariableType(param) and
|
||||
isGLValue = true
|
||||
isLValue = true
|
||||
) or
|
||||
(
|
||||
tag = InitializerStoreTag() and
|
||||
opcode instanceof Opcode::InitializeParameter and
|
||||
resultType = getVariableType(param) and
|
||||
isGLValue = false
|
||||
isLValue = false
|
||||
)
|
||||
}
|
||||
|
||||
@@ -441,15 +434,13 @@ class TranslatedConstructorInitList extends TranslatedElement,
|
||||
result = callable
|
||||
}
|
||||
|
||||
// TODO: PROBABLY NOT RIGHT, LOOK INTO CONSTRUCTORS
|
||||
// TODO: Is this enough?
|
||||
override TranslatedElement getChild(int id) {
|
||||
result = getTranslatedExpr(callable.getChild(id))
|
||||
result = getTranslatedExpr(callable).getChild(id)
|
||||
// exists(MemberInitializer init |
|
||||
// // TODO: NEED TO BIND, WHY DOES CALLABLE GET CONVERTED TO METHOD?
|
||||
// init = callable.(Constructor).getInitializer().getRawArgument(id) and
|
||||
// result = getTranslatedConstructorFieldInitialization(init)
|
||||
// ) // or
|
||||
// TODO: IS THIS PART OF EXPLICIT OR IMPLICIT INIT IN C#?
|
||||
// exists(ConstructorBaseInit baseInit |
|
||||
// baseInit = callable.(Constructor).getInitializer().getRawArgument(id) and
|
||||
// result = getTranslatedConstructorBaseInit(baseInit)
|
||||
@@ -464,7 +455,7 @@ class TranslatedConstructorInitList extends TranslatedElement,
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
Type resultType, boolean isLValue) {
|
||||
none()
|
||||
}
|
||||
|
||||
@@ -501,6 +492,7 @@ 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`,
|
||||
@@ -508,7 +500,6 @@ getTranslatedDestructorDestructionList(Callable callable) {
|
||||
* destructors. Of course, only the instances for destructors can actually contain
|
||||
* destructions.
|
||||
*/
|
||||
// TODO: FIX DESTRUCTORS, TIDY
|
||||
class TranslatedDestructorDestructionList extends TranslatedElement,
|
||||
TTranslatedDestructorDestructionList {
|
||||
Callable callable;
|
||||
@@ -525,9 +516,9 @@ class TranslatedDestructorDestructionList extends TranslatedElement,
|
||||
result = callable
|
||||
}
|
||||
|
||||
// TODO: PROBABLY NOT RIGHT, LOOK INTO DESTRUCTORS
|
||||
// TODO: Is this enough?
|
||||
override TranslatedElement getChild(int id) {
|
||||
result = getTranslatedExpr(callable.getChild(id))
|
||||
result = getTranslatedExpr(callable).getChild(id)
|
||||
}
|
||||
|
||||
override Instruction getFirstInstruction() {
|
||||
@@ -538,7 +529,7 @@ class TranslatedDestructorDestructionList extends TranslatedElement,
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
Type resultType, boolean isLValue) {
|
||||
none()
|
||||
}
|
||||
|
||||
|
||||
@@ -7,8 +7,6 @@ private import TranslatedExpr
|
||||
private import TranslatedFunction
|
||||
private import semmle.code.csharp.ir.Util
|
||||
|
||||
// TODO: LOOK INTO GET ORDER FUNCTION AND SEE EXACTLY IF IT IS NEEDED
|
||||
|
||||
/**
|
||||
* Gets the `TranslatedInitialization` for the expression `expr`.
|
||||
*/
|
||||
@@ -97,7 +95,7 @@ abstract class TranslatedListInitialization extends TranslatedInitialization, In
|
||||
}
|
||||
|
||||
override final predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
Type resultType, boolean isLValue) {
|
||||
none()
|
||||
}
|
||||
|
||||
@@ -127,8 +125,7 @@ class TranslatedClassListInitialization extends TranslatedListInitialization
|
||||
exists(TranslatedFieldInitialization fieldInit |
|
||||
result = fieldInit and
|
||||
fieldInit = getTranslatedFieldInitialization(expr, _) and
|
||||
//fieldInit.getOrder() = id
|
||||
//TODO: DOES C# HAVE ORDERING FOR FIELD MEMBERS? DO WE NEED? YES, THE PRINTIR USES THEM
|
||||
fieldInit.getOrder() = id and
|
||||
id = 200
|
||||
)
|
||||
}
|
||||
@@ -183,11 +180,11 @@ class TranslatedSimpleDirectInitialization extends TranslatedDirectInitializatio
|
||||
not expr instanceof StringLiteral
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue) {
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue) {
|
||||
tag = InitializerStoreTag() and
|
||||
opcode instanceof Opcode::Store and
|
||||
resultType = getContext().getTargetType() and
|
||||
isGLValue = false
|
||||
isLValue = false
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
@@ -215,211 +212,10 @@ class TranslatedSimpleDirectInitialization extends TranslatedDirectInitializatio
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the IR translation of an initialization of an array from a string
|
||||
* literal.
|
||||
*/
|
||||
//class TranslatedStringLiteralInitialization extends TranslatedDirectInitialization {
|
||||
// override StringLiteral expr;
|
||||
//
|
||||
// override predicate hasInstruction(Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue) {
|
||||
// (
|
||||
// // Load the string literal to make it a prvalue of type `char[len]`
|
||||
// tag = InitializerLoadStringTag() and
|
||||
// opcode instanceof Opcode::Load and
|
||||
// resultType = getInitializer().getResultType() and
|
||||
// isGLValue = false
|
||||
// ) or
|
||||
// (
|
||||
// // Store the string into the target.
|
||||
// tag = InitializerStoreTag() and
|
||||
// opcode instanceof Opcode::Store and
|
||||
// resultType = getInitializer().getResultType() and
|
||||
// isGLValue = false
|
||||
// ) or
|
||||
// exists(int startIndex, int elementCount |
|
||||
// // If the initializer string isn't large enough to fill the target, then
|
||||
// // we have to generate another instruction sequence to store a constant
|
||||
// // zero into the remainder of the array.
|
||||
// zeroInitRange(startIndex, elementCount) and
|
||||
// (
|
||||
// (
|
||||
// // Create a constant zero whose size is the size of the remaining
|
||||
// // space in the target array.
|
||||
// tag = ZeroPadStringConstantTag() and
|
||||
// opcode instanceof Opcode::Constant and
|
||||
// resultType instanceof UnknownType and
|
||||
// isGLValue = false
|
||||
// ) or
|
||||
// (
|
||||
// // The index of the first element to be zero initialized.
|
||||
// tag = ZeroPadStringElementIndexTag() and
|
||||
// opcode instanceof Opcode::Constant and
|
||||
// resultType = getIntType() and
|
||||
// isGLValue = false
|
||||
// ) or
|
||||
// (
|
||||
// // Compute the address of the first element to be zero initialized.
|
||||
// tag = ZeroPadStringElementAddressTag() and
|
||||
// opcode instanceof Opcode::PointerAdd and
|
||||
// resultType = getElementType() and
|
||||
// isGLValue = true
|
||||
// ) or
|
||||
// (
|
||||
// // Store the constant zero into the remainder of the string.
|
||||
// tag = ZeroPadStringStoreTag() and
|
||||
// opcode instanceof Opcode::Store and
|
||||
// resultType instanceof UnknownType and
|
||||
// isGLValue = false
|
||||
// )
|
||||
// )
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
// kind instanceof GotoEdge and
|
||||
// (
|
||||
// (
|
||||
// tag = InitializerLoadStringTag() and
|
||||
// result = getInstruction(InitializerStoreTag())
|
||||
// ) or
|
||||
// if zeroInitRange(_, _) then (
|
||||
// (
|
||||
// tag = InitializerStoreTag() and
|
||||
// result = getInstruction(ZeroPadStringConstantTag())
|
||||
// ) or
|
||||
// (
|
||||
// tag = ZeroPadStringConstantTag() and
|
||||
// result = getInstruction(ZeroPadStringElementIndexTag())
|
||||
// ) or
|
||||
// (
|
||||
// tag = ZeroPadStringElementIndexTag() and
|
||||
// result = getInstruction(ZeroPadStringElementAddressTag())
|
||||
// ) or
|
||||
// (
|
||||
// tag = ZeroPadStringElementAddressTag() and
|
||||
// result = getInstruction(ZeroPadStringStoreTag())
|
||||
// ) or
|
||||
// (
|
||||
// tag = ZeroPadStringStoreTag() and
|
||||
// result = getParent().getChildSuccessor(this)
|
||||
// )
|
||||
// )
|
||||
// else (
|
||||
// tag = InitializerStoreTag() and
|
||||
// result = getParent().getChildSuccessor(this)
|
||||
// )
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
// child = getInitializer() and result = getInstruction(InitializerLoadStringTag())
|
||||
// }
|
||||
//
|
||||
// override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
// (
|
||||
// tag = InitializerLoadStringTag() and
|
||||
// (
|
||||
// (
|
||||
// operandTag instanceof AddressOperandTag and
|
||||
// result = getInitializer().getResult()
|
||||
// ) or
|
||||
// (
|
||||
// operandTag instanceof LoadOperandTag and
|
||||
// result = getEnclosingFunction().getUnmodeledDefinitionInstruction()
|
||||
// )
|
||||
// )
|
||||
// ) or
|
||||
// (
|
||||
// tag = InitializerStoreTag() and
|
||||
// (
|
||||
// (
|
||||
// operandTag instanceof AddressOperandTag and
|
||||
// result = getContext().getTargetAddress()
|
||||
// ) or
|
||||
// (
|
||||
// operandTag instanceof StoreValueOperandTag and
|
||||
// result = getInstruction(InitializerLoadStringTag())
|
||||
// )
|
||||
// )
|
||||
// ) or
|
||||
// (
|
||||
// tag = ZeroPadStringElementAddressTag() and
|
||||
// (
|
||||
// (
|
||||
// operandTag instanceof LeftOperandTag and
|
||||
// result = getContext().getTargetAddress()
|
||||
// ) or
|
||||
// (
|
||||
// operandTag instanceof RightOperandTag and
|
||||
// result = getInstruction(ZeroPadStringElementIndexTag())
|
||||
// )
|
||||
// )
|
||||
// ) or
|
||||
// (
|
||||
// tag = ZeroPadStringStoreTag() and
|
||||
// (
|
||||
// (
|
||||
// operandTag instanceof AddressOperandTag and
|
||||
// result = getInstruction(ZeroPadStringElementAddressTag())
|
||||
// ) or
|
||||
// (
|
||||
// operandTag instanceof StoreValueOperandTag and
|
||||
// result = getInstruction(ZeroPadStringConstantTag())
|
||||
// )
|
||||
// )
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// override string getInstructionConstantValue(InstructionTag tag) {
|
||||
// exists(int startIndex |
|
||||
// zeroInitRange(startIndex, _) and
|
||||
// (
|
||||
// (
|
||||
// tag = ZeroPadStringConstantTag() and
|
||||
// result = "0"
|
||||
// ) or
|
||||
// (
|
||||
// tag = ZeroPadStringElementIndexTag() and
|
||||
// result = startIndex.toString()
|
||||
// )
|
||||
// )
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// override int getInstructionResultSize(InstructionTag tag) {
|
||||
// exists(int elementCount |
|
||||
// zeroInitRange(_, elementCount) and
|
||||
// (
|
||||
// tag = ZeroPadStringConstantTag() or
|
||||
// tag = ZeroPadStringStoreTag()
|
||||
// ) and
|
||||
// result = 8 //elementCount * getElementType().getSize() TODO: FIX SIZES
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// private Type getElementType() {
|
||||
// result = getContext().getTargetType().(ArrayType).getElementType()
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Holds if the `elementCount` array elements starting at `startIndex` must be
|
||||
// * zero initialized.
|
||||
// */
|
||||
// private predicate zeroInitRange(int startIndex, int elementCount) {
|
||||
// exists(int targetCount |
|
||||
// startIndex = expr.getType().(ArrayType).getArraySize() and
|
||||
// targetCount = getContext().getTargetType().(ArrayType).getArraySize() and
|
||||
// elementCount = targetCount - startIndex and
|
||||
// elementCount > 0
|
||||
// )
|
||||
// }
|
||||
//}
|
||||
|
||||
class TranslatedConstructorInitialization extends TranslatedDirectInitialization, StructorCallContext {
|
||||
override ObjectCreation expr;
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue) {
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue) {
|
||||
none()
|
||||
}
|
||||
|
||||
@@ -480,20 +276,22 @@ abstract class TranslatedFieldInitialization extends TranslatedElement {
|
||||
* Gets the zero-based index describing the order in which this field is to be
|
||||
* initialized relative to the other fields in the class.
|
||||
*/
|
||||
// final int getOrder() {
|
||||
// TODO: Fix getOrder here
|
||||
final int getOrder() {
|
||||
result = 0
|
||||
// exists(Class cls, int memberIndex |
|
||||
// this = cls.getCanonicalMember(memberIndex) and
|
||||
// memberIndex = rank[result + 1](int index |
|
||||
// cls.getCanonicalMember(index).(Field).isInitializable()
|
||||
// )
|
||||
// )
|
||||
// }
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue) {
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue) {
|
||||
tag = getFieldAddressTag() and
|
||||
opcode instanceof Opcode::FieldAddress and
|
||||
resultType = field.getType() and
|
||||
isGLValue = true
|
||||
isLValue = true
|
||||
}
|
||||
|
||||
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
@@ -570,19 +368,19 @@ class TranslatedFieldValueInitialization extends TranslatedFieldInitialization,
|
||||
this = TTranslatedFieldValueInitialization(ast, field)
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue) {
|
||||
TranslatedFieldInitialization.super.hasInstruction(opcode, tag, resultType, isGLValue) or
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue) {
|
||||
TranslatedFieldInitialization.super.hasInstruction(opcode, tag, resultType, isLValue) or
|
||||
(
|
||||
tag = getFieldDefaultValueTag() and
|
||||
opcode instanceof Opcode::Constant and
|
||||
resultType = field.getType() and
|
||||
isGLValue = false
|
||||
isLValue = false
|
||||
) or
|
||||
(
|
||||
tag = getFieldDefaultValueStoreTag() and
|
||||
opcode instanceof Opcode::Store and
|
||||
resultType = field.getType() and
|
||||
isGLValue = false
|
||||
isLValue = false
|
||||
)
|
||||
}
|
||||
|
||||
@@ -666,18 +464,18 @@ abstract class TranslatedElementInitialization extends TranslatedElement {
|
||||
result = getInstruction(getElementIndexTag())
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue) {
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue) {
|
||||
(
|
||||
tag = getElementIndexTag() and
|
||||
opcode instanceof Opcode::Constant and
|
||||
resultType = getIntType() and
|
||||
isGLValue = false
|
||||
isLValue = false
|
||||
) or
|
||||
(
|
||||
tag = getElementAddressTag() and
|
||||
opcode instanceof Opcode::PointerAdd and
|
||||
resultType = getElementType() and
|
||||
isGLValue = true
|
||||
isLValue = true
|
||||
)
|
||||
}
|
||||
|
||||
@@ -786,19 +584,19 @@ class TranslatedElementValueInitialization extends TranslatedElementInitializati
|
||||
elementCount)
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue) {
|
||||
TranslatedElementInitialization.super.hasInstruction(opcode, tag, resultType, isGLValue) or
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue) {
|
||||
TranslatedElementInitialization.super.hasInstruction(opcode, tag, resultType, isLValue) or
|
||||
(
|
||||
tag = getElementDefaultValueTag() and
|
||||
opcode instanceof Opcode::Constant and
|
||||
resultType = getDefaultValueType() and
|
||||
isGLValue = false
|
||||
isLValue = false
|
||||
) or
|
||||
(
|
||||
tag = getElementDefaultValueStoreTag() and
|
||||
opcode instanceof Opcode::Store and
|
||||
resultType = getDefaultValueType() and
|
||||
isGLValue = false
|
||||
isLValue = false
|
||||
)
|
||||
}
|
||||
|
||||
@@ -837,7 +635,8 @@ class TranslatedElementValueInitialization extends TranslatedElementInitializati
|
||||
tag = getElementDefaultValueTag() or
|
||||
tag = getElementDefaultValueStoreTag()
|
||||
) and
|
||||
result = 8 //elementCount * getElementType().getSize() TODO: FIX SIZES
|
||||
// TODO: Memory model C#
|
||||
result = 8 //elementCount * getElementType().getSize()
|
||||
}
|
||||
|
||||
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
@@ -920,11 +719,11 @@ abstract class TranslatedBaseStructorCall extends TranslatedStructorCallFromStru
|
||||
result = getInstruction(OnlyInstructionTag())
|
||||
}
|
||||
|
||||
override final predicate hasInstruction(Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue) {
|
||||
override final predicate hasInstruction(Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue) {
|
||||
tag = OnlyInstructionTag() and
|
||||
opcode instanceof Opcode::ConvertToBase and
|
||||
resultType = call.getTarget().getDeclaringType() and
|
||||
isGLValue = true
|
||||
isLValue = true
|
||||
}
|
||||
|
||||
override final Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
@@ -978,7 +777,7 @@ abstract class TranslatedBaseStructorCall extends TranslatedStructorCallFromStru
|
||||
// result = getStructorCall().getFirstInstruction()
|
||||
// }
|
||||
//
|
||||
// override final predicate hasInstruction(Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue) {
|
||||
// override final predicate hasInstruction(Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue) {
|
||||
// none()
|
||||
// }
|
||||
//
|
||||
|
||||
@@ -49,11 +49,11 @@ class TranslatedEmptyStmt extends TranslatedStmt {
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
Type resultType, boolean isLValue) {
|
||||
tag = OnlyInstructionTag() and
|
||||
opcode instanceof Opcode::NoOp and
|
||||
resultType instanceof VoidType and
|
||||
isGLValue = false
|
||||
isLValue = false
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag,
|
||||
@@ -76,7 +76,7 @@ class TranslatedDeclStmt extends TranslatedStmt {
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
Type resultType, boolean isLValue) {
|
||||
none()
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ class TranslatedExprStmt extends TranslatedStmt {
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
Type resultType, boolean isLValue) {
|
||||
none()
|
||||
}
|
||||
|
||||
@@ -162,11 +162,11 @@ class TranslatedReturnValueStmt extends TranslatedReturnStmt,
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
Type resultType, boolean isLValue) {
|
||||
tag = InitializerVariableAddressTag() and
|
||||
opcode instanceof Opcode::VariableAddress and
|
||||
resultType = getEnclosingFunction().getReturnVariable().getType() and
|
||||
isGLValue = true
|
||||
isLValue = true
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag,
|
||||
@@ -214,11 +214,11 @@ class TranslatedReturnVoidStmt extends TranslatedReturnStmt {
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
Type resultType, boolean isLValue) {
|
||||
tag = OnlyInstructionTag() and
|
||||
opcode instanceof Opcode::NoOp and
|
||||
resultType instanceof VoidType and
|
||||
isGLValue = false
|
||||
isLValue = false
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag,
|
||||
@@ -245,7 +245,7 @@ class TranslatedTryStmt extends TranslatedStmt {
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
Type resultType, boolean isLValue) {
|
||||
none()
|
||||
}
|
||||
|
||||
@@ -299,12 +299,12 @@ class TranslatedBlock extends TranslatedStmt {
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
Type resultType, boolean isLValue) {
|
||||
isEmpty() and
|
||||
opcode instanceof Opcode::NoOp and
|
||||
tag = OnlyInstructionTag() and
|
||||
resultType instanceof VoidType and
|
||||
isGLValue = false
|
||||
isLValue = false
|
||||
}
|
||||
|
||||
override Instruction getFirstInstruction() {
|
||||
@@ -373,22 +373,22 @@ abstract class TranslatedHandler extends TranslatedStmt {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The IR translation of a C++ `catch` block that catches an exception with a
|
||||
* specific type (e.g. `catch (const std::exception&)`).
|
||||
*/
|
||||
// TODO: FIX THE SPECIFIC CATCH
|
||||
// TODO: Fix specific catch
|
||||
///**
|
||||
// * The IR translation of a C++ `catch` block that catches an exception with a
|
||||
// * specific type (e.g. `catch (const std::exception&)`).
|
||||
// */
|
||||
//class TranslatedCatchByTypeHandler extends TranslatedHandler {
|
||||
// TranslatedCatchByTypeHandler() {
|
||||
// stmt instanceof SpecificCatchClause
|
||||
// }
|
||||
//
|
||||
// override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
// Type resultType, boolean isGLValue) {
|
||||
// Type resultType, boolean isLValue) {
|
||||
// tag = CatchTag() and
|
||||
// opcode instanceof Opcode::CatchByType and
|
||||
// resultType instanceof VoidType and
|
||||
// isGLValue = false
|
||||
// isLValue = false
|
||||
// }
|
||||
//
|
||||
// override TranslatedElement getChild(int id) {
|
||||
@@ -421,9 +421,10 @@ abstract class TranslatedHandler extends TranslatedStmt {
|
||||
// result = stmt.(SpecificCatchClause).getVariable().getType()
|
||||
// }
|
||||
//
|
||||
// private TranslatedParameter getParameter() {
|
||||
// result = getTranslatedParameter(stmt.(SpecificCatchClause).getVariable())
|
||||
// }
|
||||
//// TODO: Fix the getParameter() method (C++ sees the catch var as a parameter, C# sees it as a var)
|
||||
//// private TranslatedParameter getParameter() {
|
||||
//// result = getTranslatedParameter(stmt.(SpecificCatchClause).getVariable())
|
||||
//// }
|
||||
//}
|
||||
|
||||
/**
|
||||
@@ -435,11 +436,11 @@ class TranslatedCatchAnyHandler extends TranslatedHandler {
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
Type resultType, boolean isLValue) {
|
||||
tag = CatchTag() and
|
||||
opcode instanceof Opcode::CatchAny and
|
||||
resultType instanceof VoidType and
|
||||
isGLValue = false
|
||||
isLValue = false
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag,
|
||||
@@ -504,7 +505,7 @@ class TranslatedIfStmt extends TranslatedStmt, ConditionContext {
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
Type resultType, boolean isLValue) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
@@ -537,7 +538,7 @@ abstract class TranslatedLoop extends TranslatedStmt, ConditionContext {
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
Type resultType, boolean isLValue) {
|
||||
none()
|
||||
}
|
||||
|
||||
@@ -632,106 +633,6 @@ class TranslatedForStmt extends TranslatedLoop {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The IR translation of a range-based `for` loop.
|
||||
* Note that this class does not extend `TranslatedLoop`. This is because the "body" of the
|
||||
* range-based `for` loop consists of the per-iteration variable declaration followed by the
|
||||
* user-written body statement. It is easier to handle the control flow of the loop separately,
|
||||
* rather than synthesizing a single body or complicating the interface of `TranslatedLoop`.
|
||||
*/
|
||||
// TODO: PROBABLY NEEDS TO BE REPLACED BY C#'S FOREACH
|
||||
//class TranslatedRangeBasedForStmt extends TranslatedStmt, ConditionContext {
|
||||
// override RangeBasedForStmt stmt;
|
||||
//
|
||||
// override TranslatedElement getChild(int id) {
|
||||
// id = 0 and result = getRangeVariableDeclaration() or
|
||||
// id = 1 and result = getBeginVariableDeclaration() or
|
||||
// id = 2 and result = getEndVariableDeclaration() or
|
||||
// id = 3 and result = getCondition() or
|
||||
// id = 4 and result = getUpdate() or
|
||||
// id = 5 and result = getVariableDeclaration() or
|
||||
// id = 6 and result = getBody()
|
||||
// }
|
||||
//
|
||||
// override Instruction getFirstInstruction() {
|
||||
// result = getRangeVariableDeclaration().getFirstInstruction()
|
||||
// }
|
||||
//
|
||||
// override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
// (
|
||||
// child = getRangeVariableDeclaration() and
|
||||
// result = getBeginVariableDeclaration().getFirstInstruction()
|
||||
// ) or
|
||||
// (
|
||||
// child = getBeginVariableDeclaration() and
|
||||
// result = getEndVariableDeclaration().getFirstInstruction()
|
||||
// ) or
|
||||
// (
|
||||
// child = getEndVariableDeclaration() and
|
||||
// result = getCondition().getFirstInstruction()
|
||||
// ) or
|
||||
// (
|
||||
// child = getVariableDeclaration() and
|
||||
// result = getBody().getFirstInstruction()
|
||||
// ) or
|
||||
// (
|
||||
// child = getBody() and
|
||||
// result = getUpdate().getFirstInstruction()
|
||||
// ) or
|
||||
// (
|
||||
// child = getUpdate() and
|
||||
// result = getCondition().getFirstInstruction()
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// override predicate hasInstruction(Opcode opcode, InstructionTag tag, Type resultType,
|
||||
// boolean isGLValue) {
|
||||
// none()
|
||||
// }
|
||||
//
|
||||
// override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
// none()
|
||||
// }
|
||||
//
|
||||
// override Instruction getChildTrueSuccessor(TranslatedCondition child) {
|
||||
// child = getCondition() and result = getVariableDeclaration().getFirstInstruction()
|
||||
// }
|
||||
//
|
||||
// override Instruction getChildFalseSuccessor(TranslatedCondition child) {
|
||||
// child = getCondition() and result = getParent().getChildSuccessor(this)
|
||||
// }
|
||||
//
|
||||
// private TranslatedRangeBasedForVariableDeclaration getRangeVariableDeclaration() {
|
||||
// result = getTranslatedRangeBasedForVariableDeclaration(stmt.getRangeVariable())
|
||||
// }
|
||||
//
|
||||
// private TranslatedRangeBasedForVariableDeclaration getBeginVariableDeclaration() {
|
||||
// result = getTranslatedRangeBasedForVariableDeclaration(stmt.getBeginVariable())
|
||||
// }
|
||||
//
|
||||
// private TranslatedRangeBasedForVariableDeclaration getEndVariableDeclaration() {
|
||||
// result = getTranslatedRangeBasedForVariableDeclaration(stmt.getEndVariable())
|
||||
// }
|
||||
//
|
||||
// // Public for getInstructionBackEdgeSuccessor
|
||||
// final TranslatedCondition getCondition() {
|
||||
// result = getTranslatedCondition(stmt.getCondition().getFullyConverted())
|
||||
// }
|
||||
//
|
||||
// // Public for getInstructionBackEdgeSuccessor
|
||||
// final TranslatedExpr getUpdate() {
|
||||
// result = getTranslatedExpr(stmt.getUpdate().getFullyConverted())
|
||||
// }
|
||||
//
|
||||
// private TranslatedRangeBasedForVariableDeclaration getVariableDeclaration() {
|
||||
// result = getTranslatedRangeBasedForVariableDeclaration(stmt.getVariable())
|
||||
// }
|
||||
//
|
||||
// private TranslatedStmt getBody() {
|
||||
// result = getTranslatedStmt(stmt.getStmt())
|
||||
// }
|
||||
//}
|
||||
|
||||
class TranslatedJumpStmt extends TranslatedStmt {
|
||||
override JumpStmt stmt;
|
||||
|
||||
@@ -750,11 +651,11 @@ class TranslatedJumpStmt extends TranslatedStmt {
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
Type resultType, boolean isLValue) {
|
||||
tag = OnlyInstructionTag() and
|
||||
opcode instanceof Opcode::NoOp and
|
||||
resultType instanceof VoidType and
|
||||
isGLValue = false
|
||||
isLValue = false
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag,
|
||||
@@ -770,7 +671,7 @@ class TranslatedJumpStmt extends TranslatedStmt {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: DEAL WITH SWITCH STMTS
|
||||
// TODO: Fix Switch stmts
|
||||
//class TranslatedSwitchStmt extends TranslatedStmt {
|
||||
// override SwitchStmt stmt;
|
||||
//
|
||||
@@ -792,11 +693,11 @@ class TranslatedJumpStmt extends TranslatedStmt {
|
||||
// }
|
||||
//
|
||||
// override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
// Type resultType, boolean isGLValue) {
|
||||
// Type resultType, boolean isLValue) {
|
||||
// tag = SwitchBranchTag() and
|
||||
// opcode instanceof Opcode::Switch and
|
||||
// resultType instanceof VoidType and
|
||||
// isGLValue = false
|
||||
// isLValue = false
|
||||
// }
|
||||
//
|
||||
// override Instruction getInstructionOperand(InstructionTag tag,
|
||||
@@ -820,83 +721,4 @@ class TranslatedJumpStmt extends TranslatedStmt {
|
||||
// child = getExpr() and result = getInstruction(SwitchBranchTag()) or
|
||||
// child = getBody() and result = getParent().getChildSuccessor(this)
|
||||
// }
|
||||
//}
|
||||
|
||||
// TODO: ASM SHOULD NOT BE HERE
|
||||
//class TranslatedAsmStmt extends TranslatedStmt {
|
||||
// override AsmStmt stmt;
|
||||
//
|
||||
// override TranslatedElement getChild(int id) {
|
||||
// none()
|
||||
// }
|
||||
//
|
||||
// override Instruction getFirstInstruction() {
|
||||
// if exists(stmt.getChild(0))
|
||||
// then result = getInstruction(AsmInputTag(0))
|
||||
// else result = getInstruction(AsmTag())
|
||||
// }
|
||||
//
|
||||
// override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
// Type resultType, boolean isGLValue) {
|
||||
// tag = AsmTag() and
|
||||
// opcode instanceof Opcode::InlineAsm and
|
||||
// resultType instanceof UnknownType and
|
||||
// isGLValue = false
|
||||
// or
|
||||
// exists(int index, VariableAccess va |
|
||||
// tag = AsmInputTag(index) and
|
||||
// stmt.getChild(index) = va and
|
||||
// opcode instanceof Opcode::VariableAddress and
|
||||
// resultType = va.getType().getUnspecifiedType() and
|
||||
// isGLValue = true
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// override IRVariable getInstructionVariable(InstructionTag tag) {
|
||||
// exists(int index |
|
||||
// tag = AsmInputTag(index) and
|
||||
// result = getIRUserVariable(stmt.getEnclosingFunction(), stmt.getChild(index).(VariableAccess).getTarget())
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// override Instruction getInstructionOperand(InstructionTag tag,
|
||||
// OperandTag operandTag) {
|
||||
// tag = AsmTag() and
|
||||
// operandTag instanceof SideEffectOperandTag and
|
||||
// result = getTranslatedFunction(stmt.getEnclosingFunction()).getUnmodeledDefinitionInstruction()
|
||||
// or
|
||||
// exists(int index |
|
||||
// tag = AsmTag() and
|
||||
// operandTag = asmOperand(index) and
|
||||
// result = getInstruction(AsmInputTag(index))
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// override final Type getInstructionOperandType(InstructionTag tag,
|
||||
// TypedOperandTag operandTag) {
|
||||
// tag = AsmTag() and
|
||||
// operandTag instanceof SideEffectOperandTag and
|
||||
// result instanceof UnknownType
|
||||
// }
|
||||
//
|
||||
// override Instruction getInstructionSuccessor(InstructionTag tag,
|
||||
// EdgeKind kind) {
|
||||
// tag = AsmTag() and
|
||||
// result = getParent().getChildSuccessor(this) and
|
||||
// kind instanceof GotoEdge
|
||||
// or
|
||||
// exists(int index |
|
||||
// tag = AsmInputTag(index) and
|
||||
// kind instanceof GotoEdge and
|
||||
// if exists(stmt.getChild(index + 1))
|
||||
// then
|
||||
// result = getInstruction(AsmInputTag(index + 1))
|
||||
// else
|
||||
// result = getInstruction(AsmTag())
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
// none()
|
||||
// }
|
||||
//}
|
||||
//}
|
||||
@@ -8,9 +8,8 @@ import csharp
|
||||
* becomes a pointer to the element type of the array. If the specified type
|
||||
* is not subject to pointer decay, this predicate does not hold.
|
||||
*/
|
||||
// TODO: Only pointer to array decay in C#?
|
||||
private Type getDecayedType(Type type) {
|
||||
// TODO: CHECK WHAT EXACTLY CAN BE DECAYED IN C#
|
||||
// result.(FunctionPointerType).getBaseType() = type.(RoutineType) or
|
||||
result.(PointerType).getReferentType() = type.(ArrayType).getElementType()
|
||||
}
|
||||
|
||||
@@ -21,14 +20,14 @@ private Type getDecayedType(Type type) {
|
||||
*/
|
||||
Type getVariableType(Variable v) {
|
||||
exists(Type declaredType |
|
||||
declaredType = v.getType() and // TODO: IS getUnspecifiedType RELEVANT HERE?
|
||||
declaredType = v.getType() and
|
||||
if v instanceof Parameter then (
|
||||
result = getDecayedType(declaredType) or
|
||||
not exists(getDecayedType(declaredType)) and result = declaredType
|
||||
)
|
||||
else if declaredType instanceof ArrayType /*TODO: DO WE NEED TO CHECK FOR ARRAY SIZES? PROBS NOT, ILLEGAL
|
||||
* FOR AN ARRAY TO NOT HAVE SIZE
|
||||
* and not declaredType.(ArrayType).hasArraySize() */ then (
|
||||
else if declaredType instanceof ArrayType then (
|
||||
// TODO: Arrays have a declared dimension in C#, so this should not be needed
|
||||
// and not declaredType.(ArrayType).hasArraySize()
|
||||
result = v.getInitializer().getType() or
|
||||
not exists(v.getInitializer()) and result = declaredType
|
||||
)
|
||||
|
||||
@@ -22,18 +22,10 @@ private newtype TOperandTag =
|
||||
TCallTargetOperand() or
|
||||
TThisArgumentOperand() or
|
||||
TPositionalArgumentOperand(int argIndex) {
|
||||
argIndex in [0..getMaxCallArgIndex()] /* TODO: WHAT IS THE PURPOSE OF BUILTINOPS HERE? or
|
||||
exists(BuiltInOperation op |
|
||||
exists(op.getChild(argIndex))
|
||||
) */
|
||||
argIndex in [0..getMaxCallArgIndex()]
|
||||
} or
|
||||
TChiTotalOperand() or
|
||||
TChiPartialOperand() // or TODO: NO ASM INSTR FOR C#, PROBS SAFE TO COMMENT
|
||||
// TAsmOperand(int index) {
|
||||
// exists(AsmStmt asm |
|
||||
// exists(asm.getChild(index))
|
||||
// )
|
||||
// }
|
||||
TChiPartialOperand()
|
||||
|
||||
/**
|
||||
* Identifies the kind of operand on an instruction. Each `Instruction` has at
|
||||
@@ -367,28 +359,3 @@ class ChiPartialOperandTag extends MemoryOperandTag, TChiPartialOperand {
|
||||
ChiPartialOperandTag chiPartialOperand() {
|
||||
result = TChiPartialOperand()
|
||||
}
|
||||
|
||||
// TODO: NO ASM INSTR FOR C#, PROBS SAFE TO COMMENT
|
||||
//class AsmOperandTag extends RegisterOperandTag, TAsmOperand {
|
||||
// int index;
|
||||
//
|
||||
// AsmOperandTag() {
|
||||
// this = TAsmOperand(index)
|
||||
// }
|
||||
//
|
||||
// override final string toString() {
|
||||
// result = "AsmOperand(" + index + ")"
|
||||
// }
|
||||
//
|
||||
// override final int getSortOrder() {
|
||||
// result = 15 + index
|
||||
// }
|
||||
//
|
||||
// override final string getLabel() {
|
||||
// result = index.toString() + ":"
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//AsmOperandTag asmOperand(int index) {
|
||||
// result = TAsmOperand(index)
|
||||
//}
|
||||
@@ -5,11 +5,11 @@ private import semmle.code.csharp.ir.Util
|
||||
|
||||
newtype TIRVariable =
|
||||
TIRAutomaticUserVariable(LocalScopeVariable var, Callable callable) {
|
||||
Construction::functionHasIR(callable) and
|
||||
Construction::callableHasIR(callable) and
|
||||
var.getCallable() = callable
|
||||
} or
|
||||
TIRStaticUserVariable(Variable var, Callable callable) {
|
||||
Construction::functionHasIR(callable) and
|
||||
Construction::callableHasIR(callable) and
|
||||
// TODO: CHECK FOR CORRESPONDENCE HERE
|
||||
// (
|
||||
// var instanceof GlobalOrNamespaceVariable or
|
||||
@@ -20,7 +20,7 @@ newtype TIRVariable =
|
||||
access.getEnclosingCallable() = callable
|
||||
)
|
||||
} or
|
||||
TIRTempVariable(Callable callable, Locatable ast, TempVariableTag tag, Type type) { // TODO: LOOK AT LOCATABLE FOR C#
|
||||
TIRTempVariable(Callable callable, Locatable ast, TempVariableTag tag, Type type) {
|
||||
Construction::hasTempVariable(callable, ast, tag, type)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
ir.cs:
|
||||
# 4| bar
|
||||
# 4| Block 0
|
||||
# 4| v0_0(Void) = EnterFunction :
|
||||
# 4| v0_1(Void) = AliasedDefinition :
|
||||
# 4| v0_2(Void) = UnmodeledDefinition :
|
||||
# 4| r0_3(glval<foo>) = InitializeThis :
|
||||
# 5| r0_4(glval<Int32>) = VariableAddress[#return] :
|
||||
# 5| r0_5(Int32) = Constant[0] :
|
||||
# 5| mu0_6(Int32) = Store : &:r0_4, r0_5
|
||||
# 4| r0_7(glval<Int32>) = VariableAddress[#return] :
|
||||
# 4| v0_8(Void) = ReturnValue : &:r0_7, ~v0_2
|
||||
# 4| v0_9(Void) = UnmodeledUse : mu*
|
||||
# 4| v0_10(Void) = ExitFunction :
|
||||
# 4| v0_0(Void) = EnterFunction :
|
||||
# 4| v0_1(Void) = AliasedDefinition :
|
||||
# 4| v0_2(Void) = UnmodeledDefinition :
|
||||
# 4| r0_3(lval<foo>) = InitializeThis :
|
||||
# 5| r0_4(lval<Int32>) = VariableAddress[#return] :
|
||||
# 5| r0_5(Int32) = Constant[0] :
|
||||
# 5| mu0_6(Int32) = Store : &:r0_4, r0_5
|
||||
# 4| r0_7(lval<Int32>) = VariableAddress[#return] :
|
||||
# 4| v0_8(Void) = ReturnValue : &:r0_7, ~v0_2
|
||||
# 4| v0_9(Void) = UnmodeledUse : mu*
|
||||
# 4| v0_10(Void) = ExitFunction :
|
||||
|
||||
Reference in New Issue
Block a user