@@ -34,6 +34,10 @@ public MethodInfo(TypeInfo typeInfo, IMethodSymbol symbol, MethodDeclarationSynt
34
34
35
35
public bool Missing { get ; set ; }
36
36
37
+ public bool Required { get ; set ; }
38
+
39
+ public MethodAsyncConversion ? Conversion { get ; set ; }
40
+
37
41
public HashSet < MethodInfo > InvokedBy { get ; } = new HashSet < MethodInfo > ( ) ;
38
42
39
43
/// <summary>
@@ -103,7 +107,7 @@ public void CalculateIgnore(int deep = 0, HashSet<MethodInfo> processedMethodInf
103
107
return ;
104
108
}
105
109
106
- if ( Missing || ImplementsAbstractMethod )
110
+ if ( Missing || ImplementsAbstractMethod || Required )
107
111
{
108
112
foreach ( var refResult in ReferenceResults )
109
113
{
@@ -148,20 +152,30 @@ public void CalculateIgnore(int deep = 0, HashSet<MethodInfo> processedMethodInf
148
152
return ;
149
153
}
150
154
151
- var dependencies = ReferenceResults
155
+ var relRefResults = ReferenceResults
152
156
. Union ( GetAllRelatedMethods ( ) . ToList ( ) . SelectMany ( o => o . ReferenceResults ) )
153
157
. ToList ( ) ;
154
158
155
- foreach ( var refResult in dependencies )
159
+ foreach ( var refResult in relRefResults )
160
+ {
161
+ refResult . CalculateIgnore ( deep , processedMethodInfos ) ;
162
+ }
163
+ Ignore = relRefResults . All ( o => o . Ignore ) ;
164
+
165
+ if ( Ignore )
166
+ {
167
+ relRefResults = relRefResults . Except ( ReferenceResults ) . ToList ( ) ;
168
+ }
169
+
170
+ foreach ( var refResult in relRefResults )
156
171
{
157
172
// if the reference cannot be async we should preserve the original method. TODO: what if the method has dependecies that are async
158
173
if ( ! refResult . CanBeAsync && refResult . MethodInfo != null )
159
174
{
160
175
refResult . MethodInfo . CanBeAsnyc = false ;
161
176
}
162
- refResult . CalculateIgnore ( deep , processedMethodInfos ) ;
163
177
}
164
- Ignore = dependencies . All ( o => o . Ignore ) ;
178
+
165
179
_ignoreCalculating = false ;
166
180
_ignoreCalculated = true ;
167
181
}
@@ -272,12 +286,13 @@ public IEnumerable<MethodInfo> GetAllDependencies()
272
286
273
287
private void AnalyzeInvocationExpression ( SyntaxNode node , SimpleNameSyntax nameNode , MethodReferenceResult result )
274
288
{
275
- var selectClause = node . Ancestors ( )
276
- . FirstOrDefault ( o => o . IsKind ( SyntaxKind . SelectClause ) ) ;
277
- if ( selectClause != null ) // await is not supported in select clause
289
+ var queryExpression = node . Ancestors ( )
290
+ . OfType < QueryExpressionSyntax > ( )
291
+ . FirstOrDefault ( ) ;
292
+ if ( queryExpression != null ) // await is not supported in linq query
278
293
{
279
294
result . CanBeAsync = false ;
280
- Logger . Warn ( $ "Cannot await async method in a select clause :\r \n { selectClause } \r \n ") ;
295
+ Logger . Warn ( $ "Cannot await async method in a query expression :\r \n { queryExpression } \r \n ") ;
281
296
return ;
282
297
}
283
298
var docInfo = TypeInfo . NamespaceInfo . DocumentInfo ;
@@ -311,13 +326,31 @@ private void AnalyzeInvocationExpression(SyntaxNode node, SimpleNameSyntax nameN
311
326
return ;
312
327
}
313
328
329
+
330
+ // Custom code TODO: move
331
+ if ( nameNode . Identifier . ToString ( ) == "ToList" )
332
+ {
333
+ var beforeToListExpression = ( ( MemberAccessExpressionSyntax ) ( ( InvocationExpressionSyntax ) node ) . Expression ) . Expression ;
334
+ var operation = docInfo . SemanticModel . GetOperation ( beforeToListExpression ) ;
335
+ if ( operation == null )
336
+ {
337
+ result . CanBeAsync = false ;
338
+ Logger . Warn ( $ "Cannot find operation for previous node of ToList:\r \n { beforeToListExpression } \r \n ") ;
339
+ }
340
+ else if ( operation . Type . Name != "IQueryable" )
341
+ {
342
+ result . CanBeAsync = false ;
343
+ Logger . Warn ( $ "Operation for previous node of ToList is not IQueryable:\r \n { operation . Type . Name } \r \n ") ;
344
+ }
345
+ }
346
+ // End custom code
347
+
314
348
var anonFunctionNode = node . Ancestors ( )
315
349
. OfType < AnonymousFunctionExpressionSyntax > ( )
316
350
. FirstOrDefault ( ) ;
317
351
if ( anonFunctionNode ? . AsyncKeyword . IsMissing == false )
318
352
{
319
- // Custom code
320
-
353
+ // Custom code TODO: move
321
354
var methodArgTypeInfo = ModelExtensions . GetTypeInfo ( docInfo . SemanticModel , anonFunctionNode ) ;
322
355
var convertedType = methodArgTypeInfo . ConvertedType ;
323
356
if ( convertedType != null && convertedType . ContainingAssembly . Name == "nunit.framework" &&
@@ -329,7 +362,7 @@ private void AnalyzeInvocationExpression(SyntaxNode node, SimpleNameSyntax nameN
329
362
result . MakeAnonymousFunctionAsync = true ;
330
363
return ;
331
364
}
332
- //end
365
+ // End custom code
333
366
334
367
result . CanBeAsync = false ;
335
368
Logger . Warn ( $ "Cannot await async method in an non async anonymous function:\r \n { anonFunctionNode } \r \n ") ;
@@ -346,14 +379,14 @@ private void AnalyzeArgumentExpression(SyntaxNode node, SimpleNameSyntax nameNod
346
379
return ;
347
380
}
348
381
349
- // Custom code
382
+ // Custom code TODO: move
350
383
var convertedType = methodArgTypeInfo . ConvertedType ;
351
384
if ( convertedType . ContainingAssembly . Name == "nunit.framework" && convertedType . Name == "TestDelegate" )
352
385
{
353
386
result . WrapInsideAsyncFunction = true ;
354
387
return ;
355
388
}
356
- //end
389
+ // End custom code
357
390
358
391
var delegateMethod = ( IMethodSymbol ) methodArgTypeInfo . ConvertedType . GetMembers ( "Invoke" ) . First ( ) ;
359
392
@@ -479,7 +512,7 @@ public MethodReferenceResult AnalyzeReference(ReferenceLocation reference)
479
512
return result ;
480
513
}
481
514
482
- public List < AsyncCounterpartMethod > FindAsyncCounterpartMethodsWhitinBody ( Dictionary < IMethodSymbol , IMethodSymbol > methodAsyncConterparts = null )
515
+ public async Task < List < AsyncCounterpartMethod > > FindAsyncCounterpartMethodsWhitinBody ( Dictionary < IMethodSymbol , IMethodSymbol > methodAsyncConterparts = null )
483
516
{
484
517
var result = new List < AsyncCounterpartMethod > ( ) ;
485
518
if ( Node . Body == null )
@@ -503,10 +536,11 @@ public List<AsyncCounterpartMethod> FindAsyncCounterpartMethodsWhitinBody(Dictio
503
536
}
504
537
else
505
538
{
506
- var config = TypeInfo . NamespaceInfo . DocumentInfo . ProjectInfo . Configuration ;
539
+ var projectInfo = TypeInfo . NamespaceInfo . DocumentInfo . ProjectInfo ;
540
+ var config = projectInfo . Configuration ;
507
541
if ( config . FindAsyncCounterpart != null )
508
542
{
509
- asyncMethodSymbol = config . FindAsyncCounterpart . Invoke ( methodSymbol . OriginalDefinition ) ;
543
+ asyncMethodSymbol = await config . FindAsyncCounterpart . Invoke ( projectInfo . Project , methodSymbol . OriginalDefinition ) . ConfigureAwait ( false ) ;
510
544
}
511
545
else
512
546
{
@@ -613,7 +647,9 @@ public void Analyze()
613
647
{
614
648
ReferenceResults . Add ( AnalyzeReference ( reference ) ) ;
615
649
}
616
- CanBeAsnyc = ReferenceResults . Any ( o => o . CanBeAsync ) ;
650
+ // TODO: TypeTransformation should be removed
651
+ CanBeAsnyc = ReferenceResults . Any ( o => o . CanBeAsync ) ||
652
+ ( Conversion == MethodAsyncConversion . ToAsync && TypeInfo . TypeTransformation == TypeTransformation . Partial ) ;
617
653
618
654
// TODO: check if this is correct
619
655
if ( TypeInfo . TypeTransformation == TypeTransformation . Partial && GetAllRelatedMethods ( ) . ToList ( ) . Any ( o => o . InvokedBy . Any ( ) ) )
0 commit comments