Skip to content

Commit ed8b9c2

Browse files
authored
Merge pull request #21866 from michaelnebel/csharp/refreturnindexerproperty
C#: Property- and Indexer calls for ref return properties and indexers.
2 parents 17fe3e4 + 6825ccc commit ed8b9c2

16 files changed

Lines changed: 211 additions & 6 deletions

File tree

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ public override void Populate(TextWriter trapFile)
6969
}
7070

7171
Overrides(trapFile);
72+
ExtractRefReturn(trapFile, Symbol, this);
7273

7374
if (Symbol.FromSource() && !HasBody)
7475
{
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* Improved call target resolution for ref-return properties and indexers.

csharp/ql/lib/semmle/code/csharp/exprs/Call.qll

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -766,7 +766,16 @@ class PropertyCall extends AccessorCall, PropertyAccessExpr {
766766
}
767767

768768
override Accessor getWriteTarget() {
769-
this instanceof AssignableWrite and result = this.getProperty().getSetter()
769+
this instanceof AssignableWrite and
770+
exists(Property p | p = this.getProperty() |
771+
result = p.getSetter()
772+
or
773+
result =
774+
any(Getter g |
775+
g = p.getGetter() and
776+
g.getAnnotatedReturnType().isRef()
777+
)
778+
)
770779
}
771780

772781
override Expr getArgument(int i) {
@@ -801,7 +810,16 @@ class IndexerCall extends AccessorCall, IndexerAccessExpr {
801810
}
802811

803812
override Accessor getWriteTarget() {
804-
this instanceof AssignableWrite and result = this.getIndexer().getSetter()
813+
this instanceof AssignableWrite and
814+
exists(Indexer i | i = this.getIndexer() |
815+
result = i.getSetter()
816+
or
817+
result =
818+
any(Getter g |
819+
g = i.getGetter() and
820+
g.getAnnotatedReturnType().isRef()
821+
)
822+
)
805823
}
806824

807825
override Expr getArgument(int i) {

csharp/ql/test/library-tests/csharp8/NullableRefTypes.expected

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ returnTypes
227227
| NullableRefTypes.cs:107:26:107:36 | ReturnsRef5 | readonly MyClass! |
228228
| NullableRefTypes.cs:108:26:108:36 | ReturnsRef6 | readonly MyClass! |
229229
| NullableRefTypes.cs:110:10:110:20 | Parameters1 | Void! |
230-
| NullableRefTypes.cs:113:32:113:44 | get_RefProperty | MyClass! |
230+
| NullableRefTypes.cs:113:32:113:44 | get_RefProperty | ref MyClass! |
231231
| NullableRefTypes.cs:116:7:116:23 | <object initializer> | Void |
232232
| NullableRefTypes.cs:116:7:116:23 | ToStringWithTypes | Void! |
233233
| NullableRefTypes.cs:136:7:136:24 | <object initializer> | Void |
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
| indexers.cs:24:21:24:24 | Item | indexers.cs:62:22:62:29 | access to indexer | indexers.cs:26:13:26:15 | get_Item |
2+
| indexers.cs:24:21:24:24 | Item | indexers.cs:65:25:65:32 | access to indexer | indexers.cs:34:13:34:15 | set_Item |
3+
| indexers.cs:143:24:143:27 | Item | indexers.cs:156:13:156:16 | access to indexer | indexers.cs:145:13:145:15 | get_Item |
4+
| indexers.cs:143:24:143:27 | Item | indexers.cs:157:21:157:24 | access to indexer | indexers.cs:145:13:145:15 | get_Item |
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import csharp
2+
3+
from IndexerCall ic, Indexer i, Accessor target
4+
where
5+
ic.getIndexer() = i and
6+
ic.getTarget() = target and
7+
i.fromSource()
8+
select i, ic, target

csharp/ql/test/library-tests/indexers/PrintAst.expected

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,3 +360,57 @@ indexers.cs:
360360
# 130| 4: [BlockStmt] {...}
361361
# 130| 0: [ReturnStmt] return ...;
362362
# 130| 0: [IntLiteral] 0
363+
# 134| 5: [RefStruct] S
364+
# 136| 6: [Field] x
365+
# 136| -1: [TypeMention] int
366+
# 138| 7: [InstanceConstructor] S
367+
#-----| 2: (Parameters)
368+
# 138| 0: [Parameter] v
369+
# 138| -1: [TypeMention] int
370+
# 139| 4: [BlockStmt] {...}
371+
# 140| 0: [ExprStmt] ...;
372+
# 140| 0: [AssignExpr] ... = ...
373+
# 140| 0: [FieldAccess] access to field x
374+
# 140| 1: [RefExpr] ref ...
375+
# 140| 0: [ParameterAccess] access to parameter v
376+
# 143| 8: [Indexer] Item
377+
# 143| -1: [TypeMention] int
378+
#-----| 1: (Parameters)
379+
# 143| 0: [Parameter] i
380+
# 143| -1: [TypeMention] int
381+
# 145| 3: [Getter] get_Item
382+
#-----| 2: (Parameters)
383+
# 143| 0: [Parameter] i
384+
# 145| 4: [BlockStmt] {...}
385+
# 145| 0: [ReturnStmt] return ...;
386+
# 145| 0: [RefExpr] ref ...
387+
# 145| 0: [FieldAccess] access to field x
388+
# 149| 6: [Class] TestRefReturns
389+
# 151| 6: [Method] M
390+
# 151| -1: [TypeMention] Void
391+
# 152| 4: [BlockStmt] {...}
392+
# 153| 0: [LocalVariableDeclStmt] ... ...;
393+
# 153| 0: [LocalVariableDeclAndInitExpr] Int32 a = ...
394+
# 153| -1: [TypeMention] int
395+
# 153| 0: [LocalVariableAccess] access to local variable a
396+
# 153| 1: [IntLiteral] 0
397+
# 155| 1: [LocalVariableDeclStmt] ... ...;
398+
# 155| 0: [LocalVariableDeclAndInitExpr] S s = ...
399+
# 155| -1: [TypeMention] S
400+
# 155| 0: [LocalVariableAccess] access to local variable s
401+
# 155| 1: [ObjectCreation] object creation of type S
402+
# 155| -1: [TypeMention] S
403+
# 155| 0: [LocalVariableAccess] access to local variable a
404+
# 156| 2: [ExprStmt] ...;
405+
# 156| 0: [AssignExpr] ... = ...
406+
# 156| 0: [IndexerCall] access to indexer
407+
# 156| -1: [LocalVariableAccess] access to local variable s
408+
# 156| 0: [IntLiteral] 0
409+
# 156| 1: [IntLiteral] 1
410+
# 157| 3: [LocalVariableDeclStmt] ... ...;
411+
# 157| 0: [LocalVariableDeclAndInitExpr] Int32 x = ...
412+
# 157| -1: [TypeMention] int
413+
# 157| 0: [LocalVariableAccess] access to local variable x
414+
# 157| 1: [IndexerCall] access to indexer
415+
# 157| -1: [LocalVariableAccess] access to local variable s
416+
# 157| 0: [IntLiteral] 0

csharp/ql/test/library-tests/indexers/indexers.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,4 +130,31 @@ public bool this[int index]
130130
get { return 0; }
131131
}
132132
}
133+
134+
public ref struct S
135+
{
136+
private ref int x;
137+
138+
public S(ref int v)
139+
{
140+
x = ref v;
141+
}
142+
143+
public ref int this[int i]
144+
{
145+
get { return ref x; }
146+
}
147+
}
148+
149+
public class TestRefReturns
150+
{
151+
public void M()
152+
{
153+
int a = 0;
154+
155+
S s = new S(ref a);
156+
s[0] = 1;
157+
var x = s[0];
158+
}
159+
}
133160
}

