Skip to content

Commit 146d172

Browse files
committed
C#: Add extensions tests.
1 parent e4b0fa8 commit 146d172

File tree

4 files changed

+198
-0
lines changed

4 files changed

+198
-0
lines changed
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
using System;
2+
using System.Collections.Generic;
3+
4+
public static class MyExtensions
5+
{
6+
extension(string s)
7+
{
8+
public bool Prop1 => s.Length > 0;
9+
public bool Prop2 { get { return true; } set { } }
10+
public static bool StaticProp1 { get { return false; } }
11+
public bool M1() => s is not null;
12+
public string M2(string other) { return s + other; }
13+
public static int StaticM1() { return 0; }
14+
public static int StaticM2(string x) { return x.Length; }
15+
public static string operator *(int a, string b) { return ""; }
16+
}
17+
18+
extension(object)
19+
{
20+
public static int StaticObjectM1() { return 0; }
21+
public static int StaticObjectM2(string s) { return s.Length; }
22+
public static bool StaticProp => true;
23+
}
24+
}
25+
26+
public static class ClassicExtensions
27+
{
28+
public static bool M3(this string s) => s is not null;
29+
}
30+
31+
public class C
32+
{
33+
public static void CallingExtensions()
34+
{
35+
var s = "Hello World.";
36+
37+
// // Calling the extensions properties
38+
var x11 = s.Prop1;
39+
var x12 = s.Prop2;
40+
s.Prop2 = true;
41+
var x13 = string.StaticProp1;
42+
var x14 = object.StaticProp;
43+
44+
// Calling the extensions methods.
45+
var x21 = s.M1();
46+
var x22 = s.M2("!!!");
47+
var x23 = string.StaticM1();
48+
var x24 = string.StaticM2(s);
49+
var x25 = object.StaticObjectM1();
50+
var x26 = object.StaticObjectM2(s);
51+
52+
// Calling the extension operator.
53+
var x30 = 3 * s;
54+
55+
// Calling the classic extension method.
56+
var y = s.M3();
57+
58+
// Calling the compiler generated static extension methods.
59+
MyExtensions.M1(s);
60+
MyExtensions.M2(s, "!!!");
61+
MyExtensions.StaticM1();
62+
MyExtensions.StaticM2(s);
63+
MyExtensions.StaticObjectM1();
64+
MyExtensions.StaticObjectM2(s);
65+
66+
// Calling the compiler generated operator method.
67+
MyExtensions.op_Multiply(3, s);
68+
69+
// Calling the compiler generated methods used by the extension property accessors.
70+
MyExtensions.get_Prop1(s);
71+
MyExtensions.get_Prop2(s);
72+
MyExtensions.set_Prop2(s, false);
73+
MyExtensions.get_StaticProp();
74+
}
75+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
extensionMethodCallArgument
2+
| extensions.cs:45:19:45:24 | call to method M1 | extensions.cs:11:21:11:22 | M1 | extensions.cs:6:22:6:22 | s | 0 | extensions.cs:45:19:45:19 | access to local variable s |
3+
| extensions.cs:46:19:46:29 | call to method M2 | extensions.cs:12:23:12:24 | M2 | extensions.cs:6:22:6:22 | s | 0 | extensions.cs:46:19:46:19 | access to local variable s |
4+
| extensions.cs:46:19:46:29 | call to method M2 | extensions.cs:12:23:12:24 | M2 | extensions.cs:12:33:12:37 | other | 1 | extensions.cs:46:24:46:28 | "!!!" |
5+
| extensions.cs:48:19:48:36 | call to method StaticM2 | extensions.cs:14:27:14:34 | StaticM2 | extensions.cs:14:43:14:43 | x | 0 | extensions.cs:48:35:48:35 | access to local variable s |
6+
| extensions.cs:50:19:50:42 | call to method StaticObjectM2 | extensions.cs:21:27:21:40 | StaticObjectM2 | extensions.cs:21:49:21:49 | s | 0 | extensions.cs:50:41:50:41 | access to local variable s |
7+
| extensions.cs:56:17:56:22 | call to method M3 | extensions.cs:28:24:28:25 | M3 | extensions.cs:28:39:28:39 | s | 0 | extensions.cs:56:17:56:17 | access to local variable s |
8+
| extensions.cs:59:9:59:26 | call to method M1 | extensions.cs:11:21:11:22 | M1 | extensions.cs:6:22:6:22 | s | 0 | extensions.cs:59:25:59:25 | access to local variable s |
9+
| extensions.cs:60:9:60:33 | call to method M2 | extensions.cs:12:23:12:24 | M2 | extensions.cs:6:22:6:22 | s | 0 | extensions.cs:60:25:60:25 | access to local variable s |
10+
| extensions.cs:60:9:60:33 | call to method M2 | extensions.cs:12:23:12:24 | M2 | extensions.cs:12:33:12:37 | other | 1 | extensions.cs:60:28:60:32 | "!!!" |
11+
| extensions.cs:62:9:62:32 | call to method StaticM2 | extensions.cs:14:27:14:34 | StaticM2 | extensions.cs:14:43:14:43 | x | 0 | extensions.cs:62:31:62:31 | access to local variable s |
12+
| extensions.cs:64:9:64:38 | call to method StaticObjectM2 | extensions.cs:21:27:21:40 | StaticObjectM2 | extensions.cs:21:49:21:49 | s | 0 | extensions.cs:64:37:64:37 | access to local variable s |
13+
extensionMethodCalls
14+
| extensions.cs:45:19:45:24 | call to method M1 | extensions.cs:11:21:11:22 | M1 | extensions.cs:6:5:16:5 | extension(String) | MyExtensions+extension(String).M1 |
15+
| extensions.cs:46:19:46:29 | call to method M2 | extensions.cs:12:23:12:24 | M2 | extensions.cs:6:5:16:5 | extension(String) | MyExtensions+extension(String).M2 |
16+
| extensions.cs:47:19:47:35 | call to method StaticM1 | extensions.cs:13:27:13:34 | StaticM1 | extensions.cs:6:5:16:5 | extension(String) | MyExtensions+extension(String).StaticM1 |
17+
| extensions.cs:48:19:48:36 | call to method StaticM2 | extensions.cs:14:27:14:34 | StaticM2 | extensions.cs:6:5:16:5 | extension(String) | MyExtensions+extension(String).StaticM2 |
18+
| extensions.cs:49:19:49:41 | call to method StaticObjectM1 | extensions.cs:20:27:20:40 | StaticObjectM1 | extensions.cs:18:5:23:5 | extension(Object) | MyExtensions+extension(Object).StaticObjectM1 |
19+
| extensions.cs:50:19:50:42 | call to method StaticObjectM2 | extensions.cs:21:27:21:40 | StaticObjectM2 | extensions.cs:18:5:23:5 | extension(Object) | MyExtensions+extension(Object).StaticObjectM2 |
20+
| extensions.cs:56:17:56:22 | call to method M3 | extensions.cs:28:24:28:25 | M3 | extensions.cs:26:21:26:37 | ClassicExtensions | ClassicExtensions.M3 |
21+
| extensions.cs:59:9:59:26 | call to method M1 | extensions.cs:11:21:11:22 | M1 | extensions.cs:6:5:16:5 | extension(String) | MyExtensions+extension(String).M1 |
22+
| extensions.cs:60:9:60:33 | call to method M2 | extensions.cs:12:23:12:24 | M2 | extensions.cs:6:5:16:5 | extension(String) | MyExtensions+extension(String).M2 |
23+
| extensions.cs:61:9:61:31 | call to method StaticM1 | extensions.cs:13:27:13:34 | StaticM1 | extensions.cs:6:5:16:5 | extension(String) | MyExtensions+extension(String).StaticM1 |
24+
| extensions.cs:62:9:62:32 | call to method StaticM2 | extensions.cs:14:27:14:34 | StaticM2 | extensions.cs:6:5:16:5 | extension(String) | MyExtensions+extension(String).StaticM2 |
25+
| extensions.cs:63:9:63:37 | call to method StaticObjectM1 | extensions.cs:20:27:20:40 | StaticObjectM1 | extensions.cs:18:5:23:5 | extension(Object) | MyExtensions+extension(Object).StaticObjectM1 |
26+
| extensions.cs:64:9:64:38 | call to method StaticObjectM2 | extensions.cs:21:27:21:40 | StaticObjectM2 | extensions.cs:18:5:23:5 | extension(Object) | MyExtensions+extension(Object).StaticObjectM2 |
27+
extensionOperatorCallArgument
28+
| extensions.cs:15:39:15:39 | * | extensions.cs:53:19:53:23 | call to operator * | extensions.cs:15:45:15:45 | a | 0 | extensions.cs:53:19:53:19 | 3 |
29+
| extensions.cs:15:39:15:39 | * | extensions.cs:53:19:53:23 | call to operator * | extensions.cs:15:55:15:55 | b | 1 | extensions.cs:53:23:53:23 | access to local variable s |
30+
| extensions.cs:15:39:15:39 | * | extensions.cs:67:9:67:38 | call to operator * | extensions.cs:15:45:15:45 | a | 0 | extensions.cs:67:34:67:34 | 3 |
31+
| extensions.cs:15:39:15:39 | * | extensions.cs:67:9:67:38 | call to operator * | extensions.cs:15:55:15:55 | b | 1 | extensions.cs:67:37:67:37 | access to local variable s |
32+
extensionOperatorCalls
33+
| extensions.cs:53:19:53:23 | call to operator * | extensions.cs:15:39:15:39 | * | extensions.cs:6:5:16:5 | extension(String) | MyExtensions+extension(String).op_Multiply |
34+
| extensions.cs:67:9:67:38 | call to operator * | extensions.cs:15:39:15:39 | * | extensions.cs:6:5:16:5 | extension(String) | MyExtensions+extension(String).op_Multiply |
35+
extensionProperty
36+
| extensions.cs:8:21:8:25 | Prop1 | extensions.cs:6:5:16:5 | extension(String) |
37+
| extensions.cs:9:21:9:25 | Prop2 | extensions.cs:6:5:16:5 | extension(String) |
38+
| extensions.cs:10:28:10:38 | StaticProp1 | extensions.cs:6:5:16:5 | extension(String) |
39+
| extensions.cs:22:28:22:37 | StaticProp | extensions.cs:18:5:23:5 | extension(Object) |
40+
extensionPropertyCall
41+
| extensions.cs:38:19:38:25 | access to property Prop1 | extensions.cs:8:21:8:25 | Prop1 | extensions.cs:6:5:16:5 | extension(String) | MyExtensions+extension(String).Prop1 |
42+
| extensions.cs:39:19:39:25 | access to property Prop2 | extensions.cs:9:21:9:25 | Prop2 | extensions.cs:6:5:16:5 | extension(String) | MyExtensions+extension(String).Prop2 |
43+
| extensions.cs:40:9:40:15 | access to property Prop2 | extensions.cs:9:21:9:25 | Prop2 | extensions.cs:6:5:16:5 | extension(String) | MyExtensions+extension(String).Prop2 |
44+
| extensions.cs:41:19:41:36 | access to property StaticProp1 | extensions.cs:10:28:10:38 | StaticProp1 | extensions.cs:6:5:16:5 | extension(String) | MyExtensions+extension(String).StaticProp1 |
45+
| extensions.cs:42:19:42:35 | access to property StaticProp | extensions.cs:22:28:22:37 | StaticProp | extensions.cs:18:5:23:5 | extension(Object) | MyExtensions+extension(Object).StaticProp |
46+
extensionAccessorCall
47+
| extensions.cs:70:9:70:33 | call to extension accessor get_Prop1 | extensions.cs:8:30:8:41 | get_Prop1 | extensions.cs:8:21:8:25 | Prop1 | MyExtensions+extension(String).get_Prop1 |
48+
| extensions.cs:71:9:71:33 | call to extension accessor get_Prop2 | extensions.cs:9:29:9:31 | get_Prop2 | extensions.cs:9:21:9:25 | Prop2 | MyExtensions+extension(String).get_Prop2 |
49+
| extensions.cs:72:9:72:40 | call to extension accessor set_Prop2 | extensions.cs:9:50:9:52 | set_Prop2 | extensions.cs:9:21:9:25 | Prop2 | MyExtensions+extension(String).set_Prop2 |
50+
| extensions.cs:73:9:73:37 | call to extension accessor get_StaticProp | extensions.cs:22:42:22:45 | get_StaticProp | extensions.cs:22:28:22:37 | StaticProp | MyExtensions+extension(Object).get_StaticProp |
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import csharp
2+
3+
// - Method should be from source (it looks like it is considered) compiler generated.
4+
// - It appears that two methods are extracted
5+
// - One "generated" (which is what the compiler will generate).
6+
// - One "source" method, which reflects the method as it looks in source code.
7+
//. - Design decision: Only extract the associated extension implementation.
8+
// - Make tests for ExtendedType.
9+
// - Like there are extension methods, we need to declare isExtension for properties.
10+
// - Make QL classes similar to ExtensionMethod for Properties and Operators.
11+
// - Make sure we can declare MaD
12+
// - Check that control flow works as expected.
13+
// - Check that dataflow works as expected.
14+
query predicate extensionMethodCallArgument(
15+
ExtensionMethodCall emc, ExtensionMethod em, Parameter p, int i, Expr e
16+
) {
17+
em.getFile().getBaseName() = "extensions.cs" and
18+
emc.getTarget() = em and
19+
em.getParameter(i) = p and
20+
emc.getArgument(i) = e
21+
}
22+
23+
query predicate extensionMethodCalls(
24+
ExtensionMethodCall emc, ExtensionMethod em, Type t, string type
25+
) {
26+
em.getFile().getBaseName() = "extensions.cs" and
27+
emc.getTarget() = em and
28+
em.getDeclaringType() = t and
29+
em.getFullyQualifiedNameDebug() = type
30+
}
31+
32+
query predicate extensionOperatorCallArgument(
33+
ExtensionOperator op, ExtensionOperatorCall opc, Parameter p, int pos, Expr e
34+
) {
35+
opc.getTarget() = op and
36+
op.getFile().getBaseName() = "extensions.cs" and
37+
p = op.getParameter(pos) and
38+
e = opc.getArgument(pos)
39+
}
40+
41+
query predicate extensionOperatorCalls(
42+
ExtensionOperatorCall opc, ExtensionOperator op, Type t, string type
43+
) {
44+
op.getFile().getBaseName() = "extensions.cs" and
45+
opc.getTarget() = op and
46+
op.getDeclaringType() = t and
47+
op.getFullyQualifiedNameDebug() = type
48+
}
49+
50+
query predicate extensionProperty(ExtensionProperty p, Type t) {
51+
p.getFile().getBaseName() = "extensions.cs" and
52+
p.getDeclaringType() = t
53+
}
54+
55+
query predicate extensionPropertyCall(
56+
ExtensionPropertyCall pc, ExtensionProperty p, Type t, string type
57+
) {
58+
p.getFile().getBaseName() = "extensions.cs" and
59+
pc.getProperty() = p and
60+
p.getDeclaringType() = t and
61+
p.getFullyQualifiedNameDebug() = type
62+
}
63+
64+
query predicate extensionAccessorCall(
65+
ExtensionAccessorCall ac, ExtensionAccessor a, ExtensionProperty p, string type
66+
) {
67+
p.getFile().getBaseName() = "extensions.cs" and
68+
(a.(Getter).getDeclaration() = p or a.(Setter).getDeclaration() = p) and
69+
ac.getTarget() = a and
70+
a.getFullyQualifiedNameDebug() = type
71+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
semmle-extractor-options: /nostdlib /noconfig
2+
semmle-extractor-options: --load-sources-from-project:${testdir}/../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj

0 commit comments

Comments
 (0)