@@ -8,7 +8,6 @@ import Stmt
88import Type
99import exprs.Call
1010private import commons.QualifiedName
11- private import dotnet
1211private import semmle.code.csharp.ExprOrStmtParent
1312private import semmle.code.csharp.metrics.Complexity
1413private 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