mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
C#: Delete Dotnet and CIL library code.
This commit is contained in:
@@ -1,5 +0,0 @@
|
||||
/**
|
||||
* The default QL library for modeling the Common Intermediate Language (CIL).
|
||||
*/
|
||||
|
||||
import semmle.code.cil.CIL as CIL
|
||||
@@ -1,5 +0,0 @@
|
||||
/**
|
||||
* The default QL library for modeling .NET definitions for both C# and CIL code.
|
||||
*/
|
||||
|
||||
deprecated import semmle.code.dotnet.DotNet as DotNet
|
||||
@@ -1,98 +0,0 @@
|
||||
/**
|
||||
* Provides classes for accesses.
|
||||
*
|
||||
* An access is any read or write of a variable.
|
||||
*/
|
||||
|
||||
private import CIL
|
||||
|
||||
/** An instruction that accesses a variable. */
|
||||
deprecated class Access extends Instruction, @cil_access {
|
||||
/** Gets the declaration referenced by this instruction. */
|
||||
Variable getTarget() { cil_access(this, result) }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that accesses a variable.
|
||||
* This class is provided for consistency with the C# data model.
|
||||
*/
|
||||
deprecated class VariableAccess extends Access, @cil_access { }
|
||||
|
||||
/** An instruction that reads a variable. */
|
||||
deprecated class ReadAccess extends VariableAccess, Expr, @cil_read_access {
|
||||
override Type getType() { result = this.getTarget().getType() }
|
||||
}
|
||||
|
||||
/** An instruction yielding an address. */
|
||||
deprecated class ReadRef extends Expr, @cil_read_ref { }
|
||||
|
||||
/** An instruction that reads the address of a variable. */
|
||||
deprecated class ReadRefAccess extends ReadAccess, ReadRef { }
|
||||
|
||||
/** An instruction that writes a variable. */
|
||||
deprecated class WriteAccess extends VariableAccess, @cil_write_access {
|
||||
/** Gets the expression whose value is used in this variable write. */
|
||||
Expr getExpr() { none() }
|
||||
}
|
||||
|
||||
/** An instruction that accesses a parameter. */
|
||||
deprecated class ParameterAccess extends StackVariableAccess, @cil_arg_access {
|
||||
override MethodParameter getTarget() { result = StackVariableAccess.super.getTarget() }
|
||||
}
|
||||
|
||||
/** An instruction that reads a parameter. */
|
||||
deprecated class ParameterReadAccess extends ParameterAccess, ReadAccess {
|
||||
override int getPopCount() { result = 0 }
|
||||
}
|
||||
|
||||
/** An instruction that writes to a parameter. */
|
||||
deprecated class ParameterWriteAccess extends ParameterAccess, WriteAccess {
|
||||
override int getPopCount() { result = 1 }
|
||||
|
||||
override Expr getExpr() { result = this.getOperand(0) }
|
||||
}
|
||||
|
||||
/** An access to the `this` parameter. */
|
||||
deprecated class ThisAccess extends ParameterReadAccess {
|
||||
ThisAccess() { this.getTarget() instanceof ThisParameter }
|
||||
}
|
||||
|
||||
/** An instruction that accesses a stack variable. */
|
||||
deprecated class StackVariableAccess extends VariableAccess, @cil_stack_access {
|
||||
override StackVariable getTarget() { result = VariableAccess.super.getTarget() }
|
||||
}
|
||||
|
||||
/** An instruction that accesses a local variable. */
|
||||
deprecated class LocalVariableAccess extends StackVariableAccess, @cil_local_access {
|
||||
override LocalVariable getTarget() { result = StackVariableAccess.super.getTarget() }
|
||||
}
|
||||
|
||||
/** An instruction that writes to a local variable. */
|
||||
deprecated class LocalVariableWriteAccess extends LocalVariableAccess, WriteAccess {
|
||||
override int getPopCount() { result = 1 }
|
||||
|
||||
override Expr getExpr() { result = this.getOperand(0) }
|
||||
|
||||
override string getExtra() { result = "L" + this.getTarget().getIndex() }
|
||||
}
|
||||
|
||||
/** An instruction that reads a local variable. */
|
||||
deprecated class LocalVariableReadAccess extends LocalVariableAccess, ReadAccess {
|
||||
override int getPopCount() { result = 0 }
|
||||
}
|
||||
|
||||
/** An instruction that accesses a field. */
|
||||
deprecated class FieldAccess extends VariableAccess, @cil_field_access {
|
||||
override Field getTarget() { result = VariableAccess.super.getTarget() }
|
||||
|
||||
override string getExtra() { result = this.getTarget().getName() }
|
||||
|
||||
/** Gets the qualifier of the access, if any. */
|
||||
abstract Expr getQualifier();
|
||||
}
|
||||
|
||||
/** An instruction that reads a field. */
|
||||
abstract deprecated class FieldReadAccess extends FieldAccess, ReadAccess { }
|
||||
|
||||
/** An instruction that writes a field. */
|
||||
abstract deprecated class FieldWriteAccess extends FieldAccess, WriteAccess { }
|
||||
@@ -1,45 +0,0 @@
|
||||
/** Provides the `Attribute` class. */
|
||||
|
||||
private import CIL
|
||||
private import semmle.code.csharp.Location as CS
|
||||
|
||||
/** An attribute to a declaration, such as a method, field, type or parameter. */
|
||||
deprecated class Attribute extends Element, @cil_attribute {
|
||||
/** Gets the declaration this attribute is attached to. */
|
||||
Declaration getDeclaration() { cil_attribute(this, result, _) }
|
||||
|
||||
/** Gets the constructor used to construct this attribute. */
|
||||
Method getConstructor() { cil_attribute(this, _, result) }
|
||||
|
||||
/** Gets the type of this attribute. */
|
||||
Type getType() { result = this.getConstructor().getDeclaringType() }
|
||||
|
||||
override string toString() { result = "[" + this.getType().getName() + "(...)]" }
|
||||
|
||||
/** Gets the value of the `i`th argument of this attribute. */
|
||||
string getArgument(int i) { cil_attribute_positional_argument(this, i, result) }
|
||||
|
||||
/** Gets the value of the named argument `name`. */
|
||||
string getNamedArgument(string name) { cil_attribute_named_argument(this, name, result) }
|
||||
|
||||
/** Gets an argument of this attribute, if any. */
|
||||
string getAnArgument() { result = this.getArgument(_) or result = this.getNamedArgument(_) }
|
||||
|
||||
override CS::Location getLocation() { result = this.getDeclaration().getLocation() }
|
||||
}
|
||||
|
||||
/** A generic attribute to a declaration. */
|
||||
deprecated class GenericAttribute extends Attribute {
|
||||
private ConstructedType type;
|
||||
|
||||
GenericAttribute() { type = this.getType() }
|
||||
|
||||
/** Gets the total number of type arguments. */
|
||||
int getNumberOfTypeArguments() { result = count(int i | cil_type_argument(type, i, _)) }
|
||||
|
||||
/** Gets the `i`th type argument, if any. */
|
||||
Type getTypeArgument(int i) { result = type.getTypeArgument(i) }
|
||||
|
||||
/** Get a type argument. */
|
||||
Type getATypeArgument() { result = this.getTypeArgument(_) }
|
||||
}
|
||||
@@ -1,401 +0,0 @@
|
||||
/**
|
||||
* Provides classes representing basic blocks.
|
||||
*/
|
||||
|
||||
private import CIL
|
||||
|
||||
/**
|
||||
* A basic block, that is, a maximal straight-line sequence of control flow nodes
|
||||
* without branches or joins.
|
||||
*/
|
||||
deprecated class BasicBlock extends Cached::TBasicBlockStart {
|
||||
/** Gets an immediate successor of this basic block, if any. */
|
||||
BasicBlock getASuccessor() { result.getFirstNode() = this.getLastNode().getASuccessor() }
|
||||
|
||||
/** Gets an immediate predecessor of this basic block, if any. */
|
||||
BasicBlock getAPredecessor() { result.getASuccessor() = this }
|
||||
|
||||
/**
|
||||
* Gets an immediate `true` successor, if any.
|
||||
*
|
||||
* An immediate `true` successor is a successor that is reached when
|
||||
* the condition that ends this basic block evaluates to `true`.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```csharp
|
||||
* if (x < 0)
|
||||
* x = -x;
|
||||
* ```
|
||||
*
|
||||
* The basic block on line 2 is an immediate `true` successor of the
|
||||
* basic block on line 1.
|
||||
*/
|
||||
BasicBlock getATrueSuccessor() { result.getFirstNode() = this.getLastNode().getTrueSuccessor() }
|
||||
|
||||
/**
|
||||
* Gets an immediate `false` successor, if any.
|
||||
*
|
||||
* An immediate `false` successor is a successor that is reached when
|
||||
* the condition that ends this basic block evaluates to `false`.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```csharp
|
||||
* if (!(x >= 0))
|
||||
* x = -x;
|
||||
* ```
|
||||
*
|
||||
* The basic block on line 2 is an immediate `false` successor of the
|
||||
* basic block on line 1.
|
||||
*/
|
||||
BasicBlock getAFalseSuccessor() { result.getFirstNode() = this.getLastNode().getFalseSuccessor() }
|
||||
|
||||
/** Gets the control flow node at a specific (zero-indexed) position in this basic block. */
|
||||
ControlFlowNode getNode(int pos) { Cached::bbIndex(this.getFirstNode(), result, pos) }
|
||||
|
||||
/** Gets a control flow node in this basic block. */
|
||||
ControlFlowNode getANode() { result = this.getNode(_) }
|
||||
|
||||
/** Gets the first control flow node in this basic block. */
|
||||
ControlFlowNode getFirstNode() { this = Cached::TBasicBlockStart(result) }
|
||||
|
||||
/** Gets the last control flow node in this basic block. */
|
||||
ControlFlowNode getLastNode() { result = this.getNode(this.length() - 1) }
|
||||
|
||||
/** Gets the length of this basic block. */
|
||||
int length() { result = strictcount(this.getANode()) }
|
||||
|
||||
/**
|
||||
* Holds if this basic block strictly dominates basic block `bb`.
|
||||
*
|
||||
* That is, all paths reaching basic block `bb` from some entry point
|
||||
* basic block must go through this basic block (which must be different
|
||||
* from `bb`).
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```csharp
|
||||
* int M(string s) {
|
||||
* if (s == null)
|
||||
* throw new ArgumentNullException(nameof(s));
|
||||
* return s.Length;
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* The basic block starting on line 2 strictly dominates the
|
||||
* basic block on line 4 (all paths from the entry point of `M`
|
||||
* to `return s.Length;` must go through the null check).
|
||||
*/
|
||||
predicate strictlyDominates(BasicBlock bb) { bbIDominates+(this, bb) }
|
||||
|
||||
/**
|
||||
* Holds if this basic block dominates basic block `bb`.
|
||||
*
|
||||
* That is, all paths reaching basic block `bb` from some entry point
|
||||
* basic block must go through this basic block.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```csharp
|
||||
* int M(string s) {
|
||||
* if (s == null)
|
||||
* throw new ArgumentNullException(nameof(s));
|
||||
* return s.Length;
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* The basic block starting on line 2 dominates the basic
|
||||
* block on line 4 (all paths from the entry point of `M` to
|
||||
* `return s.Length;` must go through the null check).
|
||||
*
|
||||
* This predicate is *reflexive*, so for example `if (s == null)` dominates
|
||||
* itself.
|
||||
*/
|
||||
predicate dominates(BasicBlock bb) {
|
||||
bb = this or
|
||||
this.strictlyDominates(bb)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `df` is in the dominance frontier of this basic block.
|
||||
* That is, this basic block dominates a predecessor of `df`, but
|
||||
* does not dominate `df` itself.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```csharp
|
||||
* if (x < 0) {
|
||||
* x = -x;
|
||||
* if (x > 10)
|
||||
* x--;
|
||||
* }
|
||||
* Console.Write(x);
|
||||
* ```
|
||||
*
|
||||
* The basic block on line 6 is in the dominance frontier
|
||||
* of the basic block starting on line 2 because that block
|
||||
* dominates the basic block on line 4, which is a predecessor of
|
||||
* `Console.Write(x);`. Also, the basic block starting on line 2
|
||||
* does not dominate the basic block on line 6.
|
||||
*/
|
||||
predicate inDominanceFrontier(BasicBlock df) {
|
||||
this.dominatesPredecessor(df) and
|
||||
not this.strictlyDominates(df)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this basic block dominates a predecessor of `df`.
|
||||
*/
|
||||
private predicate dominatesPredecessor(BasicBlock df) { this.dominates(df.getAPredecessor()) }
|
||||
|
||||
/**
|
||||
* Gets the basic block that immediately dominates this basic block, if any.
|
||||
*
|
||||
* That is, all paths reaching this basic block from some entry point
|
||||
* basic block must go through the result, which is an immediate basic block
|
||||
* predecessor of this basic block.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```csharp
|
||||
* int M(string s) {
|
||||
* if (s == null)
|
||||
* throw new ArgumentNullException(nameof(s));
|
||||
* return s.Length;
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* The basic block starting on line 2 is an immediate dominator of
|
||||
* the basic block online 4 (all paths from the entry point of `M`
|
||||
* to `return s.Length;` must go through the null check, and the null check
|
||||
* is an immediate predecessor of `return s.Length;`).
|
||||
*/
|
||||
BasicBlock getImmediateDominator() { bbIDominates(result, this) }
|
||||
|
||||
/**
|
||||
* Holds if this basic block strictly post-dominates basic block `bb`.
|
||||
*
|
||||
* That is, all paths reaching an exit point basic block from basic
|
||||
* block `bb` must go through this basic block (which must be different
|
||||
* from `bb`).
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```csharp
|
||||
* int M(string s) {
|
||||
* try {
|
||||
* return s.Length;
|
||||
* }
|
||||
* finally {
|
||||
* Console.WriteLine("M");
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* The basic block on line 6 strictly post-dominates the basic block on
|
||||
* line 3 (all paths to the exit point of `M` from `return s.Length;`
|
||||
* must go through the `WriteLine` call).
|
||||
*/
|
||||
predicate strictlyPostDominates(BasicBlock bb) { bbIPostDominates+(this, bb) }
|
||||
|
||||
/**
|
||||
* Holds if this basic block post-dominates basic block `bb`.
|
||||
*
|
||||
* That is, all paths reaching an exit point basic block from basic
|
||||
* block `bb` must go through this basic block.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```csharp
|
||||
* int M(string s) {
|
||||
* try {
|
||||
* return s.Length;
|
||||
* }
|
||||
* finally {
|
||||
* Console.WriteLine("M");
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* The basic block on line 6 post-dominates the basic block on line 3
|
||||
* (all paths to the exit point of `M` from `return s.Length;` must go
|
||||
* through the `WriteLine` call).
|
||||
*
|
||||
* This predicate is *reflexive*, so for example `Console.WriteLine("M");`
|
||||
* post-dominates itself.
|
||||
*/
|
||||
predicate postDominates(BasicBlock bb) {
|
||||
this.strictlyPostDominates(bb) or
|
||||
this = bb
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this basic block is in a loop in the control flow graph. This
|
||||
* includes loops created by `goto` statements. This predicate may not hold
|
||||
* even if this basic block is syntactically inside a `while` loop if the
|
||||
* necessary back edges are unreachable.
|
||||
*/
|
||||
predicate inLoop() { this.getASuccessor+() = this }
|
||||
|
||||
/** Gets a textual representation of this basic block. */
|
||||
string toString() { result = this.getFirstNode().toString() }
|
||||
|
||||
/** Gets the location of this basic block. */
|
||||
Location getLocation() { result = this.getFirstNode().getLocation() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal implementation details.
|
||||
*/
|
||||
cached
|
||||
deprecated private module Cached {
|
||||
/** Internal representation of basic blocks. */
|
||||
cached
|
||||
newtype TBasicBlock = TBasicBlockStart(ControlFlowNode cfn) { startsBB(cfn) }
|
||||
|
||||
/** Holds if `cfn` starts a new basic block. */
|
||||
private predicate startsBB(ControlFlowNode cfn) {
|
||||
not exists(cfn.getAPredecessor()) and exists(cfn.getASuccessor())
|
||||
or
|
||||
cfn.isJoin()
|
||||
or
|
||||
cfn.getAPredecessor().isBranch()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `succ` is a control flow successor of `pred` within
|
||||
* the same basic block.
|
||||
*/
|
||||
private predicate intraBBSucc(ControlFlowNode pred, ControlFlowNode succ) {
|
||||
succ = pred.getASuccessor() and
|
||||
not startsBB(succ)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `cfn` is the `i`th node in basic block `bb`.
|
||||
*
|
||||
* In other words, `i` is the shortest distance from a node `bb`
|
||||
* that starts a basic block to `cfn` along the `intraBBSucc` relation.
|
||||
*/
|
||||
cached
|
||||
predicate bbIndex(ControlFlowNode bbStart, ControlFlowNode cfn, int i) =
|
||||
shortestDistances(startsBB/1, intraBBSucc/2)(bbStart, cfn, i)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the first node of basic block `succ` is a control flow
|
||||
* successor of the last node of basic block `pred`.
|
||||
*/
|
||||
deprecated private predicate succBB(BasicBlock pred, BasicBlock succ) {
|
||||
succ = pred.getASuccessor()
|
||||
}
|
||||
|
||||
/** Holds if `dom` is an immediate dominator of `bb`. */
|
||||
deprecated predicate bbIDominates(BasicBlock dom, BasicBlock bb) =
|
||||
idominance(entryBB/1, succBB/2)(_, dom, bb)
|
||||
|
||||
/** Holds if `pred` is a basic block predecessor of `succ`. */
|
||||
deprecated private predicate predBB(BasicBlock succ, BasicBlock pred) { succBB(pred, succ) }
|
||||
|
||||
/** Holds if `dom` is an immediate post-dominator of `bb`. */
|
||||
deprecated predicate bbIPostDominates(BasicBlock dom, BasicBlock bb) =
|
||||
idominance(exitBB/1, predBB/2)(_, dom, bb)
|
||||
|
||||
/**
|
||||
* An entry basic block, that is, a basic block whose first node is
|
||||
* the entry node of a callable.
|
||||
*/
|
||||
deprecated class EntryBasicBlock extends BasicBlock {
|
||||
EntryBasicBlock() { entryBB(this) }
|
||||
}
|
||||
|
||||
/** Holds if `bb` is an entry basic block. */
|
||||
deprecated private predicate entryBB(BasicBlock bb) {
|
||||
bb.getFirstNode() instanceof MethodImplementation
|
||||
}
|
||||
|
||||
/**
|
||||
* An exit basic block, that is, a basic block whose last node is
|
||||
* an exit node.
|
||||
*/
|
||||
deprecated class ExitBasicBlock extends BasicBlock {
|
||||
ExitBasicBlock() { exitBB(this) }
|
||||
}
|
||||
|
||||
/** Holds if `bb` is an exit basic block. */
|
||||
deprecated private predicate exitBB(BasicBlock bb) { not exists(bb.getLastNode().getASuccessor()) }
|
||||
|
||||
/**
|
||||
* A basic block with more than one predecessor.
|
||||
*/
|
||||
deprecated class JoinBlock extends BasicBlock {
|
||||
JoinBlock() { this.getFirstNode().isJoin() }
|
||||
}
|
||||
|
||||
/** A basic block that terminates in a condition, splitting the subsequent control flow. */
|
||||
deprecated class ConditionBlock extends BasicBlock {
|
||||
ConditionBlock() {
|
||||
exists(BasicBlock succ |
|
||||
succ = this.getATrueSuccessor()
|
||||
or
|
||||
succ = this.getAFalseSuccessor()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if basic block `controlled` is controlled by this basic block with
|
||||
* Boolean value `testIsTrue`. That is, `controlled` can only be reached from
|
||||
* the callable entry point by going via the true edge (`testIsTrue = true`)
|
||||
* or false edge (`testIsTrue = false`) out of this basic block.
|
||||
*/
|
||||
predicate controls(BasicBlock controlled, boolean testIsTrue) {
|
||||
/*
|
||||
* For this block to control the block `controlled` with `testIsTrue` the following must be true:
|
||||
* Execution must have passed through the test i.e. `this` must strictly dominate `controlled`.
|
||||
* Execution must have passed through the `testIsTrue` edge leaving `this`.
|
||||
*
|
||||
* Although "passed through the true edge" implies that `this.getATrueSuccessor()` dominates `controlled`,
|
||||
* the reverse is not true, as flow may have passed through another edge to get to `this.getATrueSuccessor()`
|
||||
* so we need to assert that `this.getATrueSuccessor()` dominates `controlled` *and* that
|
||||
* all predecessors of `this.getATrueSuccessor()` are either `this` or dominated by `this.getATrueSuccessor()`.
|
||||
*
|
||||
* For example, in the following C# snippet:
|
||||
* ```csharp
|
||||
* if (x)
|
||||
* controlled;
|
||||
* false_successor;
|
||||
* uncontrolled;
|
||||
* ```
|
||||
* `false_successor` dominates `uncontrolled`, but not all of its predecessors are `this` (`if (x)`)
|
||||
* or dominated by itself. Whereas in the following code:
|
||||
* ```csharp
|
||||
* if (x)
|
||||
* while (controlled)
|
||||
* also_controlled;
|
||||
* false_successor;
|
||||
* uncontrolled;
|
||||
* ```
|
||||
* the block `while controlled` is controlled because all of its predecessors are `this` (`if (x)`)
|
||||
* or (in the case of `also_controlled`) dominated by itself.
|
||||
*
|
||||
* The additional constraint on the predecessors of the test successor implies
|
||||
* that `this` strictly dominates `controlled` so that isn't necessary to check
|
||||
* directly.
|
||||
*/
|
||||
|
||||
exists(BasicBlock succ |
|
||||
this.isCandidateSuccessor(succ, testIsTrue) and
|
||||
succ.dominates(controlled)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate isCandidateSuccessor(BasicBlock succ, boolean testIsTrue) {
|
||||
(
|
||||
testIsTrue = true and succ = this.getATrueSuccessor()
|
||||
or
|
||||
testIsTrue = false and succ = this.getAFalseSuccessor()
|
||||
) and
|
||||
forall(BasicBlock pred | pred = succ.getAPredecessor() and pred != this | succ.dominates(pred))
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
/** Provides the core CIL data model. */
|
||||
|
||||
import semmle.code.csharp.Location
|
||||
import Element
|
||||
import Instruction
|
||||
import Instructions
|
||||
import Access
|
||||
import Variable
|
||||
import Declaration
|
||||
import Generics
|
||||
import Type
|
||||
import Types
|
||||
import Method
|
||||
import InstructionGroups
|
||||
import BasicBlock
|
||||
import Handler
|
||||
import ControlFlow
|
||||
import DataFlow
|
||||
import Attribute
|
||||
import Stubs
|
||||
import CustomModifierReceiver
|
||||
import Parameterizable
|
||||
import semmle.code.cil.Ssa
|
||||
@@ -1,74 +0,0 @@
|
||||
/**
|
||||
* Provides predicates for analysing the return values of callables.
|
||||
*/
|
||||
|
||||
private import CIL
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
/** Holds if method `m` always returns null. */
|
||||
cached
|
||||
deprecated predicate alwaysNullMethod(Method m) {
|
||||
forex(Expr e | m.canReturn(e) | alwaysNullExpr(e))
|
||||
}
|
||||
|
||||
/** Holds if method `m` always returns non-null. */
|
||||
cached
|
||||
deprecated predicate alwaysNotNullMethod(Method m) {
|
||||
forex(Expr e | m.canReturn(e) | alwaysNotNullExpr(e))
|
||||
}
|
||||
|
||||
/** Holds if method `m` always throws an exception. */
|
||||
cached
|
||||
deprecated predicate alwaysThrowsMethod(Method m) {
|
||||
m.hasBody() and
|
||||
not exists(m.getImplementation().getAnInstruction().(Return))
|
||||
}
|
||||
|
||||
/** Holds if method `m` always throws an exception of type `t`. */
|
||||
cached
|
||||
deprecated predicate alwaysThrowsException(Method m, Type t) {
|
||||
alwaysThrowsMethod(m) and
|
||||
forex(Throw ex | ex = m.getImplementation().getAnInstruction() | t = ex.getExceptionType())
|
||||
}
|
||||
}
|
||||
|
||||
import Cached
|
||||
|
||||
pragma[noinline]
|
||||
deprecated private predicate alwaysNullVariableUpdate(VariableUpdate vu) {
|
||||
forex(Expr src | src = vu.getSource() | alwaysNullExpr(src))
|
||||
}
|
||||
|
||||
/** Holds if expression `expr` always evaluates to `null`. */
|
||||
deprecated private predicate alwaysNullExpr(Expr expr) {
|
||||
expr instanceof NullLiteral
|
||||
or
|
||||
alwaysNullMethod(expr.(StaticCall).getTarget())
|
||||
or
|
||||
forex(Ssa::Definition def |
|
||||
expr = any(Ssa::Definition def0 | def = def0.getAnUltimateDefinition()).getARead()
|
||||
|
|
||||
alwaysNullVariableUpdate(def.getVariableUpdate())
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
deprecated private predicate alwaysNotNullVariableUpdate(VariableUpdate vu) {
|
||||
forex(Expr src | src = vu.getSource() | alwaysNotNullExpr(src))
|
||||
}
|
||||
|
||||
/** Holds if expression `expr` always evaluates to non-null. */
|
||||
deprecated private predicate alwaysNotNullExpr(Expr expr) {
|
||||
expr instanceof Opcodes::NewObj
|
||||
or
|
||||
expr instanceof Literal and not expr instanceof NullLiteral
|
||||
or
|
||||
alwaysNotNullMethod(expr.(StaticCall).getTarget())
|
||||
or
|
||||
forex(Ssa::Definition def |
|
||||
expr = any(Ssa::Definition def0 | def = def0.getAnUltimateDefinition()).getARead()
|
||||
|
|
||||
alwaysNotNullVariableUpdate(def.getVariableUpdate())
|
||||
)
|
||||
}
|
||||
@@ -1,787 +0,0 @@
|
||||
/**
|
||||
* Provides checks for the consistency of the data model and database.
|
||||
*/
|
||||
|
||||
private import CIL
|
||||
private import csharp as CS
|
||||
private import semmle.code.csharp.commons.QualifiedName
|
||||
|
||||
private newtype ConsistencyCheck =
|
||||
MissingEntityCheck() or
|
||||
deprecated TypeCheck(Type t) or
|
||||
deprecated CfgCheck(ControlFlowNode n) or
|
||||
deprecated DeclarationCheck(Declaration d) or
|
||||
MissingCSharpCheck(CS::Declaration d)
|
||||
|
||||
/**
|
||||
* A consistency violation in the database or data model.
|
||||
*/
|
||||
abstract deprecated class ConsistencyViolation extends ConsistencyCheck {
|
||||
abstract string toString();
|
||||
|
||||
abstract string getMessage();
|
||||
}
|
||||
|
||||
/**
|
||||
* A check that is deliberately disabled.
|
||||
*/
|
||||
abstract deprecated class DisabledCheck extends ConsistencyViolation {
|
||||
DisabledCheck() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A consistency violation on a control flow node.
|
||||
*/
|
||||
abstract deprecated class CfgViolation extends ConsistencyViolation, CfgCheck {
|
||||
ControlFlowNode node;
|
||||
|
||||
CfgViolation() { this = CfgCheck(node) }
|
||||
|
||||
override string toString() { result = node.toString() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A consistency violation in a specific instruction.
|
||||
*/
|
||||
abstract deprecated class InstructionViolation extends CfgViolation, CfgCheck {
|
||||
Instruction instruction;
|
||||
|
||||
InstructionViolation() { this = CfgCheck(instruction) }
|
||||
|
||||
private string getInstructionsUpTo() {
|
||||
result =
|
||||
concat(Instruction i |
|
||||
i.getIndex() <= instruction.getIndex() and
|
||||
i.getImplementation() = instruction.getImplementation()
|
||||
|
|
||||
i.toString() + " [push: " + i.getPushCount() + ", pop: " + i.getPopCount() + "]", "; "
|
||||
order by
|
||||
i.getIndex()
|
||||
)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result =
|
||||
instruction.getImplementation().getMethod().toStringWithTypes() + ": " +
|
||||
instruction.toString() + ", " + this.getInstructionsUpTo()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A literal that does not have exactly one `getValue()`.
|
||||
*/
|
||||
deprecated class MissingValue extends InstructionViolation {
|
||||
MissingValue() { exists(Literal l | l = instruction | count(l.getValue()) != 1) }
|
||||
|
||||
override string getMessage() { result = "Literal has invalid getValue()" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call that does not have exactly one `getTarget()`.
|
||||
*/
|
||||
deprecated class MissingCallTarget extends InstructionViolation {
|
||||
MissingCallTarget() {
|
||||
exists(Call c | c = instruction |
|
||||
count(c.getTarget()) != 1 and not c instanceof Opcodes::Calli
|
||||
or
|
||||
count(c.(Opcodes::Calli).getTargetType()) != 1 and c instanceof Opcodes::Calli
|
||||
)
|
||||
}
|
||||
|
||||
override string getMessage() { result = "Call has invalid target" }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that has not been assigned a specific QL class.
|
||||
*/
|
||||
deprecated class MissingOpCode extends InstructionViolation {
|
||||
MissingOpCode() { not exists(instruction.getOpcodeName()) }
|
||||
|
||||
override string getMessage() {
|
||||
result = "Opcode " + instruction.getOpcode() + " is missing a QL class"
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "Unknown instruction in " + instruction.getImplementation().getMethod().toString()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that is missing an operand. It means that there is no instruction which pushes
|
||||
* a value onto the stack for this instruction to pop.
|
||||
*
|
||||
* If this fails, it means that the `getPopCount`/`getPushCount`/control flow graph has failed.
|
||||
* It could also mean that the target of a call has failed and has not determined the
|
||||
* correct number of arguments.
|
||||
*/
|
||||
deprecated class MissingOperand extends InstructionViolation {
|
||||
MissingOperand() {
|
||||
exists(int op | op in [0 .. instruction.getPopCount() - 1] |
|
||||
not exists(instruction.getOperand(op)) and not instruction instanceof DeadInstruction
|
||||
)
|
||||
}
|
||||
|
||||
int getMissingOperand() {
|
||||
result in [0 .. instruction.getPopCount() - 1] and
|
||||
not exists(instruction.getOperand(result))
|
||||
}
|
||||
|
||||
override string getMessage() {
|
||||
result = "This instruction is missing operand " + this.getMissingOperand()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A dead instruction, not reachable from any entry point.
|
||||
* These should not exist, however it turns out that the Mono compiler sometimes
|
||||
* emits them.
|
||||
*/
|
||||
deprecated class DeadInstruction extends Instruction {
|
||||
DeadInstruction() { not exists(EntryPoint e | e.getASuccessor+() = this) }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that is not reachable from any entry point.
|
||||
*
|
||||
* If this fails, it means that the calculation of the call graph is incorrect.
|
||||
* Disabled, because Mono compiler sometimes emits dead instructions.
|
||||
*/
|
||||
deprecated class DeadInstructionViolation extends InstructionViolation, DisabledCheck {
|
||||
DeadInstructionViolation() { instruction instanceof DeadInstruction }
|
||||
|
||||
override string getMessage() { result = "This instruction is not reachable" }
|
||||
}
|
||||
|
||||
deprecated class YesNoBranch extends ConditionalBranch {
|
||||
YesNoBranch() { not this instanceof Opcodes::Switch }
|
||||
}
|
||||
|
||||
/**
|
||||
* A branch instruction that does not have exactly 2 successors.
|
||||
*/
|
||||
deprecated class InvalidBranchSuccessors extends InstructionViolation {
|
||||
InvalidBranchSuccessors() {
|
||||
// Mono compiler sometimes generates branches to the next instruction, which is just wrong.
|
||||
// However it is valid CIL.
|
||||
exists(YesNoBranch i | i = instruction | not count(i.getASuccessor()) in [1 .. 2])
|
||||
}
|
||||
|
||||
override string getMessage() {
|
||||
result = "Conditional branch has " + count(instruction.getASuccessor()) + " successors"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that has a true/false successor but is not a branch.
|
||||
*/
|
||||
deprecated class OnlyYesNoBranchHasTrueFalseSuccessors extends InstructionViolation {
|
||||
OnlyYesNoBranchHasTrueFalseSuccessors() {
|
||||
(exists(instruction.getTrueSuccessor()) or exists(instruction.getFalseSuccessor())) and
|
||||
not instruction instanceof YesNoBranch
|
||||
}
|
||||
|
||||
override string getMessage() { result = "This instruction has getTrue/FalseSuccessor()" }
|
||||
}
|
||||
|
||||
/**
|
||||
* An unconditional branch instruction that has more than one successor.
|
||||
*/
|
||||
deprecated class UnconditionalBranchSuccessors extends InstructionViolation {
|
||||
UnconditionalBranchSuccessors() {
|
||||
exists(UnconditionalBranch i | i = instruction | count(i.getASuccessor()) != 1)
|
||||
}
|
||||
|
||||
override string getMessage() {
|
||||
result = "Unconditional branch has " + count(instruction.getASuccessor()) + " successors"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A branch instruction that does not have a true successor.
|
||||
*/
|
||||
deprecated class NoTrueSuccessor extends InstructionViolation {
|
||||
NoTrueSuccessor() { exists(YesNoBranch i | i = instruction | not exists(i.getTrueSuccessor())) }
|
||||
|
||||
override string getMessage() { result = "Missing a true successor" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A branch instruction that does not have a false successor.
|
||||
*/
|
||||
deprecated class NoFalseSuccessor extends InstructionViolation {
|
||||
NoFalseSuccessor() { exists(YesNoBranch i | i = instruction | not exists(i.getFalseSuccessor())) }
|
||||
|
||||
override string getMessage() { result = "Missing a false successor" }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction whose true successor is not a successor.
|
||||
*/
|
||||
deprecated class TrueSuccessorIsSuccessor extends InstructionViolation {
|
||||
TrueSuccessorIsSuccessor() {
|
||||
exists(instruction.getTrueSuccessor()) and
|
||||
not instruction.getTrueSuccessor() = instruction.getASuccessor()
|
||||
}
|
||||
|
||||
override string getMessage() { result = "True successor isn't a successor" }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction whose false successor is not a successor.
|
||||
*/
|
||||
deprecated class FalseSuccessorIsSuccessor extends InstructionViolation {
|
||||
FalseSuccessorIsSuccessor() {
|
||||
exists(instruction.getFalseSuccessor()) and
|
||||
not instruction.getFalseSuccessor() = instruction.getASuccessor()
|
||||
}
|
||||
|
||||
override string getMessage() { result = "True successor isn't a successor" }
|
||||
}
|
||||
|
||||
/**
|
||||
* An access that does not have exactly one target.
|
||||
*/
|
||||
deprecated class AccessMissingTarget extends InstructionViolation {
|
||||
AccessMissingTarget() { exists(Access i | i = instruction | count(i.getTarget()) != 1) }
|
||||
|
||||
override string getMessage() { result = "Access has invalid getTarget()" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A catch handler that doesn't have a caught exception type.
|
||||
*/
|
||||
deprecated class CatchHandlerMissingType extends CfgViolation {
|
||||
CatchHandlerMissingType() { exists(CatchHandler h | h = node | not exists(h.getCaughtType())) }
|
||||
|
||||
override string getMessage() { result = "Catch handler missing caught type" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A CFG node that does not have a stack size.
|
||||
*/
|
||||
deprecated class MissingStackSize extends CfgViolation {
|
||||
MissingStackSize() {
|
||||
(
|
||||
not exists(node.getStackSizeAfter()) or
|
||||
not exists(node.getStackSizeBefore())
|
||||
) and
|
||||
not node instanceof DeadInstruction
|
||||
}
|
||||
|
||||
override string getMessage() { result = "Inconsistent stack size" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A CFG node that does not have exactly one stack size.
|
||||
* Disabled because inconsistent stack sizes have been observed.
|
||||
*/
|
||||
deprecated class InvalidStackSize extends CfgViolation, DisabledCheck {
|
||||
InvalidStackSize() {
|
||||
(
|
||||
count(node.getStackSizeAfter()) != 1 or
|
||||
count(node.getStackSizeBefore()) != 1
|
||||
) and
|
||||
not node instanceof DeadInstruction
|
||||
}
|
||||
|
||||
override string getMessage() {
|
||||
result =
|
||||
"Inconsistent stack sizes " + count(node.getStackSizeBefore()) + " before and " +
|
||||
count(node.getStackSizeAfter()) + " after"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A CFG node that does not have exactly 1 `getPopCount()`.
|
||||
*/
|
||||
deprecated class InconsistentPopCount extends CfgViolation {
|
||||
InconsistentPopCount() { count(node.getPopCount()) != 1 }
|
||||
|
||||
override string getMessage() {
|
||||
result = "Cfg node has " + count(node.getPopCount()) + " pop counts"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A CFG node that does not have exactly one `getPushCount()`.
|
||||
*/
|
||||
deprecated class InconsistentPushCount extends CfgViolation {
|
||||
InconsistentPushCount() { count(node.getPushCount()) != 1 }
|
||||
|
||||
override string getMessage() {
|
||||
result = "Cfg node has " + count(node.getPushCount()) + " push counts"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A return instruction that does not have a stack size of 0 after it.
|
||||
*/
|
||||
deprecated class InvalidReturn extends InstructionViolation {
|
||||
InvalidReturn() { instruction instanceof Return and instruction.getStackSizeAfter() != 0 }
|
||||
|
||||
override string getMessage() { result = "Return has invalid stack size" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A throw instruction that does not have a stack size of 0 after it.
|
||||
*/
|
||||
deprecated class InvalidThrow extends InstructionViolation, DisabledCheck {
|
||||
InvalidThrow() { instruction instanceof Throw and instruction.getStackSizeAfter() != 0 }
|
||||
|
||||
override string getMessage() {
|
||||
result = "Throw has invalid stack size: " + instruction.getStackSizeAfter()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A field access where the field is "static" but the instruction is "instance".
|
||||
*/
|
||||
deprecated class StaticFieldTarget extends InstructionViolation {
|
||||
StaticFieldTarget() {
|
||||
exists(FieldAccess i | i = instruction |
|
||||
(i instanceof Opcodes::Stfld or i instanceof Opcodes::Stfld) and
|
||||
i.getTarget().isStatic()
|
||||
)
|
||||
}
|
||||
|
||||
override string getMessage() { result = "Inconsistent static field" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A branch without a target.
|
||||
*/
|
||||
deprecated class BranchWithoutTarget extends InstructionViolation {
|
||||
BranchWithoutTarget() {
|
||||
instruction = any(Branch b | not exists(b.getTarget()) and not b instanceof Opcodes::Switch)
|
||||
}
|
||||
|
||||
override string getMessage() { result = "Branch without target" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A consistency violation in a type.
|
||||
*/
|
||||
deprecated class TypeViolation extends ConsistencyViolation, TypeCheck {
|
||||
/** Gets the type containing the violation. */
|
||||
Type getType() { this = TypeCheck(result) }
|
||||
|
||||
override string toString() { result = this.getType().toString() }
|
||||
|
||||
abstract override string getMessage();
|
||||
}
|
||||
|
||||
/**
|
||||
* A type that has both type arguments and type parameters.
|
||||
*/
|
||||
deprecated class TypeIsBothConstructedAndUnbound extends TypeViolation {
|
||||
TypeIsBothConstructedAndUnbound() {
|
||||
this.getType() instanceof ConstructedGeneric and this.getType() instanceof UnboundGeneric
|
||||
}
|
||||
|
||||
override string getMessage() { result = "Type is both constructed and unbound" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The location of a constructed generic type should be the same
|
||||
* as the location of its unbound generic type.
|
||||
*/
|
||||
deprecated class InconsistentTypeLocation extends TypeViolation {
|
||||
InconsistentTypeLocation() {
|
||||
this.getType().getLocation() != this.getType().getUnboundDeclaration().getLocation()
|
||||
}
|
||||
|
||||
override string getMessage() { result = "Inconsistent constructed type location" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A constructed type that does not match its unbound generic type.
|
||||
*/
|
||||
deprecated class TypeParameterMismatch extends TypeViolation {
|
||||
TypeParameterMismatch() {
|
||||
this.getType().(ConstructedGeneric).getNumberOfTypeArguments() !=
|
||||
this.getType().getUnboundType().(UnboundGeneric).getNumberOfTypeParameters()
|
||||
}
|
||||
|
||||
override string getMessage() {
|
||||
result =
|
||||
"Constructed type (" + this.getType().toStringWithTypes() + ") has " +
|
||||
this.getType().(ConstructedGeneric).getNumberOfTypeArguments() +
|
||||
" type arguments and unbound type (" + this.getType().getUnboundType().toStringWithTypes() +
|
||||
") has " + this.getType().getUnboundType().(UnboundGeneric).getNumberOfTypeParameters() +
|
||||
" type parameters"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A consistency violation in a method.
|
||||
*/
|
||||
deprecated class MethodViolation extends ConsistencyViolation, DeclarationCheck {
|
||||
/** Gets the method containing the violation. */
|
||||
Method getMethod() { this = DeclarationCheck(result) }
|
||||
|
||||
override string toString() { result = this.getMethod().toString() }
|
||||
|
||||
override string getMessage() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* The location of a constructed method should be equal to the
|
||||
* location of its unbound generic.
|
||||
*/
|
||||
deprecated class InconsistentMethodLocation extends MethodViolation {
|
||||
InconsistentMethodLocation() {
|
||||
this.getMethod().getLocation() != this.getMethod().getUnboundDeclaration().getLocation()
|
||||
}
|
||||
|
||||
override string getMessage() { result = "Inconsistent constructed method location" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A constructed method that does not match its unbound method.
|
||||
*/
|
||||
deprecated class ConstructedMethodTypeParams extends MethodViolation {
|
||||
ConstructedMethodTypeParams() {
|
||||
this.getMethod().(ConstructedGeneric).getNumberOfTypeArguments() !=
|
||||
this.getMethod().getUnboundDeclaration().(UnboundGeneric).getNumberOfTypeParameters()
|
||||
}
|
||||
|
||||
override string getMessage() {
|
||||
result =
|
||||
"The constructed method " + this.getMethod().toStringWithTypes() +
|
||||
" does not match unbound method " +
|
||||
this.getMethod().getUnboundDeclaration().toStringWithTypes()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A violation marking an entity that should be present but is not.
|
||||
*/
|
||||
abstract deprecated class MissingEntityViolation extends ConsistencyViolation, MissingEntityCheck {
|
||||
override string toString() { result = "Missing entity" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The type `object` is missing from the database.
|
||||
*/
|
||||
deprecated class MissingObjectViolation extends MissingEntityViolation {
|
||||
MissingObjectViolation() {
|
||||
exists(this) and
|
||||
not exists(ObjectType o)
|
||||
}
|
||||
|
||||
override string getMessage() { result = "Object missing" }
|
||||
}
|
||||
|
||||
/**
|
||||
* An override that is invalid because the overridden method is not in a base class.
|
||||
*/
|
||||
deprecated class InvalidOverride extends MethodViolation {
|
||||
private Method base;
|
||||
|
||||
InvalidOverride() {
|
||||
base = this.getMethod().getOverriddenMethod() and
|
||||
not this.getMethod().getDeclaringType().getABaseType+() = base.getDeclaringType() and
|
||||
base.getDeclaringType().isUnboundDeclaration() // Bases classes of constructed types aren't extracted properly.
|
||||
}
|
||||
|
||||
override string getMessage() {
|
||||
exists(string qualifier, string type |
|
||||
base.getDeclaringType().hasFullyQualifiedName(qualifier, type)
|
||||
|
|
||||
result =
|
||||
"Overridden method from " + getQualifiedName(qualifier, type) + " is not in a base type"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A pointer type that does not have a pointee type.
|
||||
*/
|
||||
deprecated class InvalidPointerType extends TypeViolation {
|
||||
InvalidPointerType() {
|
||||
exists(PointerType p | p = this.getType() | count(p.getReferentType()) != 1)
|
||||
}
|
||||
|
||||
override string getMessage() { result = "Invalid Pointertype.getPointeeType()" }
|
||||
}
|
||||
|
||||
/**
|
||||
* An array with an invalid `getElementType`.
|
||||
*/
|
||||
deprecated class ArrayTypeMissingElement extends TypeViolation {
|
||||
ArrayTypeMissingElement() {
|
||||
exists(ArrayType t | t = this.getType() | count(t.getElementType()) != 1)
|
||||
}
|
||||
|
||||
override string getMessage() { result = "Invalid ArrayType.getElementType()" }
|
||||
}
|
||||
|
||||
/**
|
||||
* An array with an invalid `getRank`.
|
||||
*/
|
||||
deprecated class ArrayTypeInvalidRank extends TypeViolation {
|
||||
ArrayTypeInvalidRank() { exists(ArrayType t | t = this.getType() | not t.getRank() > 0) }
|
||||
|
||||
override string getMessage() { result = "Invalid ArrayType.getRank()" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A type should have at most one kind, except for missing referenced types
|
||||
* where the interface/class is unknown.
|
||||
*/
|
||||
deprecated class KindViolation extends TypeViolation {
|
||||
KindViolation() {
|
||||
count(typeKind(this.getType())) != 1 and
|
||||
exists(this.getType().getLocation())
|
||||
}
|
||||
|
||||
override string getMessage() {
|
||||
result = "Invalid kinds on type: " + concat(typeKind(this.getType()), " ")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The type of a kind must be consistent between a constructed generic and its
|
||||
* unbound generic.
|
||||
*/
|
||||
deprecated class InconsistentKind extends TypeViolation {
|
||||
InconsistentKind() {
|
||||
typeKind(this.getType()) != typeKind(this.getType().getUnboundDeclaration())
|
||||
}
|
||||
|
||||
override string getMessage() { result = "Inconsistent type kind of source declaration" }
|
||||
}
|
||||
|
||||
deprecated private string typeKind(Type t) {
|
||||
t instanceof Interface and result = "interface"
|
||||
or
|
||||
t instanceof Class and result = "class"
|
||||
or
|
||||
t instanceof TypeParameter and result = "type parameter"
|
||||
or
|
||||
t instanceof ArrayType and result = "array"
|
||||
or
|
||||
t instanceof PointerType and result = "pointer"
|
||||
}
|
||||
|
||||
/**
|
||||
* A violation in a `Member`.
|
||||
*/
|
||||
abstract deprecated class DeclarationViolation extends ConsistencyViolation, DeclarationCheck {
|
||||
abstract override string getMessage();
|
||||
|
||||
/** Gets the member containing the potential violation. */
|
||||
Declaration getDeclaration() { this = DeclarationCheck(result) }
|
||||
|
||||
override string toString() { result = this.getDeclaration().toString() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Properties that have no accessors.
|
||||
*/
|
||||
deprecated class PropertyWithNoAccessors extends DeclarationViolation {
|
||||
PropertyWithNoAccessors() {
|
||||
exists(Property p | p = this.getDeclaration() | not exists(p.getAnAccessor()))
|
||||
}
|
||||
|
||||
override string getMessage() { result = "Property has no accessors" }
|
||||
}
|
||||
|
||||
/**
|
||||
* An expression that have an unexpected push count.
|
||||
*/
|
||||
deprecated class ExprPushCount extends InstructionViolation {
|
||||
ExprPushCount() {
|
||||
instruction instanceof Expr and
|
||||
not instruction instanceof Opcodes::Dup and
|
||||
if instruction instanceof Call
|
||||
then not instruction.getPushCount() in [0 .. 1]
|
||||
else instruction.(Expr).getPushCount() != 1
|
||||
}
|
||||
|
||||
override string getMessage() {
|
||||
result = "Instruction has unexpected push count " + instruction.getPushCount()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An expression that does not have exactly one type.
|
||||
* Note that calls with no return have type `System.Void`.
|
||||
*/
|
||||
deprecated class ExprMissingType extends InstructionViolation {
|
||||
ExprMissingType() {
|
||||
// Don't have types for the following op codes:
|
||||
not instruction instanceof Opcodes::Ldftn and
|
||||
not instruction instanceof Opcodes::Localloc and
|
||||
not instruction instanceof Opcodes::Ldvirtftn and
|
||||
not instruction instanceof Opcodes::Arglist and
|
||||
not instruction instanceof Opcodes::Refanytype and
|
||||
instruction.getPushCount() >= 1 and
|
||||
count(instruction.getType()) != 1 and
|
||||
// OS specific (osx) specific inconsistency
|
||||
not instruction
|
||||
.getImplementation()
|
||||
.getMethod()
|
||||
.hasFullyQualifiedName("System.Runtime.InteropServices.RuntimeInformation",
|
||||
"get_OSDescription")
|
||||
}
|
||||
|
||||
override string getMessage() { result = "Expression is missing getType()" }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that has a push count of 0, yet is still used as an operand
|
||||
*/
|
||||
deprecated class InvalidExpressionViolation extends InstructionViolation {
|
||||
InvalidExpressionViolation() {
|
||||
instruction.getPushCount() = 0 and
|
||||
exists(Instruction expr | instruction = expr.getAnOperand())
|
||||
}
|
||||
|
||||
override string getMessage() {
|
||||
result = "This instruction is used as an operand but pushes no values"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A type that has multiple entities with the same qualified name in `System`.
|
||||
* .NET Core does sometimes duplicate types, so this check is disabled.
|
||||
*/
|
||||
deprecated class TypeMultiplyDefined extends TypeViolation, DisabledCheck {
|
||||
TypeMultiplyDefined() {
|
||||
this.getType().getParent().getName() = "System" and
|
||||
not this.getType() instanceof ConstructedGeneric and
|
||||
not this.getType() instanceof ArrayType and
|
||||
this.getType().isPublic() and
|
||||
count(Type t |
|
||||
not t instanceof ConstructedGeneric and
|
||||
t.toStringWithTypes() = this.getType().toStringWithTypes()
|
||||
) != 1
|
||||
}
|
||||
|
||||
override string getMessage() {
|
||||
result =
|
||||
"This type (" + this.getType().toStringWithTypes() + ") has " +
|
||||
count(Type t |
|
||||
not t instanceof ConstructedGeneric and
|
||||
t.toStringWithTypes() = this.getType().toStringWithTypes()
|
||||
) + " entities"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A C# declaration which is expected to have a corresponding CIL declaration, but for some reason does not.
|
||||
*/
|
||||
deprecated class MissingCilDeclaration extends ConsistencyViolation, MissingCSharpCheck {
|
||||
MissingCilDeclaration() {
|
||||
exists(CS::Declaration decl | this = MissingCSharpCheck(decl) |
|
||||
expectedCilDeclaration(decl) and
|
||||
not exists(Declaration d | decl = d.getCSharpDeclaration())
|
||||
)
|
||||
}
|
||||
|
||||
CS::Declaration getDeclaration() { this = MissingCSharpCheck(result) }
|
||||
|
||||
override string getMessage() {
|
||||
result =
|
||||
"Cannot locate CIL for " + this.getDeclaration().toStringWithTypes() + " of class " +
|
||||
this.getDeclaration().getPrimaryQlClasses()
|
||||
}
|
||||
|
||||
override string toString() { result = this.getDeclaration().toStringWithTypes() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the C# declaration is expected to have a CIl declaration.
|
||||
*/
|
||||
deprecated private predicate expectedCilDeclaration(CS::Declaration decl) {
|
||||
decl = decl.getUnboundDeclaration() and
|
||||
not decl instanceof CS::ArrayType and
|
||||
decl.getALocation() instanceof CS::Assembly and
|
||||
not decl.(CS::Modifiable).isInternal() and
|
||||
not decl.(CS::Constructor).getNumberOfParameters() = 0 and // These are sometimes implicit
|
||||
not decl.(CS::Method).getReturnType() instanceof CS::UnknownType and
|
||||
not exists(CS::Parameter p | p = decl.(CS::Parameterizable).getAParameter() |
|
||||
not expectedCilDeclaration(p)
|
||||
) and
|
||||
not decl instanceof CS::AnonymousClass and
|
||||
(decl instanceof CS::Parameter implies expectedCilDeclaration(decl.(CS::Parameter).getType())) and
|
||||
(decl instanceof CS::Parameter implies expectedCilDeclaration(decl.getParent())) and
|
||||
(decl instanceof CS::Member implies expectedCilDeclaration(decl.getParent())) and
|
||||
(
|
||||
decl instanceof CS::Field
|
||||
or
|
||||
decl instanceof CS::Property
|
||||
or
|
||||
decl instanceof CS::ValueOrRefType
|
||||
or
|
||||
decl instanceof CS::Event
|
||||
or
|
||||
decl instanceof CS::Constructor
|
||||
or
|
||||
decl instanceof CS::Destructor
|
||||
or
|
||||
decl instanceof CS::Operator
|
||||
or
|
||||
decl instanceof CS::Method
|
||||
or
|
||||
decl instanceof CS::Parameter
|
||||
)
|
||||
}
|
||||
|
||||
/** A member with an invalid name. */
|
||||
deprecated class MemberWithInvalidName extends DeclarationViolation {
|
||||
MemberWithInvalidName() {
|
||||
exists(string name | name = this.getDeclaration().(Member).getName() |
|
||||
exists(name.indexOf(".")) and
|
||||
not name = ".ctor" and
|
||||
not name = ".cctor"
|
||||
)
|
||||
}
|
||||
|
||||
override string getMessage() {
|
||||
result = "Invalid name " + this.getDeclaration().(Member).getName()
|
||||
}
|
||||
}
|
||||
|
||||
deprecated class ConstructedSourceDeclarationMethod extends MethodViolation {
|
||||
Method method;
|
||||
|
||||
ConstructedSourceDeclarationMethod() {
|
||||
method = this.getMethod() and
|
||||
method = method.getUnboundDeclaration() and
|
||||
(
|
||||
method instanceof ConstructedGeneric or
|
||||
method.getDeclaringType() instanceof ConstructedGeneric
|
||||
)
|
||||
}
|
||||
|
||||
override string getMessage() {
|
||||
result = "Source declaration " + method.toStringWithTypes() + " is constructed"
|
||||
}
|
||||
}
|
||||
|
||||
/** A declaration with multiple labels. */
|
||||
deprecated class DeclarationWithMultipleLabels extends DeclarationViolation {
|
||||
DeclarationWithMultipleLabels() {
|
||||
exists(Declaration d | this = DeclarationCheck(d) | strictcount(d.getLabel()) > 1)
|
||||
}
|
||||
|
||||
override string getMessage() {
|
||||
result = "Multiple labels " + concat(this.getDeclaration().getLabel(), ", ")
|
||||
}
|
||||
}
|
||||
|
||||
/** A declaration without a label. */
|
||||
deprecated class DeclarationWithoutLabel extends DeclarationViolation {
|
||||
DeclarationWithoutLabel() {
|
||||
exists(Declaration d | this = DeclarationCheck(d) |
|
||||
d.isUnboundDeclaration() and
|
||||
not d instanceof TypeParameter and
|
||||
not exists(d.getLabel()) and
|
||||
(d instanceof Callable or d instanceof Type)
|
||||
)
|
||||
}
|
||||
|
||||
override string getMessage() { result = "No label" }
|
||||
}
|
||||
@@ -1,179 +0,0 @@
|
||||
/**
|
||||
* Provides classes for control flow.
|
||||
*/
|
||||
|
||||
private import CIL
|
||||
|
||||
/** A node in the control flow graph. */
|
||||
deprecated class ControlFlowNode extends @cil_controlflow_node {
|
||||
/** Gets a textual representation of this control flow node. */
|
||||
string toString() { none() }
|
||||
|
||||
/** Gets the location of this control flow node. */
|
||||
Location getLocation() { none() }
|
||||
|
||||
/**
|
||||
* Gets the number of items this node pushes onto the stack.
|
||||
* This value is either 0 or 1, except for the instruction `dup`
|
||||
* which pushes 2 values onto the stack.
|
||||
*/
|
||||
int getPushCount() { result = 0 }
|
||||
|
||||
/** Gets the number of items this node pops from the stack. */
|
||||
int getPopCount() { result = 0 }
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final Instruction getASuccessor() { result = this.getASuccessorType(_) }
|
||||
|
||||
/** Gets a true successor of this node, if any. */
|
||||
final Instruction getTrueSuccessor() { result = this.getASuccessorType(any(TrueFlow f)) }
|
||||
|
||||
/** Gets a false successor of this node, if any. */
|
||||
final Instruction getFalseSuccessor() { result = this.getASuccessorType(any(FalseFlow f)) }
|
||||
|
||||
/** Gets a successor to this node, of type `type`, if any. */
|
||||
cached
|
||||
Instruction getASuccessorType(FlowType t) { none() }
|
||||
|
||||
/** Gets a predecessor of this node, if any. */
|
||||
ControlFlowNode getAPredecessor() { result.getASuccessor() = this }
|
||||
|
||||
/**
|
||||
* Gets an instruction that supplies the `i`th operand to this instruction.
|
||||
* Note that this can be multi-valued.
|
||||
*/
|
||||
cached
|
||||
ControlFlowNode getOperand(int i) {
|
||||
// Immediate predecessor pushes the operand
|
||||
i in [0 .. this.getPopCount() - 1] and
|
||||
result = this.getAPredecessor() and
|
||||
i < result.getPushCount()
|
||||
or
|
||||
// Transitive predecessor pushes the operand
|
||||
exists(ControlFlowNode mid, int pushes | this.getOperandRec(mid, i, pushes) |
|
||||
pushes - mid.getStackDelta() < result.getPushCount() and
|
||||
result = mid.getAPredecessor()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of the `i`th operand. Unlike `getOperand(i).getType()`, this
|
||||
* predicate takes into account when there are multiple possible operands with
|
||||
* different types.
|
||||
*/
|
||||
Type getOperandType(int i) {
|
||||
strictcount(this.getOperand(i)) = 1 and
|
||||
result = this.getOperand(i).getType()
|
||||
or
|
||||
strictcount(this.getOperand(i)) = 2 and
|
||||
exists(ControlFlowNode op1, ControlFlowNode op2, Type t2 |
|
||||
op1 = this.getOperand(i) and
|
||||
op2 = this.getOperand(i) and
|
||||
op1 != op2 and
|
||||
result = op1.getType() and
|
||||
t2 = op2.getType()
|
||||
|
|
||||
result = t2
|
||||
or
|
||||
result.(PrimitiveType).getUnderlyingType().getConversionIndex() >
|
||||
t2.(PrimitiveType).getUnderlyingType().getConversionIndex()
|
||||
or
|
||||
op2 instanceof NullLiteral
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets an operand of this instruction, if any. */
|
||||
ControlFlowNode getAnOperand() { result = this.getOperand(_) }
|
||||
|
||||
/** Gets an expression that consumes the output of this instruction on the stack. */
|
||||
Instruction getParentExpr() { this = result.getAnOperand() }
|
||||
|
||||
/**
|
||||
* Holds if `pred` is a transitive predecessor of this instruction, this
|
||||
* instruction pops operand `i`, `pushes` additional pushes are required
|
||||
* for operand `i` at node `pred`, and no instruction between (and including)
|
||||
* `pred` and this instruction is a push for operand `i`.
|
||||
*/
|
||||
private predicate getOperandRec(ControlFlowNode pred, int i, int pushes) {
|
||||
// Invariant: no node is a push for operand `i`
|
||||
pushes >= pred.getPushCount() and
|
||||
(
|
||||
i in [0 .. this.getPopCount() - 1] and
|
||||
pred = this.getAPredecessor() and
|
||||
pushes = i
|
||||
or
|
||||
exists(ControlFlowNode mid, int pushes0 | this.getOperandRec(mid, i, pushes0) |
|
||||
pushes = pushes0 - mid.getStackDelta() and
|
||||
// This is a guard to prevent ill formed programs
|
||||
// and other logic errors going into an infinite loop.
|
||||
pushes <= this.getImplementation().getStackSize() and
|
||||
pred = mid.getAPredecessor()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private int getStackDelta() { result = this.getPushCount() - this.getPopCount() }
|
||||
|
||||
/** Gets the stack size before this instruction. */
|
||||
int getStackSizeBefore() { result = this.getAPredecessor().getStackSizeAfter() }
|
||||
|
||||
/** Gets the stack size after this instruction. */
|
||||
final int getStackSizeAfter() {
|
||||
// This is a guard to prevent ill formed programs
|
||||
// and other logic errors going into an infinite loop.
|
||||
result in [0 .. this.getImplementation().getStackSize()] and
|
||||
result = this.getStackSizeBefore() + this.getStackDelta()
|
||||
}
|
||||
|
||||
/** Gets the method containing this control flow node. */
|
||||
MethodImplementation getImplementation() { none() }
|
||||
|
||||
/**
|
||||
* Gets the type of the item pushed onto the stack, if any.
|
||||
*
|
||||
* If called via `ControlFlowNode::getOperand(i).getType()`, consider using
|
||||
* `ControlFlowNode::getOperandType(i)` instead.
|
||||
*/
|
||||
cached
|
||||
Type getType() { none() }
|
||||
|
||||
/** Holds if this control flow node has more than one predecessor. */
|
||||
predicate isJoin() { strictcount(this.getAPredecessor()) > 1 }
|
||||
|
||||
/** Holds if this control flow node has more than one successor. */
|
||||
predicate isBranch() { strictcount(this.getASuccessor()) > 1 }
|
||||
}
|
||||
|
||||
/**
|
||||
* A control flow entry point. Either a method (`MethodImplementation`) or a handler (`Handler`).
|
||||
*
|
||||
* Handlers are control flow nodes because they push the handled exception onto the stack.
|
||||
*/
|
||||
deprecated class EntryPoint extends ControlFlowNode, @cil_entry_point {
|
||||
override int getStackSizeBefore() { result = 0 }
|
||||
}
|
||||
|
||||
deprecated private newtype TFlowType =
|
||||
TNormalFlow() or
|
||||
TTrueFlow() or
|
||||
TFalseFlow()
|
||||
|
||||
/** A type of control flow. Either normal flow (`NormalFlow`), true flow (`TrueFlow`) or false flow (`FalseFlow`). */
|
||||
abstract deprecated class FlowType extends TFlowType {
|
||||
abstract string toString();
|
||||
}
|
||||
|
||||
/** Normal control flow. */
|
||||
deprecated class NormalFlow extends FlowType, TNormalFlow {
|
||||
override string toString() { result = "" }
|
||||
}
|
||||
|
||||
/** True control flow. */
|
||||
deprecated class TrueFlow extends FlowType, TTrueFlow {
|
||||
override string toString() { result = "true" }
|
||||
}
|
||||
|
||||
/** False control flow. */
|
||||
deprecated class FalseFlow extends FlowType, TFalseFlow {
|
||||
override string toString() { result = "false" }
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
/**
|
||||
* Provides a class to represent `modopt` and `modreq` declarations.
|
||||
*/
|
||||
|
||||
private import CIL
|
||||
private import dotnet
|
||||
|
||||
/**
|
||||
* A class to represent entities that can receive custom modifiers. Custom modifiers can be attached to
|
||||
* - the type of a `Field`,
|
||||
* - the return type of a `Method` or `Property`,
|
||||
* - the type of parameters.
|
||||
* A `CustomModifierReceiver` is therefore either a `Field`, `Property`, `Method`, or `Parameter`.
|
||||
*/
|
||||
deprecated class CustomModifierReceiver extends Declaration, @cil_custom_modifier_receiver {
|
||||
/** Holds if this targeted type has `modifier` applied as `modreq`. */
|
||||
predicate hasRequiredCustomModifier(Type modifier) { cil_custom_modifiers(this, modifier, 1) }
|
||||
|
||||
/** Holds if this targeted type has `modifier` applied as `modopt`. */
|
||||
predicate hasOptionalCustomModifier(Type modifier) { cil_custom_modifiers(this, modifier, 0) }
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
/**
|
||||
* Provides a collection of building blocks and utilities for data flow.
|
||||
*/
|
||||
|
||||
private import CIL
|
||||
|
||||
/**
|
||||
* A node in the data flow graph.
|
||||
*
|
||||
* Either an instruction (`Instruction`), a method return (`Method`), or a variable (`Variable`).
|
||||
*/
|
||||
deprecated class DataFlowNode extends @cil_dataflow_node {
|
||||
/** Gets a textual representation of this data flow node. */
|
||||
abstract string toString();
|
||||
|
||||
/** Gets the type of this data flow node. */
|
||||
Type getType() { none() }
|
||||
|
||||
/** Gets the method that contains this dataflow node. */
|
||||
Method getMethod() { none() }
|
||||
|
||||
/** Gets the location of this dataflow node. */
|
||||
Location getLocation() { none() }
|
||||
}
|
||||
|
||||
/** A node that updates a variable. */
|
||||
abstract deprecated class VariableUpdate extends DataFlowNode {
|
||||
/** Gets the value assigned, if any. */
|
||||
abstract DataFlowNode getSource();
|
||||
|
||||
/** Gets the variable that is updated. */
|
||||
abstract Variable getVariable();
|
||||
|
||||
/** Holds if this variable update happens at index `i` in basic block `bb`. */
|
||||
abstract predicate updatesAt(BasicBlock bb, int i);
|
||||
}
|
||||
|
||||
deprecated private class MethodParameterDef extends VariableUpdate, MethodParameter {
|
||||
override MethodParameter getSource() { result = this }
|
||||
|
||||
override MethodParameter getVariable() { result = this }
|
||||
|
||||
override predicate updatesAt(BasicBlock bb, int i) {
|
||||
bb.(EntryBasicBlock).getANode().getImplementation().getMethod() = this.getMethod() and
|
||||
i = -1
|
||||
}
|
||||
}
|
||||
|
||||
deprecated private class VariableWrite extends VariableUpdate, WriteAccess {
|
||||
override Expr getSource() { result = this.getExpr() }
|
||||
|
||||
override Variable getVariable() { result = this.getTarget() }
|
||||
|
||||
override predicate updatesAt(BasicBlock bb, int i) { this = bb.getNode(i) }
|
||||
}
|
||||
|
||||
deprecated private class MethodOutOrRefTarget extends VariableUpdate, Call {
|
||||
int parameterIndex;
|
||||
|
||||
MethodOutOrRefTarget() { this.getTarget().getRawParameter(parameterIndex).hasOutFlag() }
|
||||
|
||||
override Variable getVariable() {
|
||||
result = this.getRawArgument(parameterIndex).(ReadAccess).getTarget()
|
||||
}
|
||||
|
||||
override Expr getSource() { none() }
|
||||
|
||||
override predicate updatesAt(BasicBlock bb, int i) { this = bb.getNode(i) }
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
/**
|
||||
* Provides classes for declarations and members.
|
||||
*/
|
||||
|
||||
import CIL
|
||||
private import dotnet
|
||||
private import semmle.code.csharp.Member as CS
|
||||
private import semmle.code.csharp.commons.QualifiedName
|
||||
|
||||
/**
|
||||
* A declaration. Either a member (`Member`) or a variable (`Variable`).
|
||||
*/
|
||||
deprecated class Declaration extends DotNet::Declaration, Element, @cil_declaration {
|
||||
/** Gets an attribute (for example `[Obsolete]`) of this declaration, if any. */
|
||||
Attribute getAnAttribute() { result.getDeclaration() = this }
|
||||
|
||||
/**
|
||||
* Gets the C# declaration corresponding to this CIL declaration, if any.
|
||||
* Note that this is only for source/unconstructed declarations.
|
||||
*/
|
||||
CS::Declaration getCSharpDeclaration() {
|
||||
result = toCSharpNonTypeParameter(this) or
|
||||
result = toCSharpTypeParameter(this)
|
||||
}
|
||||
|
||||
override Declaration getUnboundDeclaration() { result = this }
|
||||
|
||||
deprecated override predicate hasQualifiedName(string qualifier, string name) {
|
||||
exists(string dqualifier, string dname |
|
||||
this.getDeclaringType().hasQualifiedName(dqualifier, dname) and
|
||||
qualifier = getQualifiedName(dqualifier, dname)
|
||||
) and
|
||||
name = this.getName()
|
||||
}
|
||||
|
||||
override predicate hasFullyQualifiedName(string qualifier, string name) {
|
||||
exists(string dqualifier, string dname |
|
||||
this.getDeclaringType().hasFullyQualifiedName(dqualifier, dname) and
|
||||
qualifier = getQualifiedName(dqualifier, dname)
|
||||
) and
|
||||
name = this.getName()
|
||||
}
|
||||
}
|
||||
|
||||
deprecated private CS::Declaration toCSharpNonTypeParameter(Declaration d) {
|
||||
result.(DotNet::Declaration).matchesHandle(d)
|
||||
}
|
||||
|
||||
deprecated private CS::TypeParameter toCSharpTypeParameter(TypeParameter tp) {
|
||||
toCSharpTypeParameterJoin(tp, result.getIndex(), result.getGeneric())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
deprecated private predicate toCSharpTypeParameterJoin(
|
||||
TypeParameter tp, int i, CS::UnboundGeneric ug
|
||||
) {
|
||||
exists(TypeContainer tc |
|
||||
tp.getIndex() = i and
|
||||
tc = tp.getGeneric() and
|
||||
ug = toCSharpNonTypeParameter(tc)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A member of a type. Either a type (`Type`), a method (`Method`), a property (`Property`), or an event (`Event`).
|
||||
*/
|
||||
deprecated class Member extends DotNet::Member, Declaration, @cil_member {
|
||||
override predicate isPublic() { cil_public(this) }
|
||||
|
||||
override predicate isProtected() { cil_protected(this) }
|
||||
|
||||
override predicate isPrivate() { cil_private(this) }
|
||||
|
||||
override predicate isInternal() { cil_internal(this) }
|
||||
|
||||
override predicate isSealed() { cil_sealed(this) }
|
||||
|
||||
override predicate isAbstract() { cil_abstract(this) }
|
||||
|
||||
override predicate isStatic() { cil_static(this) }
|
||||
|
||||
/** Holds if this member has a security attribute. */
|
||||
predicate hasSecurity() { cil_security(this) }
|
||||
|
||||
override Location getLocation() { result = this.getDeclaringType().getLocation() }
|
||||
}
|
||||
|
||||
/** A property. */
|
||||
deprecated class Property extends DotNet::Property, Member, CustomModifierReceiver, @cil_property {
|
||||
override string getName() { cil_property(this, _, result, _) }
|
||||
|
||||
/** Gets the type of this property. */
|
||||
override Type getType() { cil_property(this, _, _, result) }
|
||||
|
||||
override ValueOrRefType getDeclaringType() { cil_property(this, result, _, _) }
|
||||
|
||||
/** Gets the getter of this property, if any. */
|
||||
override Getter getGetter() { this = result.getProperty() }
|
||||
|
||||
/** Gets the setter of this property, if any. */
|
||||
override Setter getSetter() { this = result.getProperty() }
|
||||
|
||||
/** Gets an accessor of this property. */
|
||||
Accessor getAnAccessor() { result = this.getGetter() or result = this.getSetter() }
|
||||
|
||||
override string toString() { result = "property " + this.getName() }
|
||||
|
||||
override string toStringWithTypes() {
|
||||
result =
|
||||
this.getType().toStringWithTypes() + " " + this.getDeclaringType().toStringWithTypes() + "." +
|
||||
this.getName()
|
||||
}
|
||||
}
|
||||
|
||||
/** A property that is trivial (wraps a field). */
|
||||
deprecated class TrivialProperty extends Property {
|
||||
TrivialProperty() {
|
||||
this.getGetter().(TrivialGetter).getField() = this.getSetter().(TrivialSetter).getField()
|
||||
}
|
||||
|
||||
/** Gets the underlying field of this property. */
|
||||
Field getField() { result = this.getGetter().(TrivialGetter).getField() }
|
||||
}
|
||||
|
||||
/** An event. */
|
||||
deprecated class Event extends DotNet::Event, Member, @cil_event {
|
||||
override string getName() { cil_event(this, _, result, _) }
|
||||
|
||||
/** Gets the type of this event. */
|
||||
Type getType() { cil_event(this, _, _, result) }
|
||||
|
||||
override ValueOrRefType getDeclaringType() { cil_event(this, result, _, _) }
|
||||
|
||||
/** Gets the add event accessor. */
|
||||
Method getAddEventAccessor() { cil_adder(this, result) }
|
||||
|
||||
/** Gets the remove event accessor. */
|
||||
Method getRemoveEventAccessor() { cil_remover(this, result) }
|
||||
|
||||
/** Gets the raiser. */
|
||||
Method getRaiser() { cil_raiser(this, result) }
|
||||
|
||||
override string toString() { result = "event " + this.getName() }
|
||||
|
||||
override string toStringWithTypes() {
|
||||
result = this.getDeclaringType().toStringWithTypes() + "." + this.getName()
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
/** Provides the `Element` class, the base class of all CIL program elements. */
|
||||
|
||||
private import dotnet
|
||||
import semmle.code.csharp.Location
|
||||
|
||||
/** An element. */
|
||||
deprecated class Element extends DotNet::Element, @cil_element {
|
||||
override Location getLocation() { result = bestLocation(this) }
|
||||
}
|
||||
|
||||
cached
|
||||
deprecated private Location bestLocation(Element e) {
|
||||
result = e.getALocation() and
|
||||
(e.getALocation().getFile().isPdbSourceFile() implies result.getFile().isPdbSourceFile())
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
/** Provides classes for generic types and methods. */
|
||||
|
||||
private import CIL
|
||||
private import dotnet
|
||||
|
||||
/**
|
||||
* A generic declaration. Either an unbound generic (`UnboundGeneric`) or a
|
||||
* constructed generic (`ConstructedGeneric`).
|
||||
*/
|
||||
deprecated class Generic extends DotNet::Generic, Declaration, TypeContainer {
|
||||
Generic() {
|
||||
cil_type_parameter(this, _, _) or
|
||||
cil_type_argument(this, _, _)
|
||||
}
|
||||
}
|
||||
|
||||
/** An unbound generic type or method. */
|
||||
deprecated class UnboundGeneric extends Generic, DotNet::UnboundGeneric {
|
||||
UnboundGeneric() { cil_type_parameter(this, _, _) }
|
||||
|
||||
final override TypeParameter getTypeParameter(int n) { cil_type_parameter(this, n, result) }
|
||||
}
|
||||
|
||||
/** A constructed generic type or method. */
|
||||
deprecated class ConstructedGeneric extends Generic, DotNet::ConstructedGeneric {
|
||||
ConstructedGeneric() { cil_type_argument(this, _, _) }
|
||||
|
||||
final override Type getTypeArgument(int n) { cil_type_argument(this, n, result) }
|
||||
}
|
||||
|
||||
/** Gets the concatenation of the `getName()` of type arguments. */
|
||||
language[monotonicAggregates]
|
||||
deprecated private string getTypeArgumentsNames(ConstructedGeneric cg) {
|
||||
result = strictconcat(Type t, int i | t = cg.getTypeArgument(i) | t.getName(), "," order by i)
|
||||
}
|
||||
|
||||
/** An unbound generic type. */
|
||||
deprecated class UnboundGenericType extends UnboundGeneric, Type { }
|
||||
|
||||
/** An unbound generic method. */
|
||||
deprecated class UnboundGenericMethod extends UnboundGeneric, Method { }
|
||||
|
||||
/** A constructed generic type. */
|
||||
deprecated class ConstructedType extends ConstructedGeneric, Type {
|
||||
final override UnboundGenericType getUnboundGeneric() { result = this.getUnboundType() }
|
||||
|
||||
override predicate isInterface() { this.getUnboundType().isInterface() }
|
||||
|
||||
override predicate isClass() { this.getUnboundType().isClass() }
|
||||
|
||||
final override string getName() {
|
||||
result = this.getUndecoratedName() + "<" + getTypeArgumentsNames(this) + ">"
|
||||
}
|
||||
}
|
||||
|
||||
/** A constructed generic method. */
|
||||
deprecated class ConstructedMethod extends ConstructedGeneric, Method {
|
||||
final override UnboundGenericMethod getUnboundGeneric() { result = this.getUnboundMethod() }
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
/**
|
||||
* Provides classes for different types of handler.
|
||||
*/
|
||||
|
||||
private import CIL
|
||||
|
||||
/**
|
||||
* A handler is a piece of code that can be executed out of sequence, for example
|
||||
* when an instruction generates an exception or leaves a `finally` block.
|
||||
*
|
||||
* Each handler has a scope representing the block of instructions guarded by
|
||||
* this handler (corresponding to a C# `try { ... }` block), and a block of instructions
|
||||
* to execute when the handler is triggered (corresponding to a `catch` or `finally` block).
|
||||
*
|
||||
* Handlers are entry points (`EntryPoint`) so that they can
|
||||
* provide values on the stack, for example the value of the current exception. This is why
|
||||
* some handlers have a push count of 1.
|
||||
*
|
||||
* Either a finally handler (`FinallyHandler`), filter handler (`FilterHandler`),
|
||||
* catch handler (`CatchHandler`), or a fault handler (`FaultHandler`).
|
||||
*/
|
||||
deprecated class Handler extends Element, EntryPoint, @cil_handler {
|
||||
override MethodImplementation getImplementation() { cil_handler(this, result, _, _, _, _, _) }
|
||||
|
||||
/** Gets the 0-based index of this handler. Handlers are evaluated in this sequence. */
|
||||
int getIndex() { cil_handler(this, _, result, _, _, _, _) }
|
||||
|
||||
/** Gets the first instruction in the `try` block of this handler. */
|
||||
Instruction getTryStart() { cil_handler(this, _, _, _, result, _, _) }
|
||||
|
||||
/** Gets the last instruction in the `try` block of this handler. */
|
||||
Instruction getTryEnd() { cil_handler(this, _, _, _, _, result, _) }
|
||||
|
||||
/** Gets the first instruction in the `catch`/`finally` block. */
|
||||
Instruction getHandlerStart() { cil_handler(this, _, _, _, _, _, result) }
|
||||
|
||||
/**
|
||||
* Holds if the instruction `i` is in the scope of this handler.
|
||||
*/
|
||||
predicate isInScope(Instruction i) {
|
||||
i.getImplementation() = this.getImplementation() and
|
||||
i.getIndex() in [this.getTryStart().getIndex() .. this.getTryEnd().getIndex()]
|
||||
}
|
||||
|
||||
override string toString() { none() }
|
||||
|
||||
override Instruction getASuccessorType(FlowType t) {
|
||||
result = this.getHandlerStart() and
|
||||
t instanceof NormalFlow
|
||||
}
|
||||
|
||||
/** Gets the type of the caught exception, if any. */
|
||||
Type getCaughtType() { cil_handler_type(this, result) }
|
||||
|
||||
override Location getLocation() { result = this.getTryStart().getLocation() }
|
||||
}
|
||||
|
||||
/** A handler corresponding to a `finally` block. */
|
||||
deprecated class FinallyHandler extends Handler, @cil_finally_handler {
|
||||
override string toString() { result = "finally {...}" }
|
||||
}
|
||||
|
||||
/** A handler corresponding to a `where()` clause. */
|
||||
deprecated class FilterHandler extends Handler, @cil_filter_handler {
|
||||
override string toString() { result = "where (...)" }
|
||||
|
||||
/** Gets the filter clause - the start of a sequence of instructions to evaluate the filter function. */
|
||||
Instruction getFilterClause() { cil_handler_filter(this, result) }
|
||||
|
||||
override int getPushCount() { result = 1 }
|
||||
}
|
||||
|
||||
/** A handler corresponding to a `catch` clause. */
|
||||
deprecated class CatchHandler extends Handler, @cil_catch_handler {
|
||||
override string toString() { result = "catch(" + this.getCaughtType().getName() + ") {...}" }
|
||||
|
||||
override int getPushCount() { result = 1 }
|
||||
}
|
||||
|
||||
/** A handler for memory faults. */
|
||||
deprecated class FaultHandler extends Handler, @cil_fault_handler {
|
||||
override string toString() { result = "fault {...}" }
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
/** Provides the `Instruction` class. */
|
||||
|
||||
private import CIL
|
||||
|
||||
/** An instruction. */
|
||||
deprecated class Instruction extends Element, ControlFlowNode, DataFlowNode, @cil_instruction {
|
||||
override string toString() { result = this.getOpcodeName() }
|
||||
|
||||
/** Gets a more verbose textual representation of this instruction. */
|
||||
string toStringExtra() {
|
||||
result = this.getIndex() + ": " + this.getOpcodeName() + this.getExtraStr()
|
||||
}
|
||||
|
||||
/** Gets the method containing this instruction. */
|
||||
override MethodImplementation getImplementation() { cil_instruction(this, _, _, result) }
|
||||
|
||||
override Method getMethod() { result = this.getImplementation().getMethod() }
|
||||
|
||||
/**
|
||||
* Gets the index of this instruction.
|
||||
* Instructions are sequenced from 0.
|
||||
*/
|
||||
int getIndex() { cil_instruction(this, _, result, _) }
|
||||
|
||||
/** Gets the opcode of this instruction. */
|
||||
final int getOpcode() { cil_instruction(this, result, _, _) }
|
||||
|
||||
/** Gets the opcode name of this instruction, for example `ldnull`. */
|
||||
string getOpcodeName() { none() }
|
||||
|
||||
/** Gets an extra field to display for this instruction, if any. */
|
||||
string getExtra() { none() }
|
||||
|
||||
private string getExtraStr() {
|
||||
if exists(this.getExtra()) then result = " " + this.getExtra() else result = ""
|
||||
}
|
||||
|
||||
/** Gets the declaration accessed by this instruction, if any. */
|
||||
Declaration getAccess() { cil_access(this, result) }
|
||||
|
||||
/** Gets a successor instruction to this instruction. */
|
||||
override Instruction getASuccessorType(FlowType t) {
|
||||
t instanceof NormalFlow and
|
||||
this.canFlowNext() and
|
||||
result = this.getImplementation().getInstruction(this.getIndex() + 1)
|
||||
}
|
||||
|
||||
/** Holds if this instruction passes control flow into the next instruction. */
|
||||
predicate canFlowNext() { any() }
|
||||
|
||||
/**
|
||||
* Gets the `i`th handler that applies to this instruction.
|
||||
* Indexed from 0.
|
||||
*/
|
||||
Handler getHandler(int i) {
|
||||
result.isInScope(this) and
|
||||
result.getIndex() =
|
||||
rank[i + 1](int hi | exists(Handler h | h.isInScope(this) and hi = h.getIndex()))
|
||||
}
|
||||
|
||||
override Type getType() { result = ControlFlowNode.super.getType() }
|
||||
|
||||
override Location getALocation() {
|
||||
cil_instruction_location(this, result) // The source code, if available
|
||||
or
|
||||
result = this.getImplementation().getLocation() // The containing assembly
|
||||
}
|
||||
|
||||
override Location getLocation() { result = Element.super.getLocation() }
|
||||
}
|
||||
@@ -1,263 +0,0 @@
|
||||
/**
|
||||
* Provides classes representing various classes of expression
|
||||
* and other instructions.
|
||||
*/
|
||||
|
||||
private import CIL
|
||||
private import dotnet
|
||||
|
||||
/**
|
||||
* An instruction that pushes a value onto the stack.
|
||||
*/
|
||||
deprecated class Expr extends DotNet::Expr, Instruction, @cil_expr {
|
||||
override int getPushCount() { result = 1 }
|
||||
|
||||
override Type getType() { result = Instruction.super.getType() }
|
||||
|
||||
override Method getEnclosingCallable() { result = this.getImplementation().getMethod() }
|
||||
|
||||
/**
|
||||
* The "parent" of a CIL expression is taken to be the instruction
|
||||
* that consumes the value pushed by this instruction.
|
||||
*/
|
||||
override Expr getParent() { this = result.getAnOperand() }
|
||||
}
|
||||
|
||||
/** An instruction that changes control flow. */
|
||||
deprecated class Branch extends Instruction, @cil_jump {
|
||||
/** Gets the instruction that is jumped to. */
|
||||
Instruction getTarget() { cil_jump(this, result) }
|
||||
|
||||
override string getExtra() { result = this.getTarget().getIndex() + ":" }
|
||||
}
|
||||
|
||||
/** An instruction that unconditionally jumps to another instruction. */
|
||||
deprecated class UnconditionalBranch extends Branch, @cil_unconditional_jump {
|
||||
override Instruction getASuccessorType(FlowType t) {
|
||||
t instanceof NormalFlow and result = this.getTarget()
|
||||
}
|
||||
|
||||
override predicate canFlowNext() { none() }
|
||||
}
|
||||
|
||||
/** An instruction that jumps to a target based on a condition. */
|
||||
deprecated class ConditionalBranch extends Branch, @cil_conditional_jump {
|
||||
override Instruction getASuccessorType(FlowType t) {
|
||||
t instanceof TrueFlow and result = this.getTarget()
|
||||
or
|
||||
t instanceof FalseFlow and result = this.getImplementation().getInstruction(this.getIndex() + 1)
|
||||
}
|
||||
|
||||
override int getPushCount() { result = 0 }
|
||||
}
|
||||
|
||||
/** An expression with two operands. */
|
||||
deprecated class BinaryExpr extends Expr, @cil_binary_expr {
|
||||
override int getPopCount() { result = 2 }
|
||||
}
|
||||
|
||||
/** An expression with one operand. */
|
||||
deprecated class UnaryExpr extends Expr, @cil_unary_expr {
|
||||
override int getPopCount() { result = 1 }
|
||||
|
||||
/** Gets the operand of this unary expression. */
|
||||
Expr getOperand() { result = this.getOperand(0) }
|
||||
}
|
||||
|
||||
/** A binary expression that compares two values. */
|
||||
deprecated class ComparisonOperation extends BinaryExpr, @cil_comparison_operation {
|
||||
override BoolType getType() { exists(result) }
|
||||
}
|
||||
|
||||
/** A binary arithmetic expression. */
|
||||
deprecated class BinaryArithmeticExpr extends BinaryExpr, @cil_binary_arithmetic_operation {
|
||||
override Type getType() {
|
||||
exists(Type t0, Type t1 |
|
||||
t0 = this.getOperandType(0).getUnderlyingType() and
|
||||
t1 = this.getOperandType(1).getUnderlyingType()
|
||||
|
|
||||
t0 = t1 and result = t0
|
||||
or
|
||||
t0.getConversionIndex() < t1.getConversionIndex() and result = t1
|
||||
or
|
||||
t0.getConversionIndex() > t1.getConversionIndex() and result = t0
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** A binary bitwise expression. */
|
||||
deprecated class BinaryBitwiseOperation extends BinaryExpr, @cil_binary_bitwise_operation {
|
||||
// This is wrong but efficient - should depend on the types of the operands.
|
||||
override IntType getType() { exists(result) }
|
||||
}
|
||||
|
||||
/** A unary bitwise expression. */
|
||||
deprecated class UnaryBitwiseOperation extends UnaryExpr, @cil_unary_bitwise_operation {
|
||||
// This is wrong but efficient - should depend on the types of the operands.
|
||||
override IntType getType() { exists(result) }
|
||||
}
|
||||
|
||||
/** A unary expression that converts a value from one primitive type to another. */
|
||||
deprecated class Conversion extends UnaryExpr, @cil_conversion_operation {
|
||||
/** Gets the expression being converted. */
|
||||
Expr getExpr() { result = this.getOperand(0) }
|
||||
}
|
||||
|
||||
/** A branch that leaves the scope of a `Handler`. */
|
||||
deprecated class Leave extends UnconditionalBranch, @cil_leave_any { }
|
||||
|
||||
/** An expression that pushes a literal value onto the stack. */
|
||||
deprecated class Literal extends DotNet::Literal, Expr, @cil_literal {
|
||||
/** Gets the pushed value. */
|
||||
override string getValue() { cil_value(this, result) }
|
||||
|
||||
override string getExtra() { result = this.getValue() }
|
||||
}
|
||||
|
||||
/** An integer literal. */
|
||||
deprecated class IntLiteral extends Literal, @cil_ldc_i {
|
||||
override string getExtra() { none() }
|
||||
|
||||
override IntType getType() { exists(result) }
|
||||
}
|
||||
|
||||
/** An expression that pushes a `float`/`Single`. */
|
||||
deprecated class FloatLiteral extends Literal, @cil_ldc_r { }
|
||||
|
||||
/** An expression that pushes a `null` value onto the stack. */
|
||||
deprecated class NullLiteral extends Literal, @cil_ldnull { }
|
||||
|
||||
/** An expression that pushes a string onto the stack. */
|
||||
deprecated class StringLiteral extends Literal, @cil_ldstr { }
|
||||
|
||||
/** A branch with one operand. */
|
||||
deprecated class UnaryBranch extends ConditionalBranch, @cil_unary_jump {
|
||||
override int getPopCount() { result = 1 }
|
||||
|
||||
override int getPushCount() { result = 0 }
|
||||
}
|
||||
|
||||
/** A branch with two operands. */
|
||||
deprecated class BinaryBranch extends ConditionalBranch, @cil_binary_jump {
|
||||
override int getPopCount() { result = 2 }
|
||||
|
||||
override int getPushCount() { result = 0 }
|
||||
}
|
||||
|
||||
/** A call. */
|
||||
deprecated class Call extends Expr, DotNet::Call, @cil_call_any {
|
||||
/** Gets the method that is called. */
|
||||
override Method getTarget() { cil_access(this, result) }
|
||||
|
||||
override Method getARuntimeTarget() { result = this.getTarget().getAnOverrider*() }
|
||||
|
||||
override string getExtra() { result = this.getTarget().getFullyQualifiedName() }
|
||||
|
||||
/**
|
||||
* Gets the return type of the call. Methods that do not return a value
|
||||
* return the `void` type, `System.Void`, although the value of `getPushCount` is
|
||||
* 0 in this case.
|
||||
*/
|
||||
override Type getType() { result = this.getTarget().getReturnType() }
|
||||
|
||||
// The number of items popped/pushed from the stack
|
||||
// depends on the target of the call.
|
||||
override int getPopCount() { result = this.getTarget().getCallPopCount() }
|
||||
|
||||
override int getPushCount() { result = this.getTarget().getCallPushCount() }
|
||||
|
||||
/**
|
||||
* Holds if this is a "tail call", meaning that control does not return to the
|
||||
* calling method.
|
||||
*/
|
||||
predicate isTailCall() {
|
||||
this.getImplementation().getInstruction(this.getIndex() - 1) instanceof Opcodes::Tail
|
||||
}
|
||||
|
||||
/** Holds if this call is virtual and could go to an overriding method. */
|
||||
predicate isVirtual() { none() }
|
||||
|
||||
override Expr getRawArgument(int i) { result = this.getOperand(this.getPopCount() - i - 1) }
|
||||
|
||||
/** Gets the qualifier of this call, if any. */
|
||||
Expr getQualifier() { result = this.getRawArgument(0) and not this.getTarget().isStatic() }
|
||||
|
||||
override Expr getArgument(int i) {
|
||||
if this.getTarget().isStatic()
|
||||
then result = this.getRawArgument(i)
|
||||
else (
|
||||
result = this.getRawArgument(i + 1) and i >= 0
|
||||
)
|
||||
}
|
||||
|
||||
override Expr getArgumentForParameter(DotNet::Parameter param) {
|
||||
exists(int index |
|
||||
result = this.getRawArgument(index) and param = this.getTarget().getRawParameter(index)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** A tail call. */
|
||||
deprecated class TailCall extends Call {
|
||||
TailCall() { this.isTailCall() }
|
||||
|
||||
override predicate canFlowNext() { none() }
|
||||
}
|
||||
|
||||
/** A call to a static target. */
|
||||
deprecated class StaticCall extends Call {
|
||||
StaticCall() { not this.isVirtual() }
|
||||
}
|
||||
|
||||
/** A call to a virtual target. */
|
||||
deprecated class VirtualCall extends Call {
|
||||
VirtualCall() { this.isVirtual() }
|
||||
}
|
||||
|
||||
/** A read of an array element. */
|
||||
deprecated class ReadArrayElement extends BinaryExpr, @cil_read_array {
|
||||
/** Gets the array being read. */
|
||||
Expr getArray() { result = this.getOperand(1) }
|
||||
|
||||
/** Gets the index into the array. */
|
||||
Expr getArrayIndex() { result = this.getOperand(0) }
|
||||
}
|
||||
|
||||
/** A write of an array element. */
|
||||
deprecated class WriteArrayElement extends Instruction, @cil_write_array {
|
||||
override int getPushCount() { result = 0 }
|
||||
|
||||
override int getPopCount() { result = 3 }
|
||||
}
|
||||
|
||||
/** A `return` statement. */
|
||||
deprecated class Return extends Instruction, @cil_ret {
|
||||
/** Gets the expression being returned, if any. */
|
||||
Expr getExpr() { result = this.getOperand(0) }
|
||||
|
||||
override predicate canFlowNext() { none() }
|
||||
}
|
||||
|
||||
/** A `throw` statement. */
|
||||
deprecated class Throw extends Instruction, DotNet::Throw, @cil_throw_any {
|
||||
override Expr getExpr() { result = this.getOperand(0) }
|
||||
|
||||
/** Gets the type of the exception being thrown. */
|
||||
Type getExceptionType() { result = this.getOperandType(0) }
|
||||
|
||||
override predicate canFlowNext() { none() }
|
||||
}
|
||||
|
||||
/** Stores a value at an address/location. */
|
||||
deprecated class StoreIndirect extends Instruction, @cil_stind {
|
||||
override int getPopCount() { result = 2 }
|
||||
|
||||
/** Gets the location to store the value at. */
|
||||
Expr getAddress() { result = this.getOperand(1) }
|
||||
|
||||
/** Gets the value to store. */
|
||||
Expr getExpr() { result = this.getOperand(0) }
|
||||
}
|
||||
|
||||
/** Loads a value from an address/location. */
|
||||
deprecated class LoadIndirect extends UnaryExpr, @cil_ldind { }
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,296 +0,0 @@
|
||||
/**
|
||||
* Provides classes for methods.
|
||||
*
|
||||
* Methods and implementations are different because there can be several implementations for the same
|
||||
* method in different assemblies. It is not really possible to guarantee which methods will be loaded
|
||||
* at run-time.
|
||||
*/
|
||||
|
||||
private import CIL
|
||||
private import dotnet
|
||||
|
||||
/**
|
||||
* An implementation of a method in an assembly.
|
||||
*/
|
||||
deprecated class MethodImplementation extends EntryPoint, @cil_method_implementation {
|
||||
/** Gets the method of this implementation. */
|
||||
Method getMethod() { cil_method_implementation(this, result, _) }
|
||||
|
||||
override MethodImplementation getImplementation() { result = this }
|
||||
|
||||
/** Gets the location of this implementation. */
|
||||
override Assembly getLocation() { cil_method_implementation(this, _, result) }
|
||||
|
||||
/** Gets the instruction at index `index`. */
|
||||
Instruction getInstruction(int index) { cil_instruction(result, _, index, this) }
|
||||
|
||||
/** Gets the `n`th local variable of this implementation. */
|
||||
LocalVariable getLocalVariable(int n) { cil_local_variable(result, this, n, _) }
|
||||
|
||||
/** Gets a local variable of this implementation, if any. */
|
||||
LocalVariable getALocalVariable() { result = this.getLocalVariable(_) }
|
||||
|
||||
/** Gets an instruction in this implementation, if any. */
|
||||
Instruction getAnInstruction() { result = this.getInstruction(_) }
|
||||
|
||||
/** Gets the total number of instructions in this implementation. */
|
||||
int getNumberOfInstructions() { result = count(this.getAnInstruction()) }
|
||||
|
||||
/** Gets the `i`th handler in this implementation. */
|
||||
Handler getHandler(int i) { result.getImplementation() = this and result.getIndex() = i }
|
||||
|
||||
/** Gets a handler in this implementation, if any. */
|
||||
Handler getAHandler() { result.getImplementation() = this }
|
||||
|
||||
override Instruction getASuccessorType(FlowType t) {
|
||||
t instanceof NormalFlow and result.getImplementation() = this and result.getIndex() = 0
|
||||
}
|
||||
|
||||
/** Gets the maximum stack size of this implementation. */
|
||||
int getStackSize() { cil_method_stack_size(this, result) }
|
||||
|
||||
override string toString() { result = this.getMethod().toString() }
|
||||
|
||||
/** Gets a string representing the disassembly of this implementation. */
|
||||
string getDisassembly() {
|
||||
result =
|
||||
concat(Instruction i |
|
||||
i = this.getAnInstruction()
|
||||
|
|
||||
i.toStringExtra(), ", " order by i.getIndex()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A method, which corresponds to any callable in C#, including constructors,
|
||||
* destructors, operators, accessors and so on.
|
||||
*/
|
||||
deprecated class Method extends DotNet::Callable, Element, Member, TypeContainer, DataFlowNode,
|
||||
CustomModifierReceiver, Parameterizable, @cil_method
|
||||
{
|
||||
/**
|
||||
* Gets a method implementation, if any. Note that there can
|
||||
* be several implementations in different assemblies.
|
||||
*/
|
||||
MethodImplementation getAnImplementation() { result.getMethod() = this }
|
||||
|
||||
/** Gets the "best" implementation of this method, if any. */
|
||||
BestImplementation getImplementation() { result = this.getAnImplementation() }
|
||||
|
||||
override Method getMethod() { result = this }
|
||||
|
||||
override string getName() { cil_method(this, result, _, _) }
|
||||
|
||||
override string getUndecoratedName() { result = this.getName() }
|
||||
|
||||
override string toString() { result = this.getName() }
|
||||
|
||||
override Type getDeclaringType() { cil_method(this, _, result, _) }
|
||||
|
||||
override Location getLocation() { result = Element.super.getLocation() }
|
||||
|
||||
override Location getALocation() { cil_method_location(this.getUnboundMethod+(), result) }
|
||||
|
||||
override MethodParameter getParameter(int n) {
|
||||
if this.isStatic()
|
||||
then result = this.getRawParameter(n)
|
||||
else (
|
||||
result = this.getRawParameter(n + 1) and n >= 0
|
||||
)
|
||||
}
|
||||
|
||||
override Type getType() { result = this.getReturnType() }
|
||||
|
||||
/** Gets the return type of this method. */
|
||||
override Type getReturnType() { cil_method(this, _, _, result) }
|
||||
|
||||
/** Holds if the return type is `void`. */
|
||||
predicate returnsVoid() { this.getReturnType() instanceof VoidType }
|
||||
|
||||
/** Gets the number of stack items pushed in a call to this method. */
|
||||
int getCallPushCount() { if this.returnsVoid() then result = 0 else result = 1 }
|
||||
|
||||
/** Gets the number of stack items popped in a call to this method. */
|
||||
int getCallPopCount() { result = count(this.getRawParameter(_)) }
|
||||
|
||||
/** Gets a method called by this method. */
|
||||
Method getACallee() { result = this.getImplementation().getAnInstruction().(Call).getTarget() }
|
||||
|
||||
/** Holds if this method is `virtual`. */
|
||||
predicate isVirtual() { cil_virtual(this) }
|
||||
|
||||
/** Holds if the name of this method is special, for example an operator. */
|
||||
predicate isSpecial() { cil_specialname(this) }
|
||||
|
||||
/** Holds of this method is marked as secure. */
|
||||
predicate isSecureObject() { cil_requiresecobject(this) }
|
||||
|
||||
/** Holds if the method does not override an existing method. */
|
||||
predicate isNew() { cil_newslot(this) }
|
||||
|
||||
override predicate isStatic() { cil_static(this) }
|
||||
|
||||
/** Gets the unbound declaration of this method, or the method itself. */
|
||||
Method getUnboundMethod() { cil_method_source_declaration(this, result) }
|
||||
|
||||
override Method getUnboundDeclaration() { result = this.getUnboundMethod() }
|
||||
|
||||
/** Holds if this method is an instance constructor. */
|
||||
predicate isInstanceConstructor() { this.isSpecial() and this.getName() = ".ctor" }
|
||||
|
||||
/** Holds if this method is a static class constructor. */
|
||||
predicate isStaticConstructor() { this.isSpecial() and this.getName() = ".cctor" }
|
||||
|
||||
/** Holds if this method is a constructor (static or instance). */
|
||||
predicate isConstructor() { this.isStaticConstructor() or this.isInstanceConstructor() }
|
||||
|
||||
/** Holds if this method is a destructor/finalizer. */
|
||||
predicate isFinalizer() {
|
||||
this.getOverriddenMethod*().hasFullyQualifiedName("System", "Object", "Finalize")
|
||||
}
|
||||
|
||||
/** Holds if this method is an operator. */
|
||||
predicate isOperator() { this.isSpecial() and this.getName().matches("op\\_%") }
|
||||
|
||||
/** Holds if this method is a getter. */
|
||||
predicate isGetter() { this.isSpecial() and this.getName().matches("get\\_%") }
|
||||
|
||||
/** Holds if this method is a setter. */
|
||||
predicate isSetter() { this.isSpecial() and this.getName().matches("set\\_%") }
|
||||
|
||||
/** Holds if this method is an adder/add event accessor. */
|
||||
predicate isAdder() { this.isSpecial() and this.getName().matches("add\\_%") }
|
||||
|
||||
/** Holds if this method is a remover/remove event accessor. */
|
||||
predicate isRemove() { this.isSpecial() and this.getName().matches("remove\\_%") }
|
||||
|
||||
/** Holds if this method is an implicit conversion operator. */
|
||||
predicate isImplicitConversion() { this.isSpecial() and this.getName() = "op_Implicit" }
|
||||
|
||||
/** Holds if this method is an explicit conversion operator. */
|
||||
predicate isExplicitConversion() { this.isSpecial() and this.getName() = "op_Explicit" }
|
||||
|
||||
/** Holds if this method is a conversion operator. */
|
||||
predicate isConversion() { this.isImplicitConversion() or this.isExplicitConversion() }
|
||||
|
||||
/**
|
||||
* Gets a method that is overridden, either in a base class
|
||||
* or in an interface.
|
||||
*/
|
||||
Method getOverriddenMethod() { cil_implements(this, result) }
|
||||
|
||||
/** Gets a method that overrides this method, if any. */
|
||||
final Method getAnOverrider() { result.getOverriddenMethod() = this }
|
||||
|
||||
override predicate hasBody() { exists(this.getImplementation()) }
|
||||
|
||||
override predicate canReturn(DotNet::Expr expr) {
|
||||
exists(Return ret | ret.getImplementation() = this.getImplementation() and expr = ret.getExpr())
|
||||
}
|
||||
}
|
||||
|
||||
/** A destructor/finalizer. */
|
||||
deprecated class Destructor extends Method, DotNet::Destructor {
|
||||
Destructor() { this.isFinalizer() }
|
||||
}
|
||||
|
||||
/** A constructor. */
|
||||
deprecated class Constructor extends Method, DotNet::Constructor {
|
||||
Constructor() { this.isConstructor() }
|
||||
}
|
||||
|
||||
/** A static/class constructor. */
|
||||
deprecated class StaticConstructor extends Constructor {
|
||||
StaticConstructor() { this.isStaticConstructor() }
|
||||
}
|
||||
|
||||
/** An instance constructor. */
|
||||
deprecated class InstanceConstructor extends Constructor {
|
||||
InstanceConstructor() { this.isInstanceConstructor() }
|
||||
}
|
||||
|
||||
/** A method that always returns the `this` parameter. */
|
||||
deprecated class ChainingMethod extends Method {
|
||||
ChainingMethod() {
|
||||
forex(Return ret | ret = this.getImplementation().getAnInstruction() |
|
||||
ret.getExpr() instanceof ThisAccess
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** An accessor. */
|
||||
abstract deprecated class Accessor extends Method {
|
||||
/** Gets the property declaring this accessor. */
|
||||
abstract Property getProperty();
|
||||
}
|
||||
|
||||
/** A getter. */
|
||||
deprecated class Getter extends Accessor {
|
||||
Getter() { cil_getter(_, this) }
|
||||
|
||||
override Property getProperty() { cil_getter(result, this) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A method that does nothing but retrieve a field.
|
||||
* Note that this is not necessarily a property getter.
|
||||
*/
|
||||
deprecated class TrivialGetter extends Method {
|
||||
TrivialGetter() {
|
||||
exists(MethodImplementation impl | impl = this.getAnImplementation() |
|
||||
impl.getInstruction(0) instanceof ThisAccess and
|
||||
impl.getInstruction(1) instanceof FieldReadAccess and
|
||||
impl.getInstruction(2) instanceof Return
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the underlying field of this getter. */
|
||||
Field getField() {
|
||||
this.getImplementation().getAnInstruction().(FieldReadAccess).getTarget() = result
|
||||
}
|
||||
}
|
||||
|
||||
/** A setter. */
|
||||
deprecated class Setter extends Accessor {
|
||||
Setter() { cil_setter(_, this) }
|
||||
|
||||
override Property getProperty() { cil_setter(result, this) }
|
||||
|
||||
/** Holds if this setter is an `init` accessor. */
|
||||
predicate isInitOnly() {
|
||||
exists(Type t | t.hasFullyQualifiedName("System.Runtime.CompilerServices", "IsExternalInit") |
|
||||
this.hasRequiredCustomModifier(t)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A method that does nothing but set a field.
|
||||
* This is not necessarily a property setter.
|
||||
*/
|
||||
deprecated class TrivialSetter extends Method {
|
||||
TrivialSetter() {
|
||||
exists(MethodImplementation impl | impl = this.getAnImplementation() |
|
||||
impl.getInstruction(0) instanceof ThisAccess and
|
||||
impl.getInstruction(1).(ParameterReadAccess).getTarget().getIndex() = 1 and
|
||||
impl.getInstruction(2) instanceof FieldWriteAccess
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the underlying field of this setter. */
|
||||
Field getField() {
|
||||
result = this.getImplementation().getAnInstruction().(FieldWriteAccess).getTarget()
|
||||
}
|
||||
}
|
||||
|
||||
/** An alias for `Method` for compatibility with the C# data model. */
|
||||
deprecated class Callable = Method;
|
||||
|
||||
/** An operator. */
|
||||
deprecated class Operator extends Method {
|
||||
Operator() { this.isOperator() }
|
||||
|
||||
/** Gets the name of the implementing method (for compatibility with C# data model). */
|
||||
string getFunctionName() { result = this.getName() }
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
/**
|
||||
* Provides `Parameterizable` class.
|
||||
*/
|
||||
|
||||
private import CIL
|
||||
private import dotnet
|
||||
|
||||
/**
|
||||
* A parameterizable entity, such as `FunctionPointerType` or `Method`.
|
||||
*/
|
||||
deprecated class Parameterizable extends DotNet::Parameterizable, Element, @cil_parameterizable {
|
||||
override Parameter getRawParameter(int n) { cil_parameter(result, this, n, _) }
|
||||
|
||||
override Parameter getParameter(int n) { cil_parameter(result, this, n, _) }
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
/**
|
||||
* Provides the module `Ssa` for working with static single assignment (SSA) form.
|
||||
*/
|
||||
|
||||
private import CIL
|
||||
|
||||
/**
|
||||
* Provides classes for working with static single assignment (SSA) form.
|
||||
*/
|
||||
deprecated module Ssa {
|
||||
private import internal.SsaImpl as SsaImpl
|
||||
|
||||
/** An SSA definition. */
|
||||
class Definition extends SsaImpl::Definition {
|
||||
/** Gets a read of this SSA definition. */
|
||||
final ReadAccess getARead() { result = SsaImpl::getARead(this) }
|
||||
|
||||
/** Gets the underlying variable update, if any. */
|
||||
final VariableUpdate getVariableUpdate() {
|
||||
exists(BasicBlock bb, int i |
|
||||
result.updatesAt(bb, i) and
|
||||
this.definesAt(result.getVariable(), bb, i)
|
||||
)
|
||||
}
|
||||
|
||||
private Definition getAPhiInput() { result = this.(PhiNode).getAnInput() }
|
||||
|
||||
/**
|
||||
* Gets a definition that ultimately defines this SSA definition and is
|
||||
* not itself a phi node.
|
||||
*/
|
||||
final Definition getAnUltimateDefinition() {
|
||||
result = this.getAPhiInput*() and
|
||||
not result instanceof PhiNode
|
||||
}
|
||||
|
||||
/** Gets the location of this SSA definition. */
|
||||
override Location getLocation() { result = this.getVariableUpdate().getLocation() }
|
||||
}
|
||||
|
||||
/** A phi node. */
|
||||
class PhiNode extends SsaImpl::PhiNode, Definition {
|
||||
final override Location getLocation() { result = this.getBasicBlock().getLocation() }
|
||||
|
||||
/** Gets an input to this phi node. */
|
||||
final Definition getAnInput() { result = SsaImpl::getAPhiInput(this) }
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
/**
|
||||
* Provides classes and predicates for identifying stub code.
|
||||
*/
|
||||
|
||||
import CIL
|
||||
|
||||
/**
|
||||
* The average number of instructions per method,
|
||||
* below which an assembly is probably a stub.
|
||||
*/
|
||||
deprecated private float stubInstructionThreshold() { result = 5.1 }
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
/**
|
||||
* A simple heuristic for determining whether an assembly is a
|
||||
* reference assembly where the method bodies have dummy implementations.
|
||||
* Look at the average number of instructions per method.
|
||||
*/
|
||||
cached
|
||||
deprecated predicate assemblyIsStubImpl(Assembly asm) {
|
||||
exists(int totalInstructions, int totalImplementations |
|
||||
totalInstructions = count(Instruction i | i.getImplementation().getLocation() = asm) and
|
||||
totalImplementations =
|
||||
count(MethodImplementation i | i.getImplementation().getLocation() = asm) and
|
||||
totalInstructions.(float) / totalImplementations.(float) < stubInstructionThreshold()
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
deprecated predicate bestImplementation(MethodImplementation mi) {
|
||||
exists(Assembly asm |
|
||||
asm = mi.getLocation() and
|
||||
(assemblyIsStubImpl(asm) implies asm.getFile().extractedQlTest()) and
|
||||
mi =
|
||||
max(MethodImplementation impl |
|
||||
mi.getMethod() = impl.getMethod()
|
||||
|
|
||||
impl order by impl.getNumberOfInstructions(), impl.getLocation().getFile().toString() desc
|
||||
) and
|
||||
exists(mi.getAnInstruction())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private import Cached
|
||||
|
||||
deprecated predicate assemblyIsStub = assemblyIsStubImpl/1;
|
||||
|
||||
/**
|
||||
* A method implementation that is the "best" one for a particular method,
|
||||
* if there are several potential implementations to choose between, and
|
||||
* excludes implementations that are probably from stub/reference assemblies.
|
||||
*/
|
||||
deprecated class BestImplementation extends MethodImplementation {
|
||||
BestImplementation() { bestImplementation(this) }
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
/**
|
||||
* Provides classes for types and associated classes.
|
||||
*/
|
||||
|
||||
import CIL
|
||||
private import dotnet
|
||||
private import semmle.code.csharp.commons.QualifiedName
|
||||
|
||||
/**
|
||||
* Something that contains other types.
|
||||
*
|
||||
* Either a type (`Type`), a method(`Method`), or a namespace (`Namespace`).
|
||||
*/
|
||||
deprecated class TypeContainer extends DotNet::NamedElement, @cil_type_container {
|
||||
/** Gets the parent of this type container, if any. */
|
||||
TypeContainer getParent() { none() }
|
||||
|
||||
override string toStringWithTypes() { result = this.getLabel() }
|
||||
}
|
||||
|
||||
/** A namespace. */
|
||||
deprecated class Namespace extends DotNet::Namespace, TypeContainer, @namespace {
|
||||
override string toString() { result = this.getFullName() }
|
||||
|
||||
override Namespace getParent() { result = this.getParentNamespace() }
|
||||
|
||||
override Namespace getParentNamespace() { parent_namespace(this, result) }
|
||||
|
||||
override Location getLocation() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A type.
|
||||
*/
|
||||
deprecated class Type extends DotNet::Type, Declaration, TypeContainer, @cil_type {
|
||||
override TypeContainer getParent() { cil_type(this, _, _, result, _) }
|
||||
|
||||
override string getName() { cil_type(this, result, _, _, _) }
|
||||
|
||||
override string toString() { result = this.getName() }
|
||||
|
||||
/** Gets the containing type of this type, if any. */
|
||||
override Type getDeclaringType() { result = this.getParent() }
|
||||
|
||||
/** Gets a member of this type, if any. */
|
||||
Member getAMember() { result.getDeclaringType() = this }
|
||||
|
||||
/**
|
||||
* Gets the unbound generic type of this type, or `this` if the type
|
||||
* is already unbound.
|
||||
*/
|
||||
Type getUnboundType() { cil_type(this, _, _, _, result) }
|
||||
|
||||
deprecated override predicate hasQualifiedName(string qualifier, string name) {
|
||||
name = this.getName() and
|
||||
exists(string pqualifier, string pname | this.getParent().hasQualifiedName(pqualifier, pname) |
|
||||
qualifier = getQualifiedName(pqualifier, pname)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate hasFullyQualifiedName(string qualifier, string name) {
|
||||
name = this.getName() and
|
||||
exists(string pqualifier, string pname |
|
||||
this.getParent().hasFullyQualifiedName(pqualifier, pname)
|
||||
|
|
||||
qualifier = getQualifiedName(pqualifier, pname)
|
||||
)
|
||||
}
|
||||
|
||||
override Location getALocation() { cil_type_location(this.getUnboundDeclaration(), result) }
|
||||
|
||||
/** Holds if this type is a class. */
|
||||
predicate isClass() { cil_class(this) }
|
||||
|
||||
/** Holds if this type is an interface. */
|
||||
predicate isInterface() { cil_interface(this) }
|
||||
|
||||
/**
|
||||
* Holds if this type is a member of the `System` namespace and has the name
|
||||
* `name`.
|
||||
*/
|
||||
predicate isSystemType(string name) {
|
||||
exists(Namespace system | this.getParent() = system |
|
||||
system.getName() = "System" and
|
||||
system.getParentNamespace().getName() = "" and
|
||||
name = this.getName()
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if this type is an `enum`. */
|
||||
predicate isEnum() { this.getBaseClass().isSystemType("Enum") }
|
||||
|
||||
/** Holds if this type is public. */
|
||||
predicate isPublic() { cil_public(this) }
|
||||
|
||||
/** Holds if this type is private. */
|
||||
predicate isPrivate() { cil_private(this) }
|
||||
|
||||
/** Gets the machine type used to store this type. */
|
||||
Type getUnderlyingType() { result = this }
|
||||
|
||||
// Class hierarchy
|
||||
/** Gets the immediate base class of this class, if any. */
|
||||
Type getBaseClass() { cil_base_class(this, result) }
|
||||
|
||||
/** Gets an immediate base interface of this class, if any. */
|
||||
Type getABaseInterface() { cil_base_interface(this, result) }
|
||||
|
||||
/** Gets an immediate base type of this type, if any. */
|
||||
Type getABaseType() { result = this.getBaseClass() or result = this.getABaseInterface() }
|
||||
|
||||
/** Gets an immediate subtype of this type, if any. */
|
||||
Type getASubtype() { result.getABaseType() = this }
|
||||
|
||||
/** Gets the namespace directly containing this type, if any. */
|
||||
Namespace getNamespace() { result = this.getParent() }
|
||||
|
||||
/**
|
||||
* Gets an index for implicit conversions. A type can be converted to another numeric type
|
||||
* of a higher index.
|
||||
*/
|
||||
int getConversionIndex() { result = 0 }
|
||||
|
||||
override Type getUnboundDeclaration() { cil_type(this, _, _, _, result) }
|
||||
}
|
||||
@@ -1,318 +0,0 @@
|
||||
/**
|
||||
* Provides classes representing various types.
|
||||
*/
|
||||
|
||||
private import CIL
|
||||
private import dotnet
|
||||
|
||||
/** A type parameter. */
|
||||
deprecated class TypeParameter extends DotNet::TypeParameter, Type, @cil_typeparameter {
|
||||
override int getIndex() { cil_type_parameter(_, result, this) }
|
||||
|
||||
/** Gets the generic type/method declaring this type parameter. */
|
||||
TypeContainer getGeneric() { cil_type_parameter(result, _, this) }
|
||||
|
||||
override Location getLocation() { result = this.getParent().getLocation() }
|
||||
|
||||
/** Holds if this type parameter has the `new` constraint. */
|
||||
predicate isDefaultConstructible() { cil_typeparam_new(this) }
|
||||
|
||||
/** Holds if this type parameter has the `struct` constraint. */
|
||||
predicate isStruct() { cil_typeparam_struct(this) }
|
||||
|
||||
override predicate isClass() { cil_typeparam_class(this) }
|
||||
|
||||
/** Holds if this type parameter is covariant/is `in`. */
|
||||
predicate isCovariant() { cil_typeparam_covariant(this) }
|
||||
|
||||
/** Holds if this type parameter is contravariant/is `out`. */
|
||||
predicate isContravariant() { cil_typeparam_contravariant(this) }
|
||||
|
||||
/** Gets a type constraint on this type parameter, if any. */
|
||||
Type getATypeConstraint() { cil_typeparam_constraint(this, result) }
|
||||
}
|
||||
|
||||
/** A value or reference type. */
|
||||
deprecated class ValueOrRefType extends DotNet::ValueOrRefType, Type, @cil_valueorreftype {
|
||||
override ValueOrRefType getDeclaringType() { result = this.getParent() }
|
||||
|
||||
override string getUndecoratedName() { cil_type(this, result, _, _, _) }
|
||||
|
||||
override Namespace getDeclaringNamespace() { result = this.getNamespace() }
|
||||
|
||||
override ValueOrRefType getABaseType() { result = Type.super.getABaseType() }
|
||||
}
|
||||
|
||||
/** An `enum`. */
|
||||
deprecated class Enum extends ValueOrRefType {
|
||||
Enum() { this.isEnum() }
|
||||
|
||||
override IntegralType getUnderlyingType() {
|
||||
cil_enum_underlying_type(this, result)
|
||||
or
|
||||
not cil_enum_underlying_type(this, _) and
|
||||
result instanceof IntType
|
||||
}
|
||||
}
|
||||
|
||||
/** A `class`. */
|
||||
deprecated class Class extends ValueOrRefType {
|
||||
Class() { this.isClass() }
|
||||
}
|
||||
|
||||
/** An `interface`. */
|
||||
deprecated class Interface extends ValueOrRefType {
|
||||
Interface() { this.isInterface() }
|
||||
}
|
||||
|
||||
/** An array. */
|
||||
deprecated class ArrayType extends DotNet::ArrayType, Type, @cil_array_type {
|
||||
override Type getElementType() { cil_array_type(this, result, _) }
|
||||
|
||||
/** Gets the rank of this array. */
|
||||
int getRank() { cil_array_type(this, _, result) }
|
||||
|
||||
override string toStringWithTypes() { result = DotNet::ArrayType.super.toStringWithTypes() }
|
||||
|
||||
override Location getLocation() { result = this.getElementType().getLocation() }
|
||||
|
||||
override ValueOrRefType getABaseType() { result = Type.super.getABaseType() }
|
||||
}
|
||||
|
||||
/** A pointer type. */
|
||||
deprecated class PointerType extends DotNet::PointerType, PrimitiveType, @cil_pointer_type {
|
||||
override Type getReferentType() { cil_pointer_type(this, result) }
|
||||
|
||||
override IntType getUnderlyingType() { any() }
|
||||
|
||||
override string getName() { result = DotNet::PointerType.super.getName() }
|
||||
|
||||
override Location getLocation() { result = this.getReferentType().getLocation() }
|
||||
|
||||
override string toString() { result = DotNet::PointerType.super.toString() }
|
||||
|
||||
override string toStringWithTypes() { result = DotNet::PointerType.super.toStringWithTypes() }
|
||||
}
|
||||
|
||||
/** A primitive type, built into the runtime. */
|
||||
abstract deprecated class PrimitiveType extends Type { }
|
||||
|
||||
/**
|
||||
* A primitive numeric type.
|
||||
* Either an integral type (`IntegralType`) or a floating point type (`FloatingPointType`).
|
||||
*/
|
||||
abstract deprecated class NumericType extends PrimitiveType, ValueOrRefType { }
|
||||
|
||||
/** A floating point type. Either single precision (`FloatType`) or double precision (`DoubleType`). */
|
||||
abstract deprecated class FloatingPointType extends NumericType { }
|
||||
|
||||
/**
|
||||
* An integral numeric type. Either a signed integral type (`SignedIntegralType`)
|
||||
* or an unsigned integral type (`UnsignedIntegralType`).
|
||||
*/
|
||||
abstract deprecated class IntegralType extends NumericType { }
|
||||
|
||||
/** A signed integral type. */
|
||||
abstract deprecated class SignedIntegralType extends IntegralType { }
|
||||
|
||||
/** An unsigned integral type. */
|
||||
abstract deprecated class UnsignedIntegralType extends IntegralType { }
|
||||
|
||||
/** The `void` type, `System.Void`. */
|
||||
deprecated class VoidType extends PrimitiveType {
|
||||
VoidType() { this.isSystemType("Void") }
|
||||
|
||||
override string toString() { result = "void" }
|
||||
|
||||
override string toStringWithTypes() { result = "void" }
|
||||
}
|
||||
|
||||
/** The type `System.Int32`. */
|
||||
deprecated class IntType extends SignedIntegralType {
|
||||
IntType() { this.isSystemType("Int32") }
|
||||
|
||||
override string toStringWithTypes() { result = "int" }
|
||||
|
||||
override int getConversionIndex() { result = 8 }
|
||||
|
||||
override IntType getUnderlyingType() { result = this }
|
||||
}
|
||||
|
||||
/** The type `System.IntPtr`. */
|
||||
deprecated class IntPtrType extends PrimitiveType {
|
||||
IntPtrType() { this.isSystemType("IntPtr") }
|
||||
|
||||
override IntType getUnderlyingType() { any() }
|
||||
}
|
||||
|
||||
/** The type `System.UIntPtr`. */
|
||||
deprecated class UIntPtrType extends PrimitiveType {
|
||||
UIntPtrType() { this.isSystemType("UIntPtr") }
|
||||
|
||||
override IntType getUnderlyingType() { any() }
|
||||
}
|
||||
|
||||
/** The type `System.UInt32`. */
|
||||
deprecated class UIntType extends UnsignedIntegralType {
|
||||
UIntType() { this.isSystemType("UInt32") }
|
||||
|
||||
override string toStringWithTypes() { result = "uint" }
|
||||
|
||||
override int getConversionIndex() { result = 7 }
|
||||
|
||||
override IntType getUnderlyingType() { any() }
|
||||
}
|
||||
|
||||
/** The type `System.SByte`. */
|
||||
deprecated class SByteType extends SignedIntegralType {
|
||||
SByteType() { this.isSystemType("SByte") }
|
||||
|
||||
override string toStringWithTypes() { result = "sbyte" }
|
||||
|
||||
override int getConversionIndex() { result = 2 }
|
||||
}
|
||||
|
||||
/** The type `System.Byte`. */
|
||||
deprecated class ByteType extends UnsignedIntegralType {
|
||||
ByteType() { this.isSystemType("Byte") }
|
||||
|
||||
override string toStringWithTypes() { result = "byte" }
|
||||
|
||||
override int getConversionIndex() { result = 1 }
|
||||
|
||||
override SByteType getUnderlyingType() { any() }
|
||||
}
|
||||
|
||||
/** The type `System.Int16`. */
|
||||
deprecated class ShortType extends SignedIntegralType {
|
||||
ShortType() { this.isSystemType("Int16") }
|
||||
|
||||
override string toStringWithTypes() { result = "short" }
|
||||
|
||||
override int getConversionIndex() { result = 4 }
|
||||
}
|
||||
|
||||
/** The type `System.UInt16`. */
|
||||
deprecated class UShortType extends UnsignedIntegralType {
|
||||
UShortType() { this.isSystemType("UInt16") }
|
||||
|
||||
override string toStringWithTypes() { result = "ushort" }
|
||||
|
||||
override int getConversionIndex() { result = 3 }
|
||||
|
||||
override ShortType getUnderlyingType() { any() }
|
||||
}
|
||||
|
||||
/** The type `System.Int64`. */
|
||||
deprecated class LongType extends SignedIntegralType {
|
||||
LongType() { this.isSystemType("Int64") }
|
||||
|
||||
override string toStringWithTypes() { result = "long" }
|
||||
|
||||
override int getConversionIndex() { result = 10 }
|
||||
}
|
||||
|
||||
/** The type `System.UInt64`. */
|
||||
deprecated class ULongType extends UnsignedIntegralType {
|
||||
ULongType() { this.isSystemType("UInt64") }
|
||||
|
||||
override string toStringWithTypes() { result = "ulong" }
|
||||
|
||||
override int getConversionIndex() { result = 9 }
|
||||
|
||||
override LongType getUnderlyingType() { any() }
|
||||
}
|
||||
|
||||
/** The type `System.Decimal`. */
|
||||
deprecated class DecimalType extends SignedIntegralType {
|
||||
DecimalType() { this.isSystemType("Decimal") }
|
||||
|
||||
override string toStringWithTypes() { result = "decimal" }
|
||||
|
||||
override int getConversionIndex() { result = 13 }
|
||||
}
|
||||
|
||||
/** The type `System.String`. */
|
||||
deprecated class StringType extends PrimitiveType, ValueOrRefType {
|
||||
StringType() { this.isSystemType("String") }
|
||||
|
||||
override string toStringWithTypes() { result = "string" }
|
||||
}
|
||||
|
||||
/** The type `System.Object`. */
|
||||
deprecated class ObjectType extends ValueOrRefType {
|
||||
ObjectType() { this.isSystemType("Object") }
|
||||
|
||||
override string toStringWithTypes() { result = "object" }
|
||||
}
|
||||
|
||||
/** The type `System.Boolean`. */
|
||||
deprecated class BoolType extends PrimitiveType, ValueOrRefType {
|
||||
BoolType() { this.isSystemType("Boolean") }
|
||||
|
||||
override string toStringWithTypes() { result = "bool" }
|
||||
|
||||
override IntType getUnderlyingType() { any() }
|
||||
}
|
||||
|
||||
/** The type `System.Double`. */
|
||||
deprecated class DoubleType extends FloatingPointType {
|
||||
DoubleType() { this.isSystemType("Double") }
|
||||
|
||||
override string toStringWithTypes() { result = "double" }
|
||||
|
||||
override int getConversionIndex() { result = 12 }
|
||||
}
|
||||
|
||||
/** The type `System.Single`. */
|
||||
deprecated class FloatType extends FloatingPointType {
|
||||
FloatType() { this.isSystemType("Single") }
|
||||
|
||||
override string toStringWithTypes() { result = "float" }
|
||||
|
||||
override int getConversionIndex() { result = 4 }
|
||||
}
|
||||
|
||||
/** The type `System.Char`. */
|
||||
deprecated class CharType extends IntegralType {
|
||||
CharType() { this.isSystemType("Char") }
|
||||
|
||||
override string toStringWithTypes() { result = "char" }
|
||||
|
||||
override int getConversionIndex() { result = 6 }
|
||||
|
||||
override IntType getUnderlyingType() { any() }
|
||||
}
|
||||
|
||||
/** The type `System.Type`. */
|
||||
deprecated class SystemType extends ValueOrRefType {
|
||||
SystemType() { this.isSystemType("Type") }
|
||||
}
|
||||
|
||||
/**
|
||||
* A function pointer type, for example
|
||||
*
|
||||
* ```csharp
|
||||
* delegate*<int, void>
|
||||
* ```
|
||||
*/
|
||||
deprecated class FunctionPointerType extends Type, CustomModifierReceiver, Parameterizable,
|
||||
@cil_function_pointer_type
|
||||
{
|
||||
/** Gets the return type of this function pointer. */
|
||||
Type getReturnType() { cil_function_pointer_return_type(this, result) }
|
||||
|
||||
/** Gets the calling convention. */
|
||||
int getCallingConvention() { cil_function_pointer_calling_conventions(this, result) }
|
||||
|
||||
/** Holds if the return type is `void`. */
|
||||
predicate returnsVoid() { this.getReturnType() instanceof VoidType }
|
||||
|
||||
/** Gets the number of stack items pushed in a call to this method. */
|
||||
int getCallPushCount() { if this.returnsVoid() then result = 0 else result = 1 }
|
||||
|
||||
/** Gets the number of stack items popped in a call to this method. */
|
||||
int getCallPopCount() { result = count(this.getRawParameter(_)) }
|
||||
|
||||
override string getLabel() { result = this.getName() }
|
||||
}
|
||||
@@ -1,160 +0,0 @@
|
||||
/**
|
||||
* Provides classes for variables.
|
||||
*/
|
||||
|
||||
private import CIL
|
||||
private import dotnet
|
||||
|
||||
/** A variable. Either a stack variable (`StackVariable`) or a field (`Field`). */
|
||||
deprecated class Variable extends DotNet::Variable, Declaration, DataFlowNode, @cil_variable {
|
||||
/** Gets the type of this variable. */
|
||||
override Type getType() { none() }
|
||||
|
||||
/** Gets a textual representation of this variable including type information. */
|
||||
override string toStringWithTypes() { none() }
|
||||
|
||||
/** Gets an access to this variable, if any. */
|
||||
VariableAccess getAnAccess() { result.getTarget() = this }
|
||||
|
||||
/** Gets a read access to this variable, if any. */
|
||||
ReadAccess getARead() { result = this.getAnAccess() }
|
||||
|
||||
/** Gets a write access to this variable, if any. */
|
||||
WriteAccess getAWrite() { result = this.getAnAccess() }
|
||||
|
||||
override string toString() { result = Declaration.super.toString() }
|
||||
|
||||
override Location getLocation() { result = Declaration.super.getLocation() }
|
||||
}
|
||||
|
||||
/** A stack variable. Either a local variable (`LocalVariable`) or a parameter (`Parameter`). */
|
||||
deprecated class StackVariable extends Variable, @cil_stack_variable {
|
||||
deprecated override predicate hasQualifiedName(string qualifier, string name) { none() }
|
||||
|
||||
override predicate hasFullyQualifiedName(string qualifier, string name) { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A local variable.
|
||||
*
|
||||
* Each method in CIL has a number of typed local variables, in addition to the evaluation stack.
|
||||
*/
|
||||
deprecated class LocalVariable extends StackVariable, @cil_local_variable {
|
||||
override string toString() {
|
||||
result =
|
||||
"Local variable " + this.getIndex() + " of method " +
|
||||
this.getImplementation().getMethod().getName()
|
||||
}
|
||||
|
||||
/** Gets the method implementation defining this local variable. */
|
||||
MethodImplementation getImplementation() { this = result.getALocalVariable() }
|
||||
|
||||
/** Gets the index number of this local variable. This is not usually significant. */
|
||||
int getIndex() { this = this.getImplementation().getLocalVariable(result) }
|
||||
|
||||
override Type getType() { cil_local_variable(this, _, _, result) }
|
||||
|
||||
override Location getLocation() { result = this.getImplementation().getLocation() }
|
||||
|
||||
override Method getMethod() { result = this.getImplementation().getMethod() }
|
||||
}
|
||||
|
||||
/** A parameter of a `Method` or `FunctionPointerType`. */
|
||||
deprecated class Parameter extends DotNet::Parameter, CustomModifierReceiver, @cil_parameter {
|
||||
override Parameterizable getDeclaringElement() { cil_parameter(this, result, _, _) }
|
||||
|
||||
/** Gets the index of this parameter. */
|
||||
int getIndex() { cil_parameter(this, _, result, _) }
|
||||
|
||||
override string toString() {
|
||||
result = "Parameter " + this.getIndex() + " of " + this.getDeclaringElement().getName()
|
||||
}
|
||||
|
||||
override Type getType() { cil_parameter(this, _, _, result) }
|
||||
|
||||
/**
|
||||
* Holds if this parameter has an "out" flag, meaning that it will
|
||||
* be passed by reference and written to.
|
||||
*/
|
||||
predicate hasOutFlag() { cil_parameter_out(this) }
|
||||
|
||||
/**
|
||||
* Holds if this parameter has an "in" flag, meaning that it will
|
||||
* be passed by reference and may be read from and written to.
|
||||
*/
|
||||
predicate hasInFlag() { cil_parameter_in(this) }
|
||||
|
||||
/** Holds if this parameter has C# `out` semantics. */
|
||||
override predicate isOut() { this.hasOutFlag() and not this.hasInFlag() }
|
||||
|
||||
/** Holds if this parameter has C# `ref` semantics. */
|
||||
override predicate isRef() { this.hasOutFlag() and this.hasInFlag() }
|
||||
|
||||
override string toStringWithTypes() {
|
||||
result = this.getPrefix() + this.getType().toStringWithTypes()
|
||||
}
|
||||
|
||||
private string getPrefix() {
|
||||
if this.isOut()
|
||||
then result = "out "
|
||||
else
|
||||
if this.isRef()
|
||||
then result = "ref "
|
||||
else result = ""
|
||||
}
|
||||
|
||||
override Location getLocation() { result = this.getDeclaringElement().getLocation() }
|
||||
}
|
||||
|
||||
/** A method parameter. */
|
||||
deprecated class MethodParameter extends Parameter, StackVariable {
|
||||
/** Gets the method declaring this parameter. */
|
||||
override Method getMethod() { this = result.getARawParameter() }
|
||||
|
||||
override ParameterAccess getAnAccess() { result.getTarget() = this }
|
||||
|
||||
/** Gets a parameter in an overridden method. */
|
||||
MethodParameter getOverriddenParameter() {
|
||||
result = this.getMethod().getOverriddenMethod().getRawParameter(this.getRawPosition())
|
||||
}
|
||||
|
||||
override MethodParameter getUnboundDeclaration() {
|
||||
result = this.getMethod().getUnboundDeclaration().getRawParameter(this.getRawPosition())
|
||||
}
|
||||
|
||||
override string toString() { result = Parameter.super.toString() }
|
||||
|
||||
override string toStringWithTypes() { result = Parameter.super.toStringWithTypes() }
|
||||
|
||||
override Type getType() { result = Parameter.super.getType() }
|
||||
|
||||
override Location getLocation() { result = Parameter.super.getLocation() }
|
||||
}
|
||||
|
||||
/** A parameter corresponding to `this`. */
|
||||
deprecated class ThisParameter extends MethodParameter {
|
||||
ThisParameter() {
|
||||
not this.getMethod().isStatic() and
|
||||
this.getIndex() = 0
|
||||
}
|
||||
}
|
||||
|
||||
/** A field. */
|
||||
deprecated class Field extends DotNet::Field, Variable, Member, CustomModifierReceiver, @cil_field {
|
||||
override string toString() { result = this.getName() }
|
||||
|
||||
override string toStringWithTypes() {
|
||||
result = this.getDeclaringType().toStringWithTypes() + "." + this.getName()
|
||||
}
|
||||
|
||||
override string getName() { cil_field(this, _, result, _) }
|
||||
|
||||
override Type getType() { cil_field(this, _, _, result) }
|
||||
|
||||
override ValueOrRefType getDeclaringType() { cil_field(this, result, _, _) }
|
||||
|
||||
override Location getLocation() { result = this.getDeclaringType().getLocation() }
|
||||
|
||||
/** Holds if this declaration is `ref`. */
|
||||
predicate isRef() { cil_type_annotation(this, 32) }
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
private import cil
|
||||
private import CIL
|
||||
private import codeql.ssa.Ssa as SsaImplCommon
|
||||
|
||||
deprecated private module SsaInput implements SsaImplCommon::InputSig<CIL::Location> {
|
||||
class BasicBlock = CIL::BasicBlock;
|
||||
|
||||
class ControlFlowNode = CIL::ControlFlowNode;
|
||||
|
||||
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result = bb.getImmediateDominator() }
|
||||
|
||||
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
|
||||
|
||||
class ExitBasicBlock extends BasicBlock, CIL::ExitBasicBlock { }
|
||||
|
||||
class SourceVariable = CIL::StackVariable;
|
||||
|
||||
predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) {
|
||||
forceCachingInSameStage() and
|
||||
exists(CIL::VariableUpdate vu |
|
||||
vu.updatesAt(bb, i) and
|
||||
v = vu.getVariable() and
|
||||
certain = true
|
||||
)
|
||||
}
|
||||
|
||||
predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain) {
|
||||
exists(CIL::ReadAccess ra | bb.getNode(i) = ra |
|
||||
ra.getTarget() = v and
|
||||
certain = true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
deprecated import SsaImplCommon::Make<CIL::Location, SsaInput>
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
private import CIL
|
||||
|
||||
cached
|
||||
deprecated predicate forceCachingInSameStage() { any() }
|
||||
|
||||
cached
|
||||
deprecated ReadAccess getARead(Definition def) {
|
||||
exists(BasicBlock bb, int i |
|
||||
ssaDefReachesRead(_, def, bb, i) and
|
||||
result = bb.getNode(i)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
deprecated ReadAccess getAFirstReadExt(DefinitionExt def) {
|
||||
exists(BasicBlock bb1, int i1, BasicBlock bb2, int i2 |
|
||||
def.definesAt(_, bb1, i1, _) and
|
||||
adjacentDefReadExt(def, _, bb1, i1, bb2, i2) and
|
||||
result = bb2.getNode(i2)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
deprecated predicate hasAdjacentReadsExt(DefinitionExt def, ReadAccess first, ReadAccess second) {
|
||||
exists(BasicBlock bb1, int i1, BasicBlock bb2, int i2 |
|
||||
first = bb1.getNode(i1) and
|
||||
adjacentDefReadExt(def, _, bb1, i1, bb2, i2) and
|
||||
second = bb2.getNode(i2)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
deprecated Definition getAPhiInput(PhiNode phi) { phiHasInputFromBlock(phi, result, _) }
|
||||
|
||||
cached
|
||||
deprecated predicate lastRefBeforeRedefExt(
|
||||
DefinitionExt def, BasicBlock bb, int i, DefinitionExt next
|
||||
) {
|
||||
lastRefRedefExt(def, _, bb, i, next)
|
||||
}
|
||||
}
|
||||
|
||||
import Cached
|
||||
|
||||
private module Deprecated {
|
||||
private import CIL
|
||||
}
|
||||
|
||||
import Deprecated
|
||||
@@ -1,122 +0,0 @@
|
||||
/**
|
||||
* Provides `Callable` classes, which are things that can be called
|
||||
* such as methods and constructors.
|
||||
*/
|
||||
|
||||
import Declaration
|
||||
import Variable
|
||||
import Expr
|
||||
import Parameterizable
|
||||
|
||||
/** A .Net callable. */
|
||||
deprecated class Callable extends Parameterizable, @dotnet_callable {
|
||||
/** Holds if this callable has a body or an implementation. */
|
||||
predicate hasBody() { none() }
|
||||
|
||||
/** Holds if this callable can return expression `e`. */
|
||||
predicate canReturn(Expr e) { none() }
|
||||
|
||||
pragma[noinline]
|
||||
private string getDeclaringTypeLabel() { result = this.getDeclaringType().getLabel() }
|
||||
|
||||
pragma[noinline]
|
||||
private string getParameterTypeLabelNonGeneric(int p) {
|
||||
not this instanceof Generic and
|
||||
result = this.getParameter(p).getType().getLabel()
|
||||
}
|
||||
|
||||
language[monotonicAggregates]
|
||||
pragma[nomagic]
|
||||
private string getMethodParamListNonGeneric() {
|
||||
result =
|
||||
concat(int p |
|
||||
p in [0 .. this.getNumberOfParameters() - 1]
|
||||
|
|
||||
this.getParameterTypeLabelNonGeneric(p), "," order by p
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private string getParameterTypeLabelGeneric(int p) {
|
||||
this instanceof Generic and
|
||||
result = this.getParameter(p).getType().getLabel()
|
||||
}
|
||||
|
||||
language[monotonicAggregates]
|
||||
pragma[nomagic]
|
||||
private string getMethodParamListGeneric() {
|
||||
result =
|
||||
concat(int p |
|
||||
p in [0 .. this.getNumberOfParameters() - 1]
|
||||
|
|
||||
this.getParameterTypeLabelGeneric(p), "," order by p
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private string getLabelNonGeneric() {
|
||||
not this instanceof Generic and
|
||||
result =
|
||||
this.getReturnTypeLabel() + " " + this.getDeclaringTypeLabel() + "." +
|
||||
this.getUndecoratedName() + "(" + this.getMethodParamListNonGeneric() + ")"
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private string getLabelGeneric() {
|
||||
result =
|
||||
this.getReturnTypeLabel() + " " + this.getDeclaringTypeLabel() + "." +
|
||||
this.getUndecoratedName() + getGenericsLabel(this) + "(" + this.getMethodParamListGeneric() +
|
||||
")"
|
||||
}
|
||||
|
||||
final override string getLabel() {
|
||||
result = this.getLabelNonGeneric() or
|
||||
result = this.getLabelGeneric()
|
||||
}
|
||||
|
||||
private string getReturnTypeLabel() {
|
||||
result = this.getReturnType().getLabel()
|
||||
or
|
||||
not exists(this.getReturnType()) and result = "System.Void"
|
||||
}
|
||||
|
||||
/** Gets the return type of this callable. */
|
||||
Type getReturnType() { none() }
|
||||
}
|
||||
|
||||
/** A constructor. */
|
||||
abstract deprecated class Constructor extends Callable { }
|
||||
|
||||
/** A destructor/finalizer. */
|
||||
abstract deprecated class Destructor extends Callable { }
|
||||
|
||||
pragma[nomagic]
|
||||
deprecated private ValueOrRefType getARecordBaseType(ValueOrRefType t) {
|
||||
exists(Callable c |
|
||||
c.hasName("<Clone>$") and
|
||||
c.getNumberOfParameters() = 0 and
|
||||
t = c.getDeclaringType() and
|
||||
result = t
|
||||
)
|
||||
or
|
||||
result = getARecordBaseType(t).getABaseType()
|
||||
}
|
||||
|
||||
/** A clone method on a record. */
|
||||
deprecated class RecordCloneCallable extends Callable {
|
||||
RecordCloneCallable() {
|
||||
this.getDeclaringType() instanceof ValueOrRefType and
|
||||
this.hasName("<Clone>$") and
|
||||
this.getNumberOfParameters() = 0 and
|
||||
this.getReturnType() = getARecordBaseType(this.getDeclaringType()) and
|
||||
this.(Member).isPublic() and
|
||||
not this.(Member).isStatic()
|
||||
}
|
||||
|
||||
/** Gets the constructor that this clone method calls. */
|
||||
Constructor getConstructor() {
|
||||
result.getDeclaringType() = this.getDeclaringType() and
|
||||
result.getNumberOfParameters() = 1 and
|
||||
result.getParameter(0).getType() = this.getDeclaringType()
|
||||
}
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
/**
|
||||
* Provides classes for .Net declarations.
|
||||
*/
|
||||
|
||||
import Element
|
||||
import Type
|
||||
private import semmle.code.csharp.commons.QualifiedName
|
||||
|
||||
/** A declaration. */
|
||||
deprecated class Declaration extends NamedElement, @dotnet_declaration {
|
||||
/** Gets the name of this declaration, without additional decoration such as `<...>`. */
|
||||
string getUndecoratedName() { none() }
|
||||
|
||||
/** Holds if this element has undecorated name 'name'. */
|
||||
final predicate hasUndecoratedName(string name) { name = this.getUndecoratedName() }
|
||||
|
||||
/** Gets the type containing this declaration, if any. */
|
||||
Type getDeclaringType() { none() }
|
||||
|
||||
/**
|
||||
* Gets the unbound version of this declaration, that is, the declaration where
|
||||
* all type arguments have been removed. For example, in
|
||||
*
|
||||
* ```csharp
|
||||
* class C<T>
|
||||
* {
|
||||
* class Nested
|
||||
* {
|
||||
* }
|
||||
*
|
||||
* void Method<S>() { }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* we have the following
|
||||
*
|
||||
* | Declaration | Unbound declaration |
|
||||
* |-------------------------|---------------------|
|
||||
* | `C<int>` | ``C`1`` |
|
||||
* | ``C`1.Nested`` | ``C`1.Nested`` |
|
||||
* | `C<int>.Nested` | ``C`1.Nested`` |
|
||||
* | ``C`1.Method`1`` | ``C`1.Method`1`` |
|
||||
* | ``C<int>.Method`1`` | ``C`1.Method`1`` |
|
||||
* | `C<int>.Method<string>` | ``C`1.Method`1`` |
|
||||
*/
|
||||
Declaration getUnboundDeclaration() { result = this }
|
||||
|
||||
/** Holds if this declaration is unbound. */
|
||||
final predicate isUnboundDeclaration() { this.getUnboundDeclaration() = this }
|
||||
}
|
||||
|
||||
/** A member of a type. */
|
||||
deprecated class Member extends Declaration, @dotnet_member {
|
||||
/** Holds if this member is declared `public`. */
|
||||
predicate isPublic() { none() }
|
||||
|
||||
/** Holds if this member is declared `protected.` */
|
||||
predicate isProtected() { none() }
|
||||
|
||||
/** Holds if this member is `private`. */
|
||||
predicate isPrivate() { none() }
|
||||
|
||||
/** Holds if this member is `internal`. */
|
||||
predicate isInternal() { none() }
|
||||
|
||||
/** Holds if this member is `sealed`. */
|
||||
predicate isSealed() { none() }
|
||||
|
||||
/** Holds if this member is `abstract`. */
|
||||
predicate isAbstract() { none() }
|
||||
|
||||
/** Holds if this member is `static`. */
|
||||
predicate isStatic() { none() }
|
||||
|
||||
/** Holds if this member is declared `required`. */
|
||||
predicate isRequired() { none() }
|
||||
|
||||
/** Holds if this member is declared `file` local. */
|
||||
predicate isFile() { none() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `hasFullyQualifiedName` instead.
|
||||
*
|
||||
* Holds if this member has name `name` and is defined in type `type`
|
||||
* with namespace `namespace`.
|
||||
*/
|
||||
cached
|
||||
deprecated predicate hasQualifiedName(string namespace, string type, string name) {
|
||||
this.getDeclaringType().hasQualifiedName(namespace, type) and
|
||||
name = this.getName()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this member has name `name` and is defined in type `type`
|
||||
* with namespace `namespace`.
|
||||
*/
|
||||
cached
|
||||
predicate hasFullyQualifiedName(string namespace, string type, string name) {
|
||||
this.getDeclaringType().hasFullyQualifiedName(namespace, type) and
|
||||
name = this.getName()
|
||||
}
|
||||
}
|
||||
|
||||
/** A property. */
|
||||
deprecated class Property extends Member, @dotnet_property {
|
||||
/** Gets the getter of this property, if any. */
|
||||
Callable getGetter() { none() }
|
||||
|
||||
/** Gets the setter of this property, if any. */
|
||||
Callable getSetter() { none() }
|
||||
|
||||
/** Gets the type of this property. */
|
||||
Type getType() { none() }
|
||||
}
|
||||
|
||||
/** An event. */
|
||||
deprecated class Event extends Member, @dotnet_event {
|
||||
/** Gets the adder of this event, if any. */
|
||||
Callable getAdder() { none() }
|
||||
|
||||
/** Gets the remover of this event, if any. */
|
||||
Callable getRemover() { none() }
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
/**
|
||||
* Provides a common model for all .Net languages, including C# and CIL.
|
||||
*/
|
||||
|
||||
import Element
|
||||
import Namespace
|
||||
import Declaration
|
||||
import Generics
|
||||
import Type
|
||||
import Variable
|
||||
import Callable
|
||||
import Expr
|
||||
import Utils
|
||||
@@ -1,162 +0,0 @@
|
||||
/**
|
||||
* Provides the .Net `Element` class.
|
||||
*/
|
||||
|
||||
private import DotNet
|
||||
import semmle.code.csharp.Location
|
||||
|
||||
/**
|
||||
* A .Net program element.
|
||||
*/
|
||||
deprecated class Element extends @dotnet_element {
|
||||
/** Gets a textual representation of this element. */
|
||||
cached
|
||||
string toString() { none() }
|
||||
|
||||
/** Gets the location of this element. */
|
||||
pragma[nomagic]
|
||||
Location getLocation() { none() }
|
||||
|
||||
/**
|
||||
* Gets a location of this element, which can include locations in
|
||||
* both DLLs and source files.
|
||||
*/
|
||||
Location getALocation() { none() }
|
||||
|
||||
/** Gets the file containing this element. */
|
||||
final File getFile() { result = this.getLocation().getFile() }
|
||||
|
||||
/** Holds if this element is from source code. */
|
||||
predicate fromSource() { this.getFile().fromSource() }
|
||||
|
||||
/** Holds if this element is from an assembly. */
|
||||
predicate fromLibrary() { this.getFile().fromLibrary() }
|
||||
|
||||
/**
|
||||
* Gets the "language" of this program element, as defined by the extension of the filename.
|
||||
* For example, C# has language "cs", and Visual Basic has language "vb".
|
||||
*/
|
||||
final string getLanguage() { result = this.getLocation().getFile().getExtension() }
|
||||
|
||||
/** Gets the full textual representation of this element, including type information. */
|
||||
string toStringWithTypes() { result = this.toString() }
|
||||
|
||||
/**
|
||||
* Gets a comma-separated list of the names of the primary CodeQL classes to which this element belongs.
|
||||
*
|
||||
* If no primary class can be determined, the result is `"???"`.
|
||||
*/
|
||||
final string getPrimaryQlClasses() {
|
||||
result = strictconcat(this.getAPrimaryQlClass(), ",")
|
||||
or
|
||||
not exists(this.getAPrimaryQlClass()) and
|
||||
result = "???"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of a primary CodeQL class to which this element belongs.
|
||||
*
|
||||
* For most elements, this is simply the most precise syntactic category to
|
||||
* which they belong; for example, `AddExpr` is a primary class, but
|
||||
* `BinaryOperation` is not.
|
||||
*
|
||||
* If no primary classes match, this predicate has no result. If multiple
|
||||
* primary classes match, this predicate can have multiple results.
|
||||
*
|
||||
* See also `getPrimaryQlClasses`, which is better to use in most cases.
|
||||
*/
|
||||
string getAPrimaryQlClass() { none() }
|
||||
}
|
||||
|
||||
/** An element that has a name. */
|
||||
deprecated class NamedElement extends Element, @dotnet_named_element {
|
||||
/** Gets the name of this element. */
|
||||
cached
|
||||
string getName() { none() }
|
||||
|
||||
/** Holds if this element has name 'name'. */
|
||||
final predicate hasName(string name) { name = this.getName() }
|
||||
|
||||
/**
|
||||
* Gets the fully qualified name of this element, for example the
|
||||
* fully qualified name of `M` on line 3 is `N.C.M` in
|
||||
*
|
||||
* ```csharp
|
||||
* namespace N {
|
||||
* class C {
|
||||
* void M(int i, string s) { }
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
cached
|
||||
deprecated final string getQualifiedName() {
|
||||
exists(string qualifier, string name | this.hasQualifiedName(qualifier, name) |
|
||||
if qualifier = "" then result = name else result = qualifier + "." + name
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the fully qualified name of this element, for example the
|
||||
* fully qualified name of `M` on line 3 is `N.C.M` in
|
||||
*
|
||||
* ```csharp
|
||||
* namespace N {
|
||||
* class C {
|
||||
* void M(int i, string s) { }
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* Unbound generic types, such as `IList<T>`, are represented as
|
||||
* ``System.Collections.Generic.IList`1``.
|
||||
*/
|
||||
cached
|
||||
final string getFullyQualifiedName() {
|
||||
exists(string qualifier, string name | this.hasFullyQualifiedName(qualifier, name) |
|
||||
if qualifier = "" then result = name else result = qualifier + "." + name
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `hasFullyQualifiedName` instead.
|
||||
*
|
||||
* Holds if this element has the qualified name `qualifier`.`name`.
|
||||
*/
|
||||
cached
|
||||
deprecated predicate hasQualifiedName(string qualifier, string name) {
|
||||
qualifier = "" and name = this.getName()
|
||||
}
|
||||
|
||||
/** Holds if this element has the fully qualified name `qualifier`.`name`. */
|
||||
cached
|
||||
predicate hasFullyQualifiedName(string qualifier, string name) {
|
||||
qualifier = "" and name = this.getName()
|
||||
}
|
||||
|
||||
/** Gets a unique string label for this element. */
|
||||
cached
|
||||
string getLabel() { none() }
|
||||
|
||||
/** Holds if `other` has the same metadata handle in the same assembly. */
|
||||
predicate matchesHandle(NamedElement other) {
|
||||
exists(Assembly asm, int handle |
|
||||
metadata_handle(this, asm, handle) and
|
||||
metadata_handle(other, asm, handle)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this element was compiled from source code that is also present in the
|
||||
* database. That is, this element corresponds to another element from source.
|
||||
*/
|
||||
predicate compiledFromSource() {
|
||||
not this.fromSource() and
|
||||
exists(NamedElement other | other != this |
|
||||
this.matchesHandle(other) and
|
||||
other.fromSource()
|
||||
)
|
||||
}
|
||||
|
||||
override string toString() { result = this.getName() }
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
/**
|
||||
* Provides .Net expression classes.
|
||||
*/
|
||||
|
||||
import Expr
|
||||
import Type
|
||||
import Callable
|
||||
|
||||
/** An expression. */
|
||||
deprecated class Expr extends Element, @dotnet_expr {
|
||||
/** Gets the callable containing this expression. */
|
||||
Callable getEnclosingCallable() { none() }
|
||||
|
||||
/** Gets the type of this expression. */
|
||||
Type getType() { none() }
|
||||
|
||||
/** Gets the constant value of this expression, if any. */
|
||||
string getValue() { none() }
|
||||
|
||||
/** Holds if this expression has a value. */
|
||||
final predicate hasValue() { exists(this.getValue()) }
|
||||
|
||||
/**
|
||||
* Gets the parent of this expression. This is for example the element
|
||||
* that uses the result of this expression.
|
||||
*/
|
||||
Element getParent() { none() }
|
||||
}
|
||||
|
||||
/** A call. */
|
||||
deprecated class Call extends Expr, @dotnet_call {
|
||||
/** Gets the target of this call. */
|
||||
Callable getTarget() { none() }
|
||||
|
||||
/** Gets any potential target of this call. */
|
||||
Callable getARuntimeTarget() { none() }
|
||||
|
||||
/**
|
||||
* Gets the `i`th "raw" argument to this call, if any.
|
||||
* For instance methods, argument 0 is the qualifier.
|
||||
*/
|
||||
Expr getRawArgument(int i) { none() }
|
||||
|
||||
/** Gets the `i`th argument to this call, if any. */
|
||||
Expr getArgument(int i) { none() }
|
||||
|
||||
/** Gets an argument to this call. */
|
||||
Expr getAnArgument() { result = this.getArgument(_) }
|
||||
|
||||
/** Gets the expression that is supplied for parameter `p`. */
|
||||
Expr getArgumentForParameter(Parameter p) { none() }
|
||||
}
|
||||
|
||||
/** A literal expression. */
|
||||
deprecated class Literal extends Expr, @dotnet_literal { }
|
||||
|
||||
/** A string literal expression. */
|
||||
deprecated class StringLiteral extends Literal, @dotnet_string_literal { }
|
||||
|
||||
/** An integer literal expression. */
|
||||
deprecated class IntLiteral extends Literal, @dotnet_int_literal { }
|
||||
|
||||
/** A `null` literal expression. */
|
||||
deprecated class NullLiteral extends Literal, @dotnet_null_literal { }
|
||||
@@ -1,72 +0,0 @@
|
||||
/** Provides classes for generic types and methods. */
|
||||
|
||||
import Declaration
|
||||
|
||||
/**
|
||||
* A generic declaration. Either an unbound generic (`UnboundGeneric`) or a
|
||||
* constructed generic (`ConstructedGeneric`).
|
||||
*/
|
||||
abstract deprecated class Generic extends Declaration, @dotnet_generic { }
|
||||
|
||||
/** An unbound generic. */
|
||||
abstract deprecated class UnboundGeneric extends Generic {
|
||||
/** Gets the `i`th type parameter, if any. */
|
||||
abstract TypeParameter getTypeParameter(int i);
|
||||
|
||||
/** Gets a type parameter. */
|
||||
TypeParameter getATypeParameter() { result = this.getTypeParameter(_) }
|
||||
|
||||
/**
|
||||
* Gets one of the constructed versions of this declaration,
|
||||
* which has been bound to a specific set of types.
|
||||
*/
|
||||
ConstructedGeneric getAConstructedGeneric() { result.getUnboundGeneric() = this }
|
||||
|
||||
/** Gets the total number of type parameters. */
|
||||
int getNumberOfTypeParameters() { result = count(int i | exists(this.getTypeParameter(i))) }
|
||||
}
|
||||
|
||||
/** A constructed generic. */
|
||||
abstract deprecated class ConstructedGeneric extends Generic {
|
||||
/** Gets the `i`th type argument, if any. */
|
||||
abstract Type getTypeArgument(int i);
|
||||
|
||||
/** Gets a type argument. */
|
||||
Type getATypeArgument() { result = this.getTypeArgument(_) }
|
||||
|
||||
/**
|
||||
* Gets the unbound generic declaration from which this declaration was
|
||||
* constructed.
|
||||
*/
|
||||
UnboundGeneric getUnboundGeneric() { none() }
|
||||
|
||||
/** Gets the total number of type arguments. */
|
||||
final int getNumberOfTypeArguments() { result = count(int i | exists(this.getTypeArgument(i))) }
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
* Constructs the label suffix for a generic method or type.
|
||||
*/
|
||||
deprecated string getGenericsLabel(Generic g) {
|
||||
result = "`" + g.(UnboundGeneric).getNumberOfTypeParameters()
|
||||
or
|
||||
result = "<" + typeArgs(g) + ">"
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
deprecated private string getTypeArgumentLabel(ConstructedGeneric generic, int p) {
|
||||
result = generic.getTypeArgument(p).getLabel()
|
||||
}
|
||||
|
||||
language[monotonicAggregates]
|
||||
pragma[nomagic]
|
||||
deprecated private string typeArgs(ConstructedGeneric generic) {
|
||||
result =
|
||||
concat(int p |
|
||||
p in [0 .. generic.getNumberOfTypeArguments() - 1]
|
||||
|
|
||||
getTypeArgumentLabel(generic, p), ","
|
||||
)
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
/**
|
||||
* Provides the `Namespace` class to represent .Net namespaces.
|
||||
*/
|
||||
|
||||
private import Declaration
|
||||
private import semmle.code.csharp.commons.QualifiedName
|
||||
|
||||
/** A namespace. */
|
||||
deprecated class Namespace extends Declaration, @namespace {
|
||||
/**
|
||||
* Gets the parent namespace, if any. For example the parent namespace of `System.IO`
|
||||
* is `System`. The parent namespace of `System` is the global namespace.
|
||||
*/
|
||||
Namespace getParentNamespace() { none() }
|
||||
|
||||
/**
|
||||
* Gets a child namespace, if any. For example `System.IO` is a child in
|
||||
* the namespace `System`.
|
||||
*/
|
||||
Namespace getAChildNamespace() { result.getParentNamespace() = this }
|
||||
|
||||
/**
|
||||
* Holds if this namespace has the qualified name `qualifier`.`name`.
|
||||
*
|
||||
* For example if the qualified name is `System.Collections.Generic`, then
|
||||
* `qualifier`=`System.Collections` and `name`=`Generic`.
|
||||
*/
|
||||
deprecated override predicate hasQualifiedName(string qualifier, string name) {
|
||||
namespaceHasQualifiedName(this, qualifier, name)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this namespace has the qualified name `qualifier`.`name`.
|
||||
*
|
||||
* For example if the qualified name is `System.Collections.Generic`, then
|
||||
* `qualifier`=`System.Collections` and `name`=`Generic`.
|
||||
*/
|
||||
override predicate hasFullyQualifiedName(string qualifier, string name) {
|
||||
namespaceHasQualifiedName(this, qualifier, name)
|
||||
}
|
||||
|
||||
/** Gets a textual representation of this namespace. */
|
||||
override string toString() { result = this.getFullName() }
|
||||
|
||||
/** Holds if this is the global namespace. */
|
||||
final predicate isGlobalNamespace() { this.getName() = "" }
|
||||
|
||||
/** Gets the simple name of this namespace, for example `IO` in `System.IO`. */
|
||||
final override string getName() { namespaces(this, result) }
|
||||
|
||||
final override string getUndecoratedName() { namespaces(this, result) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "Namespace" }
|
||||
|
||||
/**
|
||||
* Get the fully qualified name of this namespace.
|
||||
*/
|
||||
string getFullName() {
|
||||
exists(string namespace, string name |
|
||||
namespaceHasQualifiedName(this, namespace, name) and
|
||||
result = getQualifiedName(namespace, name)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** The global namespace. */
|
||||
deprecated class GlobalNamespace extends Namespace {
|
||||
GlobalNamespace() { this.getName() = "" }
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
/**
|
||||
* Provides a general parameterizable entity to represent constructs that might
|
||||
* have parameters.
|
||||
*/
|
||||
|
||||
import Declaration
|
||||
|
||||
/**
|
||||
* A general parameterizable entity, such as a callable, delegate type, accessor,
|
||||
* indexer, or function pointer type.
|
||||
*/
|
||||
deprecated class Parameterizable extends Declaration, @dotnet_parameterizable {
|
||||
/** Gets raw parameter `i`, including the `this` parameter at index 0. */
|
||||
Parameter getRawParameter(int i) { none() }
|
||||
|
||||
/** Gets the `i`th parameter, excluding the `this` parameter. */
|
||||
Parameter getParameter(int i) { none() }
|
||||
|
||||
/** Gets the number of parameters of this callable. */
|
||||
int getNumberOfParameters() { result = count(this.getAParameter()) }
|
||||
|
||||
/** Holds if this declaration has no parameters. */
|
||||
predicate hasNoParameters() { not exists(this.getAParameter()) }
|
||||
|
||||
/** Gets a parameter, if any. */
|
||||
Parameter getAParameter() { result = this.getParameter(_) }
|
||||
|
||||
/** Gets a raw parameter (including the qualifier), if any. */
|
||||
final Parameter getARawParameter() { result = this.getRawParameter(_) }
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
/**
|
||||
* Provides classes for .Net types.
|
||||
*/
|
||||
|
||||
import Declaration
|
||||
import Namespace
|
||||
import Callable
|
||||
import Generics
|
||||
|
||||
/**
|
||||
* A type. Either a value or reference type (`ValueOrRefType`), a type parameter (`TypeParameter`),
|
||||
* a pointer type (`PointerType`), or an array type (`ArrayType`).
|
||||
*/
|
||||
deprecated class Type extends Declaration, @dotnet_type {
|
||||
/** Gets the name of this type without additional syntax such as `[]` or `*`. */
|
||||
override string getUndecoratedName() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A value or reference type.
|
||||
*/
|
||||
deprecated class ValueOrRefType extends Type, @dotnet_valueorreftype {
|
||||
/** Gets the namespace declaring this type, if any. */
|
||||
Namespace getDeclaringNamespace() { none() }
|
||||
|
||||
private string getPrefixWithTypes() {
|
||||
result = this.getDeclaringType().getLabel() + "."
|
||||
or
|
||||
if this.getDeclaringNamespace().isGlobalNamespace()
|
||||
then result = ""
|
||||
else result = this.getDeclaringNamespace().getFullName() + "."
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private string getLabelNonGeneric() {
|
||||
not this instanceof Generic and
|
||||
result = this.getPrefixWithTypes() + this.getUndecoratedName()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private string getLabelGeneric() {
|
||||
result = this.getPrefixWithTypes() + this.getUndecoratedName() + getGenericsLabel(this)
|
||||
}
|
||||
|
||||
override string getLabel() {
|
||||
result = this.getLabelNonGeneric() or
|
||||
result = this.getLabelGeneric()
|
||||
}
|
||||
|
||||
/** Gets a base type of this type, if any. */
|
||||
ValueOrRefType getABaseType() { none() }
|
||||
|
||||
/** Holds if this type is a `record`. */
|
||||
predicate isRecord() { exists(RecordCloneCallable c | c.getDeclaringType() = this) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A type parameter, for example `T` in `System.Nullable<T>`.
|
||||
*/
|
||||
deprecated class TypeParameter extends Type, @dotnet_type_parameter {
|
||||
/** Gets the generic type or method declaring this type parameter. */
|
||||
UnboundGeneric getDeclaringGeneric() { this = result.getATypeParameter() }
|
||||
|
||||
/** Gets the index of this type parameter. For example the index of `U` in `Func<T,U>` is 1. */
|
||||
int getIndex() { none() }
|
||||
|
||||
final override string getLabel() { result = "!" + this.getIndex() }
|
||||
|
||||
override string getUndecoratedName() { result = "!" + this.getIndex() }
|
||||
}
|
||||
|
||||
/** A pointer type. */
|
||||
deprecated class PointerType extends Type, @dotnet_pointer_type {
|
||||
/** Gets the type referred by this pointer type, for example `char` in `char*`. */
|
||||
Type getReferentType() { none() }
|
||||
|
||||
override string getName() { result = this.getReferentType().getName() + "*" }
|
||||
|
||||
final override string getLabel() { result = this.getReferentType().getLabel() + "*" }
|
||||
|
||||
override string toStringWithTypes() { result = this.getReferentType().toStringWithTypes() + "*" }
|
||||
}
|
||||
|
||||
/** An array type. */
|
||||
deprecated class ArrayType extends ValueOrRefType, @dotnet_array_type {
|
||||
/** Gets the type of the array element. */
|
||||
Type getElementType() { none() }
|
||||
|
||||
final override string getLabel() { result = this.getElementType().getLabel() + "[]" }
|
||||
|
||||
override string toStringWithTypes() { result = this.getElementType().toStringWithTypes() + "[]" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ArrayType" }
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
/**
|
||||
* Provides some useful .Net classes.
|
||||
*/
|
||||
|
||||
import Element
|
||||
import Expr
|
||||
|
||||
/** A throw element. */
|
||||
deprecated class Throw extends Element, @dotnet_throw {
|
||||
/** Gets the expression being thrown, if any. */
|
||||
Expr getExpr() { none() }
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
/** Provides classes for .Net variables, such as fields and parameters. */
|
||||
|
||||
import Declaration
|
||||
import Callable
|
||||
|
||||
/** A .Net variable. */
|
||||
deprecated class Variable extends Declaration, @dotnet_variable {
|
||||
/** Gets the type of this variable. */
|
||||
Type getType() { none() }
|
||||
}
|
||||
|
||||
/** A .Net field. */
|
||||
deprecated class Field extends Variable, Member, @dotnet_field { }
|
||||
|
||||
/** A parameter to a .Net callable, property or function pointer type. */
|
||||
deprecated class Parameter extends Variable, @dotnet_parameter {
|
||||
/** Gets the raw position of this parameter, including the `this` parameter at index 0. */
|
||||
final int getRawPosition() { this = this.getDeclaringElement().getRawParameter(result) }
|
||||
|
||||
/** Gets the position of this parameter, excluding the `this` parameter. */
|
||||
int getPosition() { this = this.getDeclaringElement().getParameter(result) }
|
||||
|
||||
/** Gets the callable defining this parameter, if any. */
|
||||
Callable getCallable() { result = this.getDeclaringElement() }
|
||||
|
||||
/** Gets the declaring `Parameterizable`. */
|
||||
Parameterizable getDeclaringElement() { none() }
|
||||
|
||||
/** Holds if this is an `out` parameter. */
|
||||
predicate isOut() { none() }
|
||||
|
||||
/** Holds if this is a `ref` parameter. */
|
||||
predicate isRef() { none() }
|
||||
}
|
||||
Reference in New Issue
Block a user