Skip to content

Commit c606ab0

Browse files
committed
C#: Copy dotnet.Callable implementation.
1 parent d7dc73e commit c606ab0

File tree

1 file changed

+99
-12
lines changed

1 file changed

+99
-12
lines changed

csharp/ql/lib/semmle/code/csharp/Callable.qll

Lines changed: 99 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import Stmt
88
import Type
99
import exprs.Call
1010
private import commons.QualifiedName
11-
private import dotnet
1211
private import semmle.code.csharp.ExprOrStmtParent
1312
private import semmle.code.csharp.metrics.Complexity
1413
private import TypeRef
@@ -21,8 +20,73 @@ private import TypeRef
2120
* an anonymous function (`AnonymousFunctionExpr`), or a local function
2221
* (`LocalFunction`).
2322
*/
24-
class Callable extends DotNet::Callable, Parameterizable, ExprOrStmtParent, @callable {
25-
override Type getReturnType() { none() }
23+
class Callable extends Parameterizable, ExprOrStmtParent, @callable {
24+
pragma[noinline]
25+
private string getDeclaringTypeLabel() { result = this.getDeclaringType().getLabel() }
26+
27+
pragma[noinline]
28+
private string getParameterTypeLabelNonGeneric(int p) {
29+
not this instanceof Generic and
30+
result = this.getParameter(p).getType().getLabel()
31+
}
32+
33+
language[monotonicAggregates]
34+
pragma[nomagic]
35+
private string getMethodParamListNonGeneric() {
36+
result =
37+
concat(int p |
38+
p in [0 .. this.getNumberOfParameters() - 1]
39+
|
40+
this.getParameterTypeLabelNonGeneric(p), "," order by p
41+
)
42+
}
43+
44+
pragma[noinline]
45+
private string getParameterTypeLabelGeneric(int p) {
46+
this instanceof Generic and
47+
result = this.getParameter(p).getType().getLabel()
48+
}
49+
50+
language[monotonicAggregates]
51+
pragma[nomagic]
52+
private string getMethodParamListGeneric() {
53+
result =
54+
concat(int p |
55+
p in [0 .. this.getNumberOfParameters() - 1]
56+
|
57+
this.getParameterTypeLabelGeneric(p), "," order by p
58+
)
59+
}
60+
61+
pragma[noinline]
62+
private string getLabelNonGeneric() {
63+
not this instanceof Generic and
64+
result =
65+
this.getReturnTypeLabel() + " " + this.getDeclaringTypeLabel() + "." +
66+
this.getUndecoratedName() + "(" + this.getMethodParamListNonGeneric() + ")"
67+
}
68+
69+
pragma[noinline]
70+
private string getLabelGeneric() {
71+
result =
72+
this.getReturnTypeLabel() + " " + this.getDeclaringTypeLabel() + "." +
73+
this.getUndecoratedName() + getGenericsLabel(this) + "(" + this.getMethodParamListGeneric() +
74+
")"
75+
}
76+
77+
final override string getLabel() {
78+
result = this.getLabelNonGeneric() or
79+
result = this.getLabelGeneric()
80+
}
81+
82+
private string getReturnTypeLabel() {
83+
result = this.getReturnType().getLabel()
84+
or
85+
not exists(this.getReturnType()) and result = "System.Void"
86+
}
87+
88+
/** Gets the return type of this callable. */
89+
Type getReturnType() { none() }
2690

2791
/** Gets the annotated return type of this callable. */
2892
final AnnotatedType getAnnotatedReturnType() { result.appliesTo(this) }
@@ -65,7 +129,8 @@ class Callable extends DotNet::Callable, Parameterizable, ExprOrStmtParent, @cal
65129
result = this.getExpressionBody()
66130
}
67131

68-
override predicate hasBody() { exists(this.getBody()) }
132+
/** Holds if this callable has a body or an implementation. */
133+
predicate hasBody() { exists(this.getBody()) }
69134

70135
/**
71136
* Holds if this callable has a non-empty body. That is, either it has
@@ -196,7 +261,8 @@ class Callable extends DotNet::Callable, Parameterizable, ExprOrStmtParent, @cal
196261
)
197262
}
198263

199-
override predicate canReturn(DotNet::Expr e) {
264+
/** Holds if this callable can return expression `e`. */
265+
predicate canReturn(Expr e) {
200266
exists(ReturnStmt ret | ret.getEnclosingCallable() = this | e = ret.getExpr())
201267
or
202268
e = this.getExpressionBody() and
@@ -218,8 +284,6 @@ class Callable extends DotNet::Callable, Parameterizable, ExprOrStmtParent, @cal
218284

219285
/** Gets a `Call` that has this callable as a target. */
220286
Call getACall() { this = result.getTarget() }
221-
222-
override Parameter getAParameter() { result = Parameterizable.super.getAParameter() }
223287
}
224288

225289
/**
@@ -325,7 +389,7 @@ class ExtensionMethod extends Method {
325389
* }
326390
* ```
327391
*/
328-
class Constructor extends DotNet::Constructor, Callable, Member, Attributable, @constructor {
392+
class Constructor extends Callable, Member, Attributable, @constructor {
329393
override string getName() { constructors(this, result, _, _) }
330394

331395
override Type getReturnType() {
@@ -435,7 +499,7 @@ class PrimaryConstructor extends Constructor {
435499
* }
436500
* ```
437501
*/
438-
class Destructor extends DotNet::Destructor, Callable, Member, Attributable, @destructor {
502+
class Destructor extends Callable, Member, Attributable, @destructor {
439503
override string getName() { destructors(this, result, _, _) }
440504

441505
override Type getReturnType() {
@@ -497,10 +561,33 @@ class Operator extends Callable, Member, Attributable, Overridable, @operator {
497561
override Parameter getRawParameter(int i) { result = this.getParameter(i) }
498562
}
499563

564+
pragma[nomagic]
565+
private ValueOrRefType getARecordBaseType(ValueOrRefType t) {
566+
exists(Callable c |
567+
c.hasName("<Clone>$") and
568+
c.getNumberOfParameters() = 0 and
569+
t = c.getDeclaringType() and
570+
result = t
571+
)
572+
or
573+
result = getARecordBaseType(t).getABaseType()
574+
}
575+
500576
/** A clone method on a record. */
501-
class RecordCloneMethod extends Method, DotNet::RecordCloneCallable {
502-
override Constructor getConstructor() {
503-
result = DotNet::RecordCloneCallable.super.getConstructor()
577+
class RecordCloneMethod extends Method {
578+
RecordCloneMethod() {
579+
this.hasName("<Clone>$") and
580+
this.getNumberOfParameters() = 0 and
581+
this.getReturnType() = getARecordBaseType(this.getDeclaringType()) and
582+
this.(Member).isPublic() and
583+
not this.(Member).isStatic()
584+
}
585+
586+
/** Gets the constructor that this clone method calls. */
587+
Constructor getConstructor() {
588+
result.getDeclaringType() = this.getDeclaringType() and
589+
result.getNumberOfParameters() = 1 and
590+
result.getParameter(0).getType() = this.getDeclaringType()
504591
}
505592
}
506593

0 commit comments

Comments
 (0)