Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 5d8162c

Browse files
committed
C#: Improve AccessorCall::getArgument()
- Handle tuple assignments. - Handle compound `+=` assignments.
1 parent 7423916 commit 5d8162c

5 files changed

Lines changed: 146 additions & 123 deletions

File tree

csharp/ql/src/semmle/code/csharp/Assignable.qll

Lines changed: 138 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -183,62 +183,24 @@ class AssignableWrite extends AssignableAccess {
183183
}
184184
}
185185

186-
private cached module AssignableDefinitionImpl {
187-
cached newtype TAssignableDefinition =
188-
TAssignmentDefinition(Assignment a) {
189-
not a.getLValue() instanceof TupleExpr
190-
}
191-
or
192-
TTupleAssignmentDefinition(AssignExpr ae, Expr leaf) {
193-
exists(TupleExpr te |
194-
ae.getLValue() = te and
195-
te.getAnArgument+() = leaf and
196-
// `leaf` is either an assignable access or a local variable declaration
197-
not leaf instanceof TupleExpr
198-
)
199-
}
200-
or
201-
TOutRefDefinition(AssignableAccess aa) {
202-
aa.isOutArgument()
203-
or
204-
isRelevantRefCall(_, aa)
205-
}
206-
or
207-
TMutationDefinition(MutatorOperation mo)
208-
or
209-
TLocalVariableDefinition(LocalVariableDeclExpr lvde) {
210-
not lvde.hasInitializer() and
211-
not exists(getTupleSource(TTupleAssignmentDefinition(_, lvde))) and
212-
not lvde = any(IsPatternExpr ipe).getVariableDeclExpr() and
213-
not lvde = any(TypeCase tc).getVariableDeclExpr()
214-
}
215-
or
216-
TImplicitParameterDefinition(Parameter p) {
217-
exists(Callable c |
218-
p = c.getAParameter() |
219-
c.hasBody() or
220-
c.(Constructor).hasInitializer()
221-
)
222-
}
223-
or
224-
TAddressOfDefinition(AddressOfExpr aoe)
225-
or
226-
TIsPatternDefinition(IsPatternExpr ipe)
227-
or
228-
TTypeCasePatternDefinition(TypeCase tc)
229-
or
230-
TInitializer(Assignable a, Expr e) {
231-
e = a.(Field).getInitializer() or
232-
e = a.(Property).getInitializer()
233-
}
186+
/** INTERNAL: Do not use. */
187+
module AssignableInternal {
188+
private predicate tupleAssignmentDefinition(AssignExpr ae, Expr leaf) {
189+
exists(TupleExpr te |
190+
ae.getLValue() = te and
191+
te.getAnArgument+() = leaf and
192+
// `leaf` is either an assignable access or a local variable declaration
193+
not leaf instanceof TupleExpr
194+
)
195+
}
234196

235197
/**
236198
* Holds if `ae` is a tuple assignment, and `left` is a sub expression
237199
* on the left-hand side of the assignment, with corresponding
238200
* right-hand side `right`.
239201
*/
240202
private predicate tupleAssignmentPair(AssignExpr ae, Expr left, Expr right) {
241-
exists(TTupleAssignmentDefinition(ae, _)) and
203+
tupleAssignmentDefinition(ae, _) and
242204
left = ae.getLValue() and
243205
right = ae.getRValue()
244206
or
@@ -249,16 +211,6 @@ private cached module AssignableDefinitionImpl {
249211
)
250212
}
251213

252-
/**
253-
* Gets the source expression assigned in tuple definition `def`, if any.
254-
*/
255-
cached Expr getTupleSource(TTupleAssignmentDefinition def) {
256-
exists(AssignExpr ae, Expr leaf |
257-
def = TTupleAssignmentDefinition(ae, leaf) |
258-
tupleAssignmentPair(ae, leaf, result)
259-
)
260-
}
261-
262214
/**
263215
* Holds if the `ref` assignment to `aa` via call `c` is relevant.
264216
*/
@@ -341,19 +293,6 @@ private cached module AssignableDefinitionImpl {
341293
not result = TImplicitParameterDefinition(_)
342294
}
343295

344-
/**
345-
* Holds if the `ref` assignment to `aa` via call `c` is uncertain.
346-
*/
347-
cached predicate isUncertainRefCall(Call c, AssignableAccess aa) {
348-
isRelevantRefCall(c, aa)
349-
and
350-
exists(ControlFlow::BasicBlock bb, Parameter p |
351-
isAnalyzableRefCall(c, aa, p) |
352-
parameterReachesWithoutDef(p, bb) and
353-
bb.getLastNode() = p.getCallable().getExitPoint()
354-
)
355-
}
356-
357296
/**
358297
* Holds if `p` is an analyzable `ref` parameter and there is a path from the
359298
* entry point of `p`'s callable to basic block `bb` without passing through
@@ -378,51 +317,137 @@ private cached module AssignableDefinitionImpl {
378317
bb.getANode() = getAnAnalyzableRefDef(_, _, p).getAControlFlowNode()
379318
}
380319

381-
// Not defined by dispatch in order to avoid too conservative negative recursion error
382-
cached Assignable getTarget(AssignableDefinition def) {
383-
result = def.getTargetAccess().getTarget()
384-
or
385-
exists(Expr leaf |
386-
def = TTupleAssignmentDefinition(_, leaf) |
387-
result = leaf.(LocalVariableDeclExpr).getVariable()
388-
)
389-
or
390-
def = any(AssignableDefinitions::ImplicitParameterDefinition p |
391-
result = p.getParameter()
392-
)
393-
or
394-
def = any(AssignableDefinitions::LocalVariableDefinition decl |
395-
result = decl.getDeclaration().getVariable()
396-
)
397-
or
398-
def = any(AssignableDefinitions::IsPatternDefinition is |
399-
result = is.getDeclaration().getVariable()
400-
)
401-
or
402-
def = any(AssignableDefinitions::TypeCasePatternDefinition case |
403-
result = case.getDeclaration().getVariable()
404-
)
405-
or
406-
def = any(AssignableDefinitions::InitializerDefinition init |
407-
result = init.getAssignable()
408-
)
409-
}
320+
private cached module Cached {
321+
cached newtype TAssignableDefinition =
322+
TAssignmentDefinition(Assignment a) {
323+
not a.getLValue() instanceof TupleExpr
324+
}
325+
or
326+
TTupleAssignmentDefinition(AssignExpr ae, Expr leaf) {
327+
tupleAssignmentDefinition(ae, leaf)
328+
}
329+
or
330+
TOutRefDefinition(AssignableAccess aa) {
331+
aa.isOutArgument()
332+
or
333+
isRelevantRefCall(_, aa)
334+
}
335+
or
336+
TMutationDefinition(MutatorOperation mo)
337+
or
338+
TLocalVariableDefinition(LocalVariableDeclExpr lvde) {
339+
not lvde.hasInitializer() and
340+
not exists(getTupleSource(TTupleAssignmentDefinition(_, lvde))) and
341+
not lvde = any(IsPatternExpr ipe).getVariableDeclExpr() and
342+
not lvde = any(TypeCase tc).getVariableDeclExpr()
343+
}
344+
or
345+
TImplicitParameterDefinition(Parameter p) {
346+
exists(Callable c |
347+
p = c.getAParameter() |
348+
c.hasBody() or
349+
c.(Constructor).hasInitializer()
350+
)
351+
}
352+
or
353+
TAddressOfDefinition(AddressOfExpr aoe)
354+
or
355+
TIsPatternDefinition(IsPatternExpr ipe)
356+
or
357+
TTypeCasePatternDefinition(TypeCase tc)
358+
or
359+
TInitializer(Assignable a, Expr e) {
360+
e = a.(Field).getInitializer() or
361+
e = a.(Property).getInitializer()
362+
}
410363

411-
// Not defined by dispatch in order to avoid too conservative negative recursion error
412-
cached AssignableAccess getTargetAccess(AssignableDefinition def) {
413-
def = TAssignmentDefinition(any(Assignment a | a.getLValue() = result))
414-
or
415-
def = TTupleAssignmentDefinition(_, result)
416-
or
417-
def = TOutRefDefinition(result)
418-
or
419-
def = TMutationDefinition(any(MutatorOperation mo | mo.getOperand() = result))
420-
or
421-
def = TAddressOfDefinition(any(AddressOfExpr aoe | aoe.getOperand() = result))
364+
/**
365+
* Gets the source expression assigned in tuple definition `def`, if any.
366+
*/
367+
cached Expr getTupleSource(TTupleAssignmentDefinition def) {
368+
exists(AssignExpr ae, Expr leaf |
369+
def = TTupleAssignmentDefinition(ae, leaf) |
370+
tupleAssignmentPair(ae, leaf, result)
371+
)
372+
}
373+
374+
/**
375+
* Holds if the `ref` assignment to `aa` via call `c` is uncertain.
376+
*/
377+
cached predicate isUncertainRefCall(Call c, AssignableAccess aa) {
378+
isRelevantRefCall(c, aa)
379+
and
380+
exists(ControlFlow::BasicBlock bb, Parameter p |
381+
isAnalyzableRefCall(c, aa, p) |
382+
parameterReachesWithoutDef(p, bb) and
383+
bb.getLastNode() = p.getCallable().getExitPoint()
384+
)
385+
}
386+
387+
// Not defined by dispatch in order to avoid too conservative negative recursion error
388+
cached Assignable getTarget(AssignableDefinition def) {
389+
result = def.getTargetAccess().getTarget()
390+
or
391+
exists(Expr leaf |
392+
def = TTupleAssignmentDefinition(_, leaf) |
393+
result = leaf.(LocalVariableDeclExpr).getVariable()
394+
)
395+
or
396+
def = any(AssignableDefinitions::ImplicitParameterDefinition p |
397+
result = p.getParameter()
398+
)
399+
or
400+
def = any(AssignableDefinitions::LocalVariableDefinition decl |
401+
result = decl.getDeclaration().getVariable()
402+
)
403+
or
404+
def = any(AssignableDefinitions::IsPatternDefinition is |
405+
result = is.getDeclaration().getVariable()
406+
)
407+
or
408+
def = any(AssignableDefinitions::TypeCasePatternDefinition case |
409+
result = case.getDeclaration().getVariable()
410+
)
411+
or
412+
def = any(AssignableDefinitions::InitializerDefinition init |
413+
result = init.getAssignable()
414+
)
415+
}
416+
417+
// Not defined by dispatch in order to avoid too conservative negative recursion error
418+
cached AssignableAccess getTargetAccess(AssignableDefinition def) {
419+
def = TAssignmentDefinition(any(Assignment a | a.getLValue() = result))
420+
or
421+
def = TTupleAssignmentDefinition(_, result)
422+
or
423+
def = TOutRefDefinition(result)
424+
or
425+
def = TMutationDefinition(any(MutatorOperation mo | mo.getOperand() = result))
426+
or
427+
def = TAddressOfDefinition(any(AddressOfExpr aoe | aoe.getOperand() = result))
428+
}
429+
430+
/**
431+
* Gets the argument for the implicit `value` parameter in the accessor call
432+
* `ac`, if any.
433+
*/
434+
cached Expr getAccessorCallValueArgument(AccessorCall ac) {
435+
exists(AssignExpr ae |
436+
tupleAssignmentDefinition(ae, ac) |
437+
tupleAssignmentPair(ae, ac, result)
438+
)
439+
or
440+
exists(Assignment a |
441+
ac = a.getLValue() |
442+
result = a.getRValue() and
443+
not a.(AssignOperation).hasExpandedAssignment()
444+
)
445+
}
422446
}
447+
import Cached
423448
}
424449

