Skip to content

Commit 7e18b3e

Browse files
authored
Merge pull request github#18533 from michaelnebel/csharp/partialmembers
C# 13: Partial properties and indexers.
2 parents a3de138 + 501f985 commit 7e18b3e

25 files changed

+456
-43
lines changed

csharp/extractor/Semmle.Extraction.CSharp/Entities/Accessor.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ protected Accessor(Context cx, IMethodSymbol init, IPropertySymbol property)
3030
return props.SingleOrDefault();
3131
}
3232

33+
public override bool NeedsPopulation =>
34+
base.NeedsPopulation &&
35+
!Symbol.IsPartialDefinition; // Accessors always have an implementing declaration as well.
36+
3337
public override void Populate(TextWriter trapFile)
3438
{
3539
PopulateMethod(trapFile);

csharp/extractor/Semmle.Extraction.CSharp/Entities/Indexer.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,16 @@ public override void Populate(TextWriter trapFile)
2222
foreach (var l in Locations)
2323
trapFile.indexer_location(this, l);
2424

25-
var getter = Symbol.GetMethod;
26-
var setter = Symbol.SetMethod;
25+
var getter = BodyDeclaringSymbol.GetMethod;
26+
var setter = BodyDeclaringSymbol.SetMethod;
2727

2828
if (getter is null && setter is null)
2929
Context.ModelError(Symbol, "No indexer accessor defined");
3030

31-
if (!(getter is null))
31+
if (getter is not null)
3232
Method.Create(Context, getter);
3333

34-
if (!(setter is null))
34+
if (setter is not null)
3535
Method.Create(Context, setter);
3636

3737
for (var i = 0; i < Symbol.Parameters.Length; ++i)

csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ protected Property(Context cx, IPropertySymbol init)
2121

2222
private Type Type => type.Value;
2323

24+
protected override IPropertySymbol BodyDeclaringSymbol => Symbol.PartialImplementationPart ?? Symbol;
25+
26+
public override Microsoft.CodeAnalysis.Location? ReportingLocation => BodyDeclaringSymbol.Locations.BestOrDefault();
27+
2428
public override void WriteId(EscapingTextWriter trapFile)
2529
{
2630
trapFile.WriteSubId(Type);
@@ -43,13 +47,13 @@ public override void Populate(TextWriter trapFile)
4347
var type = Type;
4448
trapFile.properties(this, Symbol.GetName(), ContainingType!, type.TypeRef, Create(Context, Symbol.OriginalDefinition));
4549

46-
var getter = Symbol.GetMethod;
47-
var setter = Symbol.SetMethod;
50+
var getter = BodyDeclaringSymbol.GetMethod;
51+
var setter = BodyDeclaringSymbol.SetMethod;
4852

49-
if (!(getter is null))
53+
if (getter is not null)
5054
Method.Create(Context, getter);
5155

52-
if (!(setter is null))
56+
if (setter is not null)
5357
Method.Create(Context, setter);
5458

5559
var declSyntaxReferences = IsSourceDeclaration ?
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* C# 13: Added support for partial properties and indexers.

csharp/ql/test/library-tests/dataflow/fields/D.cs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,41 @@ public static void Sink(object o) { }
5151

5252
static T Source<T>(object source) => throw null;
5353
}
54+
55+
public partial class DPartial
56+
{
57+
private object _backingField;
58+
public partial object PartialProp1
59+
{
60+
get { return _backingField; }
61+
set { _backingField = value; }
62+
}
63+
64+
public partial object PartialProp2
65+
{
66+
get { return null; }
67+
set { }
68+
}
69+
}
70+
71+
public partial class DPartial
72+
{
73+
public partial object PartialProp1 { get; set; }
74+
public partial object PartialProp2 { get; set; }
75+
76+
public void M()
77+
{
78+
var o = Source<object>(1);
79+
80+
var d = new DPartial();
81+
d.PartialProp1 = o;
82+
d.PartialProp2 = o;
83+
84+
Sink(d.PartialProp1); // $ hasValueFlow=1
85+
Sink(d.PartialProp2); // no flow
86+
}
87+
88+
public static void Sink(object o) { }
89+
90+
static T Source<T>(object source) => throw null;
91+
}

csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,30 @@ edges
502502
| D.cs:47:14:47:14 | access to local variable d : D [field trivialPropField] : Object | D.cs:14:9:14:11 | this : D [field trivialPropField] : Object | provenance | |
503503
| D.cs:47:14:47:14 | access to local variable d : D [field trivialPropField] : Object | D.cs:47:14:47:26 | access to property ComplexProp | provenance | |
504504
| D.cs:47:14:47:14 | access to local variable d : D [field trivialPropField] : Object | D.cs:47:14:47:26 | access to property ComplexProp | provenance | |
505+
| D.cs:60:9:60:11 | this : DPartial [field _backingField] : Object | D.cs:60:22:60:34 | this access : DPartial [field _backingField] : Object | provenance | |
506+
| D.cs:60:9:60:11 | this : DPartial [field _backingField] : Object | D.cs:60:22:60:34 | this access : DPartial [field _backingField] : Object | provenance | |
507+
| D.cs:60:22:60:34 | this access : DPartial [field _backingField] : Object | D.cs:60:22:60:34 | access to field _backingField : Object | provenance | |
508+
| D.cs:60:22:60:34 | this access : DPartial [field _backingField] : Object | D.cs:60:22:60:34 | access to field _backingField : Object | provenance | |
509+
| D.cs:61:9:61:11 | value : Object | D.cs:61:31:61:35 | access to parameter value : Object | provenance | |
510+
| D.cs:61:9:61:11 | value : Object | D.cs:61:31:61:35 | access to parameter value : Object | provenance | |
511+
| D.cs:61:15:61:27 | [post] this access : DPartial [field _backingField] : Object | D.cs:61:9:61:11 | this [Return] : DPartial [field _backingField] : Object | provenance | |
512+
| D.cs:61:15:61:27 | [post] this access : DPartial [field _backingField] : Object | D.cs:61:9:61:11 | this [Return] : DPartial [field _backingField] : Object | provenance | |
513+
| D.cs:61:31:61:35 | access to parameter value : Object | D.cs:61:15:61:27 | [post] this access : DPartial [field _backingField] : Object | provenance | |
514+
| D.cs:61:31:61:35 | access to parameter value : Object | D.cs:61:15:61:27 | [post] this access : DPartial [field _backingField] : Object | provenance | |
515+
| D.cs:78:13:78:13 | access to local variable o : Object | D.cs:81:26:81:26 | access to local variable o : Object | provenance | |
516+
| D.cs:78:13:78:13 | access to local variable o : Object | D.cs:81:26:81:26 | access to local variable o : Object | provenance | |
517+
| D.cs:78:17:78:33 | call to method Source<Object> : Object | D.cs:78:13:78:13 | access to local variable o : Object | provenance | |
518+
| D.cs:78:17:78:33 | call to method Source<Object> : Object | D.cs:78:13:78:13 | access to local variable o : Object | provenance | |
519+
| D.cs:81:9:81:9 | [post] access to local variable d : DPartial [field _backingField] : Object | D.cs:84:14:84:14 | access to local variable d : DPartial [field _backingField] : Object | provenance | |
520+
| D.cs:81:9:81:9 | [post] access to local variable d : DPartial [field _backingField] : Object | D.cs:84:14:84:14 | access to local variable d : DPartial [field _backingField] : Object | provenance | |
521+
| D.cs:81:26:81:26 | access to local variable o : Object | D.cs:61:9:61:11 | value : Object | provenance | |
522+
| D.cs:81:26:81:26 | access to local variable o : Object | D.cs:61:9:61:11 | value : Object | provenance | |
523+
| D.cs:81:26:81:26 | access to local variable o : Object | D.cs:81:9:81:9 | [post] access to local variable d : DPartial [field _backingField] : Object | provenance | |
524+
| D.cs:81:26:81:26 | access to local variable o : Object | D.cs:81:9:81:9 | [post] access to local variable d : DPartial [field _backingField] : Object | provenance | |
525+
| D.cs:84:14:84:14 | access to local variable d : DPartial [field _backingField] : Object | D.cs:60:9:60:11 | this : DPartial [field _backingField] : Object | provenance | |
526+
| D.cs:84:14:84:14 | access to local variable d : DPartial [field _backingField] : Object | D.cs:60:9:60:11 | this : DPartial [field _backingField] : Object | provenance | |
527+
| D.cs:84:14:84:14 | access to local variable d : DPartial [field _backingField] : Object | D.cs:84:14:84:27 | access to property PartialProp1 | provenance | |
528+
| D.cs:84:14:84:14 | access to local variable d : DPartial [field _backingField] : Object | D.cs:84:14:84:27 | access to property PartialProp1 | provenance | |
505529
| E.cs:8:29:8:29 | o : Object | E.cs:11:21:11:21 | access to parameter o : Object | provenance | |
506530
| E.cs:8:29:8:29 | o : Object | E.cs:11:21:11:21 | access to parameter o : Object | provenance | |
507531
| E.cs:11:9:11:11 | [post] access to local variable ret : S [field Field] : Object | E.cs:12:16:12:18 | access to local variable ret : S [field Field] : Object | provenance | |
@@ -1745,6 +1769,32 @@ nodes
17451769
| D.cs:47:14:47:14 | access to local variable d : D [field trivialPropField] : Object | semmle.label | access to local variable d : D [field trivialPropField] : Object |
17461770
| D.cs:47:14:47:26 | access to property ComplexProp | semmle.label | access to property ComplexProp |
17471771
| D.cs:47:14:47:26 | access to property ComplexProp | semmle.label | access to property ComplexProp |
1772+
| D.cs:60:9:60:11 | this : DPartial [field _backingField] : Object | semmle.label | this : DPartial [field _backingField] : Object |
1773+
| D.cs:60:9:60:11 | this : DPartial [field _backingField] : Object | semmle.label | this : DPartial [field _backingField] : Object |
1774+
| D.cs:60:22:60:34 | access to field _backingField : Object | semmle.label | access to field _backingField : Object |
1775+
| D.cs:60:22:60:34 | access to field _backingField : Object | semmle.label | access to field _backingField : Object |
1776+
| D.cs:60:22:60:34 | this access : DPartial [field _backingField] : Object | semmle.label | this access : DPartial [field _backingField] : Object |
1777+
| D.cs:60:22:60:34 | this access : DPartial [field _backingField] : Object | semmle.label | this access : DPartial [field _backingField] : Object |
1778+
| D.cs:61:9:61:11 | this [Return] : DPartial [field _backingField] : Object | semmle.label | this [Return] : DPartial [field _backingField] : Object |
1779+
| D.cs:61:9:61:11 | this [Return] : DPartial [field _backingField] : Object | semmle.label | this [Return] : DPartial [field _backingField] : Object |
1780+
| D.cs:61:9:61:11 | value : Object | semmle.label | value : Object |
1781+
| D.cs:61:9:61:11 | value : Object | semmle.label | value : Object |
1782+
| D.cs:61:15:61:27 | [post] this access : DPartial [field _backingField] : Object | semmle.label | [post] this access : DPartial [field _backingField] : Object |
1783+
| D.cs:61:15:61:27 | [post] this access : DPartial [field _backingField] : Object | semmle.label | [post] this access : DPartial [field _backingField] : Object |
1784+
| D.cs:61:31:61:35 | access to parameter value : Object | semmle.label | access to parameter value : Object |
1785+
| D.cs:61:31:61:35 | access to parameter value : Object | semmle.label | access to parameter value : Object |
1786+
| D.cs:78:13:78:13 | access to local variable o : Object | semmle.label | access to local variable o : Object |
1787+
| D.cs:78:13:78:13 | access to local variable o : Object | semmle.label | access to local variable o : Object |
1788+
| D.cs:78:17:78:33 | call to method Source<Object> : Object | semmle.label | call to method Source<Object> : Object |
1789+
| D.cs:78:17:78:33 | call to method Source<Object> : Object | semmle.label | call to method Source<Object> : Object |
1790+
| D.cs:81:9:81:9 | [post] access to local variable d : DPartial [field _backingField] : Object | semmle.label | [post] access to local variable d : DPartial [field _backingField] : Object |
1791+
| D.cs:81:9:81:9 | [post] access to local variable d : DPartial [field _backingField] : Object | semmle.label | [post] access to local variable d : DPartial [field _backingField] : Object |
1792+
| D.cs:81:26:81:26 | access to local variable o : Object | semmle.label | access to local variable o : Object |
1793+
| D.cs:81:26:81:26 | access to local variable o : Object | semmle.label | access to local variable o : Object |
1794+
| D.cs:84:14:84:14 | access to local variable d : DPartial [field _backingField] : Object | semmle.label | access to local variable d : DPartial [field _backingField] : Object |
1795+
| D.cs:84:14:84:14 | access to local variable d : DPartial [field _backingField] : Object | semmle.label | access to local variable d : DPartial [field _backingField] : Object |
1796+
| D.cs:84:14:84:27 | access to property PartialProp1 | semmle.label | access to property PartialProp1 |
1797+
| D.cs:84:14:84:27 | access to property PartialProp1 | semmle.label | access to property PartialProp1 |
17481798
| E.cs:8:29:8:29 | o : Object | semmle.label | o : Object |
17491799
| E.cs:8:29:8:29 | o : Object | semmle.label | o : Object |
17501800
| E.cs:11:9:11:11 | [post] access to local variable ret : S [field Field] : Object | semmle.label | [post] access to local variable ret : S [field Field] : Object |
@@ -2582,6 +2632,10 @@ subpaths
25822632
| D.cs:45:14:45:14 | access to local variable d : D [field trivialPropField] : Object | D.cs:8:9:8:11 | this : D [field trivialPropField] : Object | D.cs:8:22:8:42 | access to field trivialPropField : Object | D.cs:45:14:45:26 | access to property TrivialProp |
25832633
| D.cs:47:14:47:14 | access to local variable d : D [field trivialPropField] : Object | D.cs:14:9:14:11 | this : D [field trivialPropField] : Object | D.cs:14:22:14:42 | access to field trivialPropField : Object | D.cs:47:14:47:26 | access to property ComplexProp |
25842634
| D.cs:47:14:47:14 | access to local variable d : D [field trivialPropField] : Object | D.cs:14:9:14:11 | this : D [field trivialPropField] : Object | D.cs:14:22:14:42 | access to field trivialPropField : Object | D.cs:47:14:47:26 | access to property ComplexProp |
2635+
| D.cs:81:26:81:26 | access to local variable o : Object | D.cs:61:9:61:11 | value : Object | D.cs:61:9:61:11 | this [Return] : DPartial [field _backingField] : Object | D.cs:81:9:81:9 | [post] access to local variable d : DPartial [field _backingField] : Object |
2636+
| D.cs:81:26:81:26 | access to local variable o : Object | D.cs:61:9:61:11 | value : Object | D.cs:61:9:61:11 | this [Return] : DPartial [field _backingField] : Object | D.cs:81:9:81:9 | [post] access to local variable d : DPartial [field _backingField] : Object |
2637+
| D.cs:84:14:84:14 | access to local variable d : DPartial [field _backingField] : Object | D.cs:60:9:60:11 | this : DPartial [field _backingField] : Object | D.cs:60:22:60:34 | access to field _backingField : Object | D.cs:84:14:84:27 | access to property PartialProp1 |
2638+
| D.cs:84:14:84:14 | access to local variable d : DPartial [field _backingField] : Object | D.cs:60:9:60:11 | this : DPartial [field _backingField] : Object | D.cs:60:22:60:34 | access to field _backingField : Object | D.cs:84:14:84:27 | access to property PartialProp1 |
25852639
| E.cs:23:25:23:25 | access to local variable o : Object | E.cs:8:29:8:29 | o : Object | E.cs:12:16:12:18 | access to local variable ret : S [field Field] : Object | E.cs:23:17:23:26 | call to method CreateS : S [field Field] : Object |
25862640
| E.cs:23:25:23:25 | access to local variable o : Object | E.cs:8:29:8:29 | o : Object | E.cs:12:16:12:18 | access to local variable ret : S [field Field] : Object | E.cs:23:17:23:26 | call to method CreateS : S [field Field] : Object |
25872641
| E.cs:55:29:55:33 | access to local variable taint : Object | E.cs:43:46:43:46 | o : Object | E.cs:43:36:43:36 | s [Return] : RefS [field RefField] : Object | E.cs:55:23:55:26 | [post] access to local variable refs : RefS [field RefField] : Object |
@@ -2690,6 +2744,8 @@ testFailures
26902744
| D.cs:46:14:46:31 | access to field trivialPropField | D.cs:43:32:43:48 | call to method Source<Object> : Object | D.cs:46:14:46:31 | access to field trivialPropField | $@ | D.cs:43:32:43:48 | call to method Source<Object> : Object | call to method Source<Object> : Object |
26912745
| D.cs:47:14:47:26 | access to property ComplexProp | D.cs:43:32:43:48 | call to method Source<Object> : Object | D.cs:47:14:47:26 | access to property ComplexProp | $@ | D.cs:43:32:43:48 | call to method Source<Object> : Object | call to method Source<Object> : Object |
26922746
| D.cs:47:14:47:26 | access to property ComplexProp | D.cs:43:32:43:48 | call to method Source<Object> : Object | D.cs:47:14:47:26 | access to property ComplexProp | $@ | D.cs:43:32:43:48 | call to method Source<Object> : Object | call to method Source<Object> : Object |
2747+
| D.cs:84:14:84:27 | access to property PartialProp1 | D.cs:78:17:78:33 | call to method Source<Object> : Object | D.cs:84:14:84:27 | access to property PartialProp1 | $@ | D.cs:78:17:78:33 | call to method Source<Object> : Object | call to method Source<Object> : Object |
2748+
| D.cs:84:14:84:27 | access to property PartialProp1 | D.cs:78:17:78:33 | call to method Source<Object> : Object | D.cs:84:14:84:27 | access to property PartialProp1 | $@ | D.cs:78:17:78:33 | call to method Source<Object> : Object | call to method Source<Object> : Object |
26932749
| E.cs:24:14:24:20 | access to field Field | E.cs:22:17:22:33 | call to method Source<Object> : Object | E.cs:24:14:24:20 | access to field Field | $@ | E.cs:22:17:22:33 | call to method Source<Object> : Object | call to method Source<Object> : Object |
26942750
| E.cs:24:14:24:20 | access to field Field | E.cs:22:17:22:33 | call to method Source<Object> : Object | E.cs:24:14:24:20 | access to field Field | $@ | E.cs:22:17:22:33 | call to method Source<Object> : Object | call to method Source<Object> : Object |
26952751
| E.cs:57:14:57:26 | access to field RefField | E.cs:54:21:54:37 | call to method Source<Object> : Object | E.cs:57:14:57:26 | access to field RefField | $@ | E.cs:54:21:54:37 | call to method Source<Object> : Object | call to method Source<Object> : Object |

0 commit comments

Comments
 (0)