C#: Make implicit this receivers explicit

This commit is contained in:
Kasper Svendsen
2023-05-09 11:25:54 +02:00
parent ffa30284ea
commit 3041fdebba
23 changed files with 125 additions and 119 deletions

View File

@@ -14,8 +14,8 @@ import csharp
class CommentedOutCode extends CommentBlock {
CommentedOutCode() {
not isXmlCommentBlock() and
2 * count(getAProbableCodeLine()) > count(getANonEmptyLine())
not this.isXmlCommentBlock() and
2 * count(this.getAProbableCodeLine()) > count(this.getANonEmptyLine())
}
}

View File

@@ -22,7 +22,7 @@ predicate potentiallyUsedFromXaml(RefType t) {
class ExportAttribute extends Attribute {
ExportAttribute() {
getType().hasQualifiedName("System.ComponentModel.Composition", "ExportAttribute")
this.getType().hasQualifiedName("System.ComponentModel.Composition", "ExportAttribute")
}
}

View File

@@ -14,12 +14,12 @@ import semmle.code.csharp.frameworks.System
/** A call to IDisposable.Dispose or a method that overrides it. */
class DisposeCall extends MethodCall {
DisposeCall() { getTarget() instanceof DisposeMethod }
DisposeCall() { this.getTarget() instanceof DisposeMethod }
/** The object being disposed by the call (provided it can be easily determined). */
Variable getDisposee() {
exists(VariableAccess va |
va = getQualifier().stripCasts() and
va = this.getQualifier().stripCasts() and
result = va.getTarget()
)
}

View File

@@ -38,7 +38,7 @@ private predicate containerSizeAccess(PropertyAccess pa, string containerKind) {
}
class ZeroLiteral extends Expr {
ZeroLiteral() { getValue() = "0" }
ZeroLiteral() { this.getValue() = "0" }
}
/**

View File

@@ -41,9 +41,9 @@ class NonShortCircuit extends BinaryBitwiseOperation {
this instanceof BitwiseOrExpr
) and
not exists(AssignBitwiseOperation abo | abo.getExpandedAssignment().getRValue() = this) and
getLeftOperand().getType() instanceof BoolType and
getRightOperand().getType() instanceof BoolType and
getRightOperand() instanceof DangerousExpression
this.getLeftOperand().getType() instanceof BoolType and
this.getRightOperand().getType() instanceof BoolType and
this.getRightOperand() instanceof DangerousExpression
}
}

View File

@@ -20,7 +20,7 @@ abstract class BadDynamicCall extends DynamicExpr {
abstract AssignableRead getARelevantVariableAccess(int i);
Type possibleBadTypeForRelevantSource(Variable v, int i, Expr source) {
exists(Type t | t = possibleTypeForRelevantSource(v, i, source) |
exists(Type t | t = this.possibleTypeForRelevantSource(v, i, source) |
// If the source can have the type of an interface or an abstract class,
// then all possible sub types are, in principle, possible
t instanceof Interface and result.isImplicitlyConvertibleTo(t)
@@ -37,7 +37,7 @@ abstract class BadDynamicCall extends DynamicExpr {
private Type possibleTypeForRelevantSource(Variable v, int i, Expr source) {
exists(AssignableRead read, Ssa::Definition ssaDef, Ssa::ExplicitDefinition ultimateSsaDef |
read = getARelevantVariableAccess(i) and
read = this.getARelevantVariableAccess(i) and
v = read.getTarget() and
result = source.getType() and
read = ssaDef.getARead() and
@@ -55,28 +55,30 @@ abstract class BadDynamicCall extends DynamicExpr {
}
class BadDynamicMethodCall extends BadDynamicCall, DynamicMethodCall {
override AssignableRead getARelevantVariableAccess(int i) { result = getQualifier() and i = -1 }
override AssignableRead getARelevantVariableAccess(int i) {
result = this.getQualifier() and i = -1
}
override predicate isBad(Variable v, ValueOrRefType pt, Expr pts, string message, string target) {
pt = possibleBadTypeForRelevantSource(v, -1, pts) and
not exists(Method m | m = getARuntimeTarget() |
pt = this.possibleBadTypeForRelevantSource(v, -1, pts) and
not exists(Method m | m = this.getARuntimeTarget() |
pt.isImplicitlyConvertibleTo(m.getDeclaringType())
) and
message =
"The $@ of this dynamic method invocation can obtain (from $@) type $@, which does not have a method '"
+ getLateBoundTargetName() + "' with the appropriate signature." and
+ this.getLateBoundTargetName() + "' with the appropriate signature." and
target = "target"
}
}
class BadDynamicOperatorCall extends BadDynamicCall, DynamicOperatorCall {
override AssignableRead getARelevantVariableAccess(int i) { result = getRuntimeArgument(i) }
override AssignableRead getARelevantVariableAccess(int i) { result = this.getRuntimeArgument(i) }
override predicate isBad(Variable v, ValueOrRefType pt, Expr pts, string message, string target) {
exists(int i |
pt = possibleBadTypeForRelevantSource(v, i, pts) and
pt = this.possibleBadTypeForRelevantSource(v, i, pts) and
not pt.containsTypeParameters() and
not exists(Type paramType | paramType = getADynamicParameterType(_, i) |
not exists(Type paramType | paramType = this.getADynamicParameterType(_, i) |
pt.isImplicitlyConvertibleTo(paramType)
or
// If either the argument type or the parameter type contains type parameters,
@@ -93,11 +95,11 @@ class BadDynamicOperatorCall extends BadDynamicCall, DynamicOperatorCall {
) and
message =
"The $@ of this dynamic operator can obtain (from $@) type $@, which does not match an operator '"
+ getLateBoundTargetName() + "' with the appropriate signature."
+ this.getLateBoundTargetName() + "' with the appropriate signature."
}
private Type getADynamicParameterType(Operator o, int i) {
o = getARuntimeTarget() and
o = this.getARuntimeTarget() and
result = o.getParameter(i).getType()
}
}

View File

@@ -27,26 +27,26 @@ class ReferenceEqualityTestOnObject extends EqualityOperation {
// One or both of the operands has type object or interface.
exists(getObjectOperand(this)) and
// Neither operand is 'null'.
not getAnOperand() instanceof NullLiteral and
not exists(Type t | t = getAnOperand().stripImplicitCasts().getType() |
not this.getAnOperand() instanceof NullLiteral and
not exists(Type t | t = this.getAnOperand().stripImplicitCasts().getType() |
t instanceof NullType or
t instanceof ValueType
) and
// Neither operand is a constant - a reference comparison may well be intended for those.
not getAnOperand().(FieldAccess).getTarget().isReadOnly() and
not getAnOperand().hasValue() and
not this.getAnOperand().(FieldAccess).getTarget().isReadOnly() and
not this.getAnOperand().hasValue() and
// Not a short-cut test in a custom `Equals` method
not exists(EqualsMethod m |
getEnclosingCallable() = m and
getAnOperand() instanceof ThisAccess and
getAnOperand() = m.getParameter(0).getAnAccess()
this.getEnclosingCallable() = m and
this.getAnOperand() instanceof ThisAccess and
this.getAnOperand() = m.getParameter(0).getAnAccess()
) and
// Reference comparisons in Moq methods are used to define mocks
not exists(MethodCall mc, Namespace n |
mc.getTarget().getDeclaringType().getNamespace().getParentNamespace*() = n and
n.hasName("Moq") and
not exists(n.getParentNamespace()) and
mc.getAnArgument() = getEnclosingCallable()
mc.getAnArgument() = this.getEnclosingCallable()
)
}
@@ -54,7 +54,7 @@ class ReferenceEqualityTestOnObject extends EqualityOperation {
result = getObjectOperand(this) and
// Avoid duplicate results: only include left operand if both operands
// have object type
(result = getRightOperand() implies not getLeftOperand() = getObjectOperand(this))
(result = this.getRightOperand() implies not this.getLeftOperand() = getObjectOperand(this))
}
}

View File

@@ -50,7 +50,7 @@ abstract class LossOfPrecision extends Expr {
Type convertedType;
LossOfPrecision() {
getType() instanceof IntegralType and
this.getType() instanceof IntegralType and
convertedToFloatOrDecimal(this, convertedType)
}

View File

@@ -26,11 +26,11 @@ Stmt getASuccessorStmt(Stmt s) {
}
class IfThenStmt extends IfStmt {
IfThenStmt() { not exists(getElse()) }
IfThenStmt() { not exists(this.getElse()) }
}
class IfThenElseStmt extends IfStmt {
IfThenElseStmt() { exists(getElse()) }
IfThenElseStmt() { exists(this.getElse()) }
}
Stmt getTrailingBody(Stmt s) {
@@ -49,16 +49,16 @@ abstract class UnbracedControlStmt extends Stmt {
abstract Stmt getSuccessorStmt();
private Stmt getACandidate() {
getSuccessorStmt() = result and
this.getSuccessorStmt() = result and
getBlockStmt(this) = getBlockStmt(result)
}
private Location getBodyLocation() { result = getBody().getLocation() }
private Location getBodyLocation() { result = this.getBody().getLocation() }
pragma[noopt]
Stmt getAConfusingTrailingStmt() {
result = getACandidate() and
exists(Location l1, Location l2 | l1 = getBodyLocation() and l2 = result.getLocation() |
result = this.getACandidate() and
exists(Location l1, Location l2 | l1 = this.getBodyLocation() and l2 = result.getLocation() |
// This test is slightly unreliable
// because tabs are counted as 1 column.
// But it's accurate enough to be useful, and will
@@ -79,7 +79,7 @@ class UnbracedIfStmt extends UnbracedControlStmt {
override Stmt getBody() { result = getTrailingBody(this) }
override Stmt getSuccessorStmt() {
result = getASuccessorStmt(getBody()) and
result = getASuccessorStmt(this.getBody()) and
result != this
}
}
@@ -95,7 +95,7 @@ class UnbracedLoopStmt extends UnbracedControlStmt {
override Stmt getSuccessorStmt() {
result = getASuccessorStmt(this) and
result != getBody()
result != this.getBody()
}
}

View File

@@ -19,7 +19,7 @@ import semmle.code.csharp.frameworks.system.web.Mvc
/** An `AuthorizationFilter` that calls the `AntiForgery.Validate` method. */
class AntiForgeryAuthorizationFilter extends AuthorizationFilter {
AntiForgeryAuthorizationFilter() {
getOnAuthorizationMethod().calls*(any(AntiForgeryClass a).getValidateMethod())
this.getOnAuthorizationMethod().calls*(any(AntiForgeryClass a).getValidateMethod())
}
}

View File

@@ -191,7 +191,7 @@ abstract private class OnAppendCookieTrackingConfig extends DataFlow::Configurat
override predicate isSink(DataFlow::Node sink) {
exists(PropertyWrite pw, Assignment a |
pw.getProperty().getDeclaringType() instanceof MicrosoftAspNetCoreHttpCookieOptions and
pw.getProperty().getName() = propertyName() and
pw.getProperty().getName() = this.propertyName() and
a.getLValue() = pw and
exists(Expr val |
DataFlow::localExprFlow(val, a.getRValue()) and

View File

@@ -150,10 +150,10 @@ class CSharpType extends TCSharpType {
abstract string toString();
/** Gets a string used in IR dumps */
string getDumpString() { result = toString() }
string getDumpString() { result = this.toString() }
/** Gets the size of the type in bytes, if known. */
final int getByteSize() { result = getIRType().getByteSize() }
final int getByteSize() { result = this.getIRType().getByteSize() }
/**
* Gets the `IRType` that represents this `CSharpType`. Many different `CSharpType`s can map to a
@@ -168,7 +168,7 @@ class CSharpType extends TCSharpType {
*/
abstract predicate hasType(Type type, boolean isGLValue);
final predicate hasUnspecifiedType(Type type, boolean isGLValue) { hasType(type, isGLValue) }
final predicate hasUnspecifiedType(Type type, boolean isGLValue) { this.hasType(type, isGLValue) }
}
/**

View File

@@ -41,7 +41,7 @@ abstract class Bound extends TBound {
abstract Instruction getInstruction(int delta);
/** Gets an expression that equals this bound. */
Instruction getInstruction() { result = getInstruction(0) }
Instruction getInstruction() { result = this.getInstruction(0) }
abstract Location getLocation();
}

View File

@@ -194,7 +194,7 @@ class NoReason extends Reason, TNoReason {
class CondReason extends Reason, TCondReason {
IRGuardCondition getCond() { this = TCondReason(result) }
override string toString() { result = getCond().toString() }
override string toString() { result = this.getCond().toString() }
}
/**
@@ -222,10 +222,10 @@ private predicate safeCast(IntegralType fromtyp, IntegralType totyp) {
private class SafeCastInstruction extends ConvertInstruction {
SafeCastInstruction() {
safeCast(getResultType(), getUnary().getResultType())
safeCast(this.getResultType(), this.getUnary().getResultType())
or
getResultType() instanceof PointerType and
getUnary().getResultType() instanceof PointerType
this.getResultType() instanceof PointerType and
this.getUnary().getResultType() instanceof PointerType
}
}
@@ -260,14 +260,14 @@ private predicate typeBound(IntegralType typ, int lowerbound, int upperbound) {
private class NarrowingCastInstruction extends ConvertInstruction {
NarrowingCastInstruction() {
not this instanceof SafeCastInstruction and
typeBound(getResultType(), _, _)
typeBound(this.getResultType(), _, _)
}
/** Gets the lower bound of the resulting type. */
int getLowerBound() { typeBound(getResultType(), result, _) }
int getLowerBound() { typeBound(this.getResultType(), result, _) }
/** Gets the upper bound of the resulting type. */
int getUpperBound() { typeBound(getResultType(), _, result) }
int getUpperBound() { typeBound(this.getResultType(), _, result) }
}
/**