425-
private import AssignableDefinitionImpl
450+
private import AssignableInternal
426451

427452
/**
428453
* An assignable definition.

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -643,8 +643,7 @@ class PropertyCall extends AccessorCall, PropertyAccessExpr {
643643

644644
override Expr getArgument(int i) {
645645
i = 0 and
646-
this instanceof AssignableWrite and
647-
exists(Assignment a | a.getLValue() = this and result = a.getRValue())
646+
result = AssignableInternal::getAccessorCallValueArgument(this)
648647
}
649648

650649
override string toString() {
@@ -681,9 +680,8 @@ class IndexerCall extends AccessorCall, IndexerAccessExpr {
681680
override Expr getArgument(int i) {
682681
result = this.(ElementAccess).getIndex(i)
683682
or
684-
this instanceof AssignableWrite and
685683
i = count(this.(ElementAccess).getAnIndex()) and
686-
exists(Assignment a | a.getLValue() = this and result = a.getRValue())
684+
result = AssignableInternal::getAccessorCallValueArgument(this)
687685
}
688686

689687
override string toString() { result = IndexerAccessExpr.super.toString() }

csharp/ql/test/library-tests/arguments/argumentByName.expected

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,17 @@
2121
| arguments.cs:55:9:55:12 | access to property Prop | arguments.cs:55:16:55:25 | access to indexer | value |
2222
| arguments.cs:55:16:55:25 | access to indexer | arguments.cs:55:21:55:21 | 1 | a |
2323
| arguments.cs:55:16:55:25 | access to indexer | arguments.cs:55:24:55:24 | 2 | b |
24+
| arguments.cs:56:10:56:13 | access to property Prop | arguments.cs:56:31:56:31 | 5 | value |
2425
| arguments.cs:56:16:56:25 | access to indexer | arguments.cs:56:21:56:21 | 3 | a |
2526
| arguments.cs:56:16:56:25 | access to indexer | arguments.cs:56:24:56:24 | 4 | b |
27+
| arguments.cs:56:16:56:25 | access to indexer | arguments.cs:56:34:56:34 | 6 | value |
2628
| arguments.cs:58:9:58:12 | access to property Prop | arguments.cs:58:9:58:17 | ... + ... | value |
27-
| arguments.cs:58:9:58:12 | access to property Prop | arguments.cs:58:17:58:17 | 7 | value |
2829
| arguments.cs:59:9:59:18 | access to indexer | arguments.cs:59:14:59:14 | 8 | a |
2930
| arguments.cs:59:9:59:18 | access to indexer | arguments.cs:59:17:59:17 | 9 | b |
3031
| arguments.cs:60:9:60:20 | access to indexer | arguments.cs:60:9:60:26 | ... + ... | value |
3132
| arguments.cs:60:9:60:20 | access to indexer | arguments.cs:60:14:60:15 | 10 | a |
3233
| arguments.cs:60:9:60:20 | access to indexer | arguments.cs:60:14:60:15 | 10 | a |
3334
| arguments.cs:60:9:60:20 | access to indexer | arguments.cs:60:18:60:19 | 11 | b |
3435
| arguments.cs:60:9:60:20 | access to indexer | arguments.cs:60:18:60:19 | 11 | b |
35-
| arguments.cs:60:9:60:20 | access to indexer | arguments.cs:60:25:60:26 | 12 | value |
3636
| arguments.cs:62:16:62:27 | access to indexer | arguments.cs:62:21:62:22 | 15 | a |
3737
| arguments.cs:62:16:62:27 | access to indexer | arguments.cs:62:25:62:26 | 16 | b |

csharp/ql/test/library-tests/arguments/argumentByParameter.expected

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,11 @@
2121
| arguments.cs:55:9:55:12 | access to property Prop | arguments.cs:55:16:55:25 | access to indexer | arguments.cs:48:21:48:23 | value |
2222
| arguments.cs:55:16:55:25 | access to indexer | arguments.cs:55:21:55:21 | 1 | arguments.cs:50:18:50:18 | a |
2323
| arguments.cs:55:16:55:25 | access to indexer | arguments.cs:55:24:55:24 | 2 | arguments.cs:50:25:50:25 | b |
24+
| arguments.cs:56:10:56:13 | access to property Prop | arguments.cs:56:31:56:31 | 5 | arguments.cs:48:21:48:23 | value |
2425
| arguments.cs:56:16:56:25 | access to indexer | arguments.cs:56:21:56:21 | 3 | arguments.cs:50:18:50:18 | a |
2526
| arguments.cs:56:16:56:25 | access to indexer | arguments.cs:56:24:56:24 | 4 | arguments.cs:50:25:50:25 | b |
27+
| arguments.cs:56:16:56:25 | access to indexer | arguments.cs:56:34:56:34 | 6 | arguments.cs:50:44:50:46 | value |
2628
| arguments.cs:58:9:58:12 | access to property Prop | arguments.cs:58:9:58:17 | ... + ... | arguments.cs:48:21:48:23 | value |
27-
| arguments.cs:58:9:58:12 | access to property Prop | arguments.cs:58:17:58:17 | 7 | arguments.cs:48:21:48:23 | value |
2829
| arguments.cs:59:9:59:18 | access to indexer | arguments.cs:59:14:59:14 | 8 | arguments.cs:50:18:50:18 | a |
2930
| arguments.cs:59:9:59:18 | access to indexer | arguments.cs:59:14:59:14 | 8 | arguments.cs:50:18:50:18 | a |
3031
| arguments.cs:59:9:59:18 | access to indexer | arguments.cs:59:17:59:17 | 9 | arguments.cs:50:25:50:25 | b |
@@ -34,6 +35,5 @@
3435
| arguments.cs:60:9:60:20 | access to indexer | arguments.cs:60:14:60:15 | 10 | arguments.cs:50:18:50:18 | a |
3536
| arguments.cs:60:9:60:20 | access to indexer | arguments.cs:60:18:60:19 | 11 | arguments.cs:50:25:50:25 | b |
3637
| arguments.cs:60:9:60:20 | access to indexer | arguments.cs:60:18:60:19 | 11 | arguments.cs:50:25:50:25 | b |
37-
| arguments.cs:60:9:60:20 | access to indexer | arguments.cs:60:25:60:26 | 12 | arguments.cs:50:44:50:46 | value |
3838
| arguments.cs:62:16:62:27 | access to indexer | arguments.cs:62:21:62:22 | 15 | arguments.cs:50:18:50:18 | a |
3939
| arguments.cs:62:16:62:27 | access to indexer | arguments.cs:62:25:62:26 | 16 | arguments.cs:50:25:50:25 | b |

csharp/ql/test/library-tests/arguments/parameterGetArguments.expected

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@
1919
| arguments.cs:33:33:33:36 | args | arguments.cs:40:18:40:35 | array creation of type Int32[] |
2020
| arguments.cs:48:21:48:23 | value | arguments.cs:54:16:54:16 | 0 |
2121
| arguments.cs:48:21:48:23 | value | arguments.cs:55:16:55:25 | access to indexer |
22+
| arguments.cs:48:21:48:23 | value | arguments.cs:56:31:56:31 | 5 |
2223
| arguments.cs:48:21:48:23 | value | arguments.cs:58:9:58:17 | ... + ... |
23-
| arguments.cs:48:21:48:23 | value | arguments.cs:58:17:58:17 | 7 |
2424
| arguments.cs:50:18:50:18 | a | arguments.cs:55:21:55:21 | 1 |
2525
| arguments.cs:50:18:50:18 | a | arguments.cs:56:21:56:21 | 3 |
2626
| arguments.cs:50:18:50:18 | a | arguments.cs:59:14:59:14 | 8 |
@@ -35,5 +35,5 @@
3535
| arguments.cs:50:25:50:25 | b | arguments.cs:60:18:60:19 | 11 |
3636
| arguments.cs:50:25:50:25 | b | arguments.cs:60:18:60:19 | 11 |
3737
| arguments.cs:50:25:50:25 | b | arguments.cs:62:25:62:26 | 16 |
38+
| arguments.cs:50:44:50:46 | value | arguments.cs:56:34:56:34 | 6 |
3839
| arguments.cs:50:44:50:46 | value | arguments.cs:60:9:60:26 | ... + ... |
39-
| arguments.cs:50:44:50:46 | value | arguments.cs:60:25:60:26 | 12 |

0 commit comments

Comments
 (0)