@@ -171,7 +171,7 @@ public abstract TValue HandleMethodCall(
171
171
172
172
public override TValue VisitLocalReference ( ILocalReferenceOperation operation , LocalDataFlowState < TValue , TContext , TValueLattice , TContextLattice > state )
173
173
{
174
- return GetLocal ( operation , state ) ;
174
+ return GetLocal ( operation . Local , state ) ;
175
175
}
176
176
177
177
private TValue ProcessBinderCall ( IOperation operation , string methodName , LocalDataFlowState < TValue , TContext , TValueLattice , TContextLattice > state )
@@ -199,21 +199,19 @@ public override TValue VisitDynamicMemberReference(IDynamicMemberReferenceOperat
199
199
public override TValue VisitDynamicIndexerAccess ( IDynamicIndexerAccessOperation operation , LocalDataFlowState < TValue , TContext , TValueLattice , TContextLattice > state )
200
200
=> ProcessBinderCall ( operation , operation . GetValueUsageInfo ( OwningSymbol ) . HasFlag ( ValueUsageInfo . Write ) ? "SetIndex" : "GetIndex" , state ) ;
201
201
202
- private bool IsReferenceToCapturedVariable ( ILocalReferenceOperation localReference )
202
+ private bool IsCapturedVariable ( ILocalSymbol local )
203
203
{
204
- var local = localReference . Local ;
205
-
206
204
if ( local . IsConst )
207
205
return false ;
208
206
Debug . Assert ( local . ContainingSymbol is IMethodSymbol or IFieldSymbol , // backing field for property initializers
209
- $ "{ local . ContainingSymbol . GetType ( ) } : { localReference . Syntax . GetLocation ( ) . GetLineSpan ( ) } ") ;
207
+ $ "{ local . ContainingSymbol . GetType ( ) } : { local . Locations [ 0 ] . GetLineSpan ( ) } ") ;
210
208
return ! ReferenceEquals ( local . ContainingSymbol , OwningSymbol ) ;
211
209
}
212
210
213
- private TValue GetLocal ( ILocalReferenceOperation operation , LocalDataFlowState < TValue , TContext , TValueLattice , TContextLattice > state )
211
+ private TValue GetLocal ( ILocalSymbol symbol , LocalDataFlowState < TValue , TContext , TValueLattice , TContextLattice > state )
214
212
{
215
- var local = new LocalKey ( operation . Local ) ;
216
- if ( IsReferenceToCapturedVariable ( operation ) )
213
+ var local = new LocalKey ( symbol ) ;
214
+ if ( IsCapturedVariable ( symbol ) )
217
215
InterproceduralState . TrackHoistedLocal ( local ) ;
218
216
219
217
// Get the value from the hoisted locals, if it's tracked there.
@@ -223,10 +221,10 @@ private TValue GetLocal(ILocalReferenceOperation operation, LocalDataFlowState<T
223
221
return state . Get ( local ) ;
224
222
}
225
223
226
- private void SetLocal ( ILocalReferenceOperation operation , TValue value , LocalDataFlowState < TValue , TContext , TValueLattice , TContextLattice > state , bool merge = false )
224
+ private void SetLocal ( ILocalSymbol localSymbol , TValue value , LocalDataFlowState < TValue , TContext , TValueLattice , TContextLattice > state , bool merge = false )
227
225
{
228
- var local = new LocalKey ( operation . Local ) ;
229
- if ( IsReferenceToCapturedVariable ( operation ) )
226
+ var local = new LocalKey ( localSymbol ) ;
227
+ if ( IsCapturedVariable ( localSymbol ) )
230
228
InterproceduralState . TrackHoistedLocal ( local ) ;
231
229
232
230
// Update the value stored in the hoisted locals, if it's tracked there.
@@ -239,7 +237,23 @@ private void SetLocal(ILocalReferenceOperation operation, TValue value, LocalDat
239
237
state . Set ( local , newValue ) ;
240
238
}
241
239
242
- private TValue ProcessSingleTargetAssignment ( IOperation targetOperation , IAssignmentOperation operation , LocalDataFlowState < TValue , TContext , TValueLattice , TContextLattice > state , bool merge )
240
+ private TValue ProcessSingleTargetAssignment (
241
+ IOperation targetOperation ,
242
+ IAssignmentOperation operation ,
243
+ LocalDataFlowState < TValue , TContext , TValueLattice , TContextLattice > state ,
244
+ bool merge
245
+ )
246
+ {
247
+ return ProcessSingleTargetAssignment ( targetOperation , operation . Value , operation , state , merge ) ;
248
+ }
249
+
250
+ private TValue ProcessSingleTargetAssignment (
251
+ IOperation targetOperation ,
252
+ IOperation valueOperation ,
253
+ IOperation assignmentOperation ,
254
+ LocalDataFlowState < TValue , TContext , TValueLattice , TContextLattice > state ,
255
+ bool merge
256
+ )
243
257
{
244
258
switch ( targetOperation )
245
259
{
@@ -253,8 +267,8 @@ private TValue ProcessSingleTargetAssignment(IOperation targetOperation, IAssign
253
267
IParameterReferenceOperation parameterRef => GetParameterTargetValue ( parameterRef . Parameter ) ,
254
268
_ => throw new InvalidOperationException ( )
255
269
} ;
256
- TValue value = Visit ( operation . Value , state ) ;
257
- HandleAssignment ( value , targetValue , operation , in current . Context ) ;
270
+ TValue value = Visit ( valueOperation , state ) ;
271
+ HandleAssignment ( value , targetValue , assignmentOperation , in current . Context ) ;
258
272
return value ;
259
273
}
260
274
@@ -266,7 +280,7 @@ private TValue ProcessSingleTargetAssignment(IOperation targetOperation, IAssign
266
280
// correctly detect whether it is used for reading or writing inside of VisitPropertyReference.
267
281
// https://github.com/dotnet/roslyn/issues/25057
268
282
TValue instanceValue = Visit ( propertyRef . Instance , state ) ;
269
- TValue value = Visit ( operation . Value , state ) ;
283
+ TValue value = Visit ( valueOperation , state ) ;
270
284
IMethodSymbol ? setMethod = propertyRef . Property . GetSetMethod ( ) ;
271
285
272
286
if ( setMethod == null ||
@@ -287,7 +301,7 @@ private TValue ProcessSingleTargetAssignment(IOperation targetOperation, IAssign
287
301
288
302
var current = state . Current ;
289
303
TValue targetValue = GetBackingFieldTargetValue ( propertyRef , in current . Context ) ;
290
- HandleAssignment ( value , targetValue , operation , in current . Context ) ;
304
+ HandleAssignment ( value , targetValue , assignmentOperation , in current . Context ) ;
291
305
return value ;
292
306
}
293
307
@@ -297,7 +311,7 @@ private TValue ProcessSingleTargetAssignment(IOperation targetOperation, IAssign
297
311
arguments . Add ( Visit ( val , state ) ) ;
298
312
arguments . Add ( value ) ;
299
313
300
- HandleMethodCallHelper ( setMethod , instanceValue , arguments . ToImmutableArray ( ) , operation , state ) ;
314
+ HandleMethodCallHelper ( setMethod , instanceValue , arguments . ToImmutableArray ( ) , assignmentOperation , state ) ;
301
315
// The return value of a property set expression is the value,
302
316
// even though a property setter has no return value.
303
317
return value ;
@@ -308,14 +322,14 @@ private TValue ProcessSingleTargetAssignment(IOperation targetOperation, IAssign
308
322
// not a call to an event accessor method. There is no Roslyn API to access the field,
309
323
// so just visit the instance and the value. https://github.com/dotnet/roslyn/issues/40103
310
324
Visit ( eventRef . Instance , state ) ;
311
- return Visit ( operation . Value , state ) ;
325
+ return Visit ( valueOperation , state ) ;
312
326
}
313
327
case IImplicitIndexerReferenceOperation indexerRef :
314
328
{
315
329
// An implicit reference to an indexer where the argument is a System.Index
316
330
TValue instanceValue = Visit ( indexerRef . Instance , state ) ;
317
331
TValue indexArgumentValue = Visit ( indexerRef . Argument , state ) ;
318
- TValue value = Visit ( operation . Value , state ) ;
332
+ TValue value = Visit ( valueOperation , state ) ;
319
333
320
334
var property = ( IPropertySymbol ) indexerRef . IndexerSymbol ;
321
335
@@ -331,15 +345,23 @@ private TValue ProcessSingleTargetAssignment(IOperation targetOperation, IAssign
331
345
break ;
332
346
}
333
347
334
- HandleMethodCallHelper ( setMethod , instanceValue , argumentsBuilder . ToImmutableArray ( ) , operation , state ) ;
348
+ HandleMethodCallHelper ( setMethod , instanceValue , argumentsBuilder . ToImmutableArray ( ) , assignmentOperation , state ) ;
335
349
return value ;
336
350
}
337
351
338
352
// TODO: when setting a property in an attribute, target is an IPropertyReference.
339
353
case ILocalReferenceOperation localRef :
340
354
{
341
- TValue value = Visit ( operation . Value , state ) ;
342
- SetLocal ( localRef , value , state , merge ) ;
355
+ TValue value = Visit ( valueOperation , state ) ;
356
+ SetLocal ( localRef . Local , value , state , merge ) ;
357
+ return value ;
358
+ }
359
+ case IDeclarationPatternOperation declPattern :
360
+ {
361
+ if ( declPattern . DeclaredSymbol is not ILocalSymbol declaredSymbol )
362
+ break ;
363
+ var value = Visit ( valueOperation , state ) ;
364
+ SetLocal ( declaredSymbol , value , state , merge ) ;
343
365
return value ;
344
366
}
345
367
case IArrayElementReferenceOperation arrayElementRef :
@@ -349,22 +371,22 @@ private TValue ProcessSingleTargetAssignment(IOperation targetOperation, IAssign
349
371
350
372
TValue arrayRef = Visit ( arrayElementRef . ArrayReference , state ) ;
351
373
TValue index = Visit ( arrayElementRef . Indices [ 0 ] , state ) ;
352
- TValue value = Visit ( operation . Value , state ) ;
353
- HandleArrayElementWrite ( arrayRef , index , value , operation , merge : merge ) ;
374
+ TValue value = Visit ( valueOperation , state ) ;
375
+ HandleArrayElementWrite ( arrayRef , index , value , assignmentOperation , merge : merge ) ;
354
376
return value ;
355
377
}
356
378
case IInlineArrayAccessOperation inlineArrayAccess :
357
379
{
358
380
TValue arrayRef = Visit ( inlineArrayAccess . Instance , state ) ;
359
381
TValue index = Visit ( inlineArrayAccess . Argument , state ) ;
360
- TValue value = Visit ( operation . Value , state ) ;
361
- HandleArrayElementWrite ( arrayRef , index , value , operation , merge : merge ) ;
382
+ TValue value = Visit ( valueOperation , state ) ;
383
+ HandleArrayElementWrite ( arrayRef , index , value , assignmentOperation , merge : merge ) ;
362
384
return value ;
363
385
}
364
386
case IDiscardOperation :
365
387
// Assignments like "_ = SomeMethod();" don't need dataflow tracking.
366
388
// Seems like this can't happen with a flow capture operation.
367
- Debug . Assert ( operation . Target is not IFlowCaptureReferenceOperation ) ;
389
+ Debug . Assert ( targetOperation is not IFlowCaptureReferenceOperation ) ;
368
390
break ;
369
391
case IInstanceReferenceOperation :
370
392
// Assignment to 'this' is not tracked currently.
@@ -389,14 +411,45 @@ private TValue ProcessSingleTargetAssignment(IOperation targetOperation, IAssign
389
411
UnexpectedOperationHandler . Handle ( targetOperation ) ;
390
412
break ;
391
413
}
392
- return Visit ( operation . Value , state ) ;
414
+ return Visit ( valueOperation , state ) ;
393
415
}
394
416
395
417
public override TValue VisitSimpleAssignment ( ISimpleAssignmentOperation operation , LocalDataFlowState < TValue , TContext , TValueLattice , TContextLattice > state )
396
418
{
397
419
return ProcessAssignment ( operation , state ) ;
398
420
}
399
421
422
+ public override TValue VisitIsPattern ( IIsPatternOperation operation , LocalDataFlowState < TValue , TContext , TValueLattice , TContextLattice > state )
423
+ {
424
+ if ( operation . Pattern is IDeclarationPatternOperation declarationPattern )
425
+ {
426
+ // A declaration pattern is like an assignment to a local
427
+ return ProcessSingleTargetAssignment (
428
+ declarationPattern ,
429
+ operation . Value ,
430
+ operation ,
431
+ state ,
432
+ merge : false
433
+ ) ;
434
+ }
435
+ return base . VisitIsPattern ( operation , state ) ;
436
+ }
437
+
438
+ public override TValue VisitPropertySubpattern ( IPropertySubpatternOperation propPattern , LocalDataFlowState < TValue , TContext , TValueLattice , TContextLattice > state )
439
+ {
440
+ if ( propPattern . Pattern is IDeclarationPatternOperation declPattern )
441
+ {
442
+ return ProcessSingleTargetAssignment (
443
+ declPattern ,
444
+ propPattern . Member ,
445
+ propPattern ,
446
+ state ,
447
+ merge : false
448
+ ) ;
449
+ }
450
+ return base . VisitPropertySubpattern ( propPattern , state ) ;
451
+ }
452
+
400
453
public override TValue VisitCompoundAssignment ( ICompoundAssignmentOperation operation , LocalDataFlowState < TValue , TContext , TValueLattice , TContextLattice > state )
401
454
{
402
455
return ProcessAssignment ( operation , state ) ;
0 commit comments