csharp/ql/test/library-tests/properties/PrintAst.expected

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,3 +246,50 @@ properties.cs:
246246
# 133| 0: [FieldAccess] access to field Prop.field
247247
# 133| 1: [ParameterAccess] access to parameter value
248248
# 130| 7: [Field] Prop.field
249+
# 137| 11: [RefStruct] S
250+
# 139| 6: [Field] x
251+
# 139| -1: [TypeMention] int
252+
# 141| 7: [InstanceConstructor] S
253+
#-----| 2: (Parameters)
254+
# 141| 0: [Parameter] v
255+
# 141| -1: [TypeMention] int
256+
# 142| 4: [BlockStmt] {...}
257+
# 143| 0: [ExprStmt] ...;
258+
# 143| 0: [AssignExpr] ... = ...
259+
# 143| 0: [FieldAccess] access to field x
260+
# 143| 1: [RefExpr] ref ...
261+
# 143| 0: [ParameterAccess] access to parameter v
262+
# 146| 8: [Property] Prop
263+
# 146| -1: [TypeMention] int
264+
# 148| 3: [Getter] get_Prop
265+
# 148| 4: [BlockStmt] {...}
266+
# 148| 0: [ReturnStmt] return ...;
267+
# 148| 0: [RefExpr] ref ...
268+
# 148| 0: [FieldAccess] access to field x
269+
# 152| 12: [Class] TestRefReturns
270+
# 154| 6: [Method] M
271+
# 154| -1: [TypeMention] Void
272+
# 155| 4: [BlockStmt] {...}
273+
# 156| 0: [LocalVariableDeclStmt] ... ...;
274+
# 156| 0: [LocalVariableDeclAndInitExpr] Int32 a = ...
275+
# 156| -1: [TypeMention] int
276+
# 156| 0: [LocalVariableAccess] access to local variable a
277+
# 156| 1: [IntLiteral] 0
278+
# 158| 1: [LocalVariableDeclStmt] ... ...;
279+
# 158| 0: [LocalVariableDeclAndInitExpr] S s = ...
280+
# 158| -1: [TypeMention] S
281+
# 158| 0: [LocalVariableAccess] access to local variable s
282+
# 158| 1: [ObjectCreation] object creation of type S
283+
# 158| -1: [TypeMention] S
284+
# 158| 0: [LocalVariableAccess] access to local variable a
285+
# 159| 2: [ExprStmt] ...;
286+
# 159| 0: [AssignExpr] ... = ...
287+
# 159| 0: [PropertyCall] access to property Prop
288+
# 159| -1: [LocalVariableAccess] access to local variable s
289+
# 159| 1: [IntLiteral] 1
290+
# 160| 3: [LocalVariableDeclStmt] ... ...;
291+
# 160| 0: [LocalVariableDeclAndInitExpr] Int32 x = ...
292+
# 160| -1: [TypeMention] int
293+
# 160| 0: [LocalVariableAccess] access to local variable x
294+
# 160| 1: [PropertyCall] access to property Prop
295+
# 160| -1: [LocalVariableAccess] access to local variable s
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
| Prop.field |
22
| caption |
33
| next |
4+
| x |
45
| y |
56
| z |

0 commit comments

Comments
 (0)