@@ -29,7 +29,8 @@ internal abstract class SelectionResult(
2929 protected static readonly SyntaxAnnotation s_firstTokenAnnotation = new ( ) ;
3030 protected static readonly SyntaxAnnotation s_lastTokenAnnotation = new ( ) ;
3131
32- private bool ? _createAsyncMethod ;
32+ private bool ? _containsAwaitExpression ;
33+ private bool ? _containsConfigureAwaitFalse ;
3334
3435 public SemanticDocument SemanticDocument { get ; private set ; } = document ;
3536 public TextSpan FinalSpan { get ; } = finalSpan ;
@@ -120,64 +121,55 @@ public TExecutableStatementSyntax GetLastStatement()
120121 return token . GetRequiredAncestor < TExecutableStatementSyntax > ( ) ;
121122 }
122123
123- public bool ContainsAwaitExpression ( )
124+ /// <summary>
125+ /// Checks all of the nodes within the user's selection to see if any of them satisfy the supplied <paramref
126+ /// name="predicate"/>. Will not descend into local functions or lambdas.
127+ /// </summary>
128+ /// <param name="predicate"></param>
129+ /// <returns></returns>
130+ private bool CheckNodesInSelection ( Func < ISyntaxFacts , SyntaxNode , bool > predicate )
124131 {
125- _createAsyncMethod ??= CreateAsyncMethodWorker ( ) ;
126- return _createAsyncMethod . Value ;
132+ var firstToken = this . GetFirstTokenInSelection ( ) ;
133+ var lastToken = this . GetLastTokenInSelection ( ) ;
134+ var span = TextSpan . FromBounds ( firstToken . SpanStart , lastToken . Span . End ) ;
127135
128- bool CreateAsyncMethodWorker ( )
129- {
130- var firstToken = this . GetFirstTokenInSelection ( ) ;
131- var lastToken = this . GetLastTokenInSelection ( ) ;
132- var span = TextSpan . FromBounds ( firstToken . SpanStart , lastToken . Span . End ) ;
136+ using var _ = ArrayBuilder < SyntaxNode > . GetInstance ( out var stack ) ;
137+ stack . Push ( this . GetContainingScope ( ) ) ;
133138
134- using var _ = ArrayBuilder < SyntaxNode > . GetInstance ( out var stack ) ;
135- stack . Push ( this . GetContainingScope ( ) ) ;
139+ var syntaxFacts = this . SemanticDocument . GetRequiredLanguageService < ISyntaxFactsService > ( ) ;
136140
137- var syntaxFacts = this . SemanticDocument . GetRequiredLanguageService < ISyntaxFactsService > ( ) ;
141+ while ( stack . TryPop ( out var current ) )
142+ {
143+ // Don't dive into lambdas and local functions. They reset the async/await context.
144+ if ( syntaxFacts . IsAnonymousOrLocalFunction ( current ) )
145+ continue ;
138146
139- while ( stack . TryPop ( out var current ) )
147+ if ( predicate ( syntaxFacts , current ) )
148+ return true ;
149+
150+ // Only dive into child nodes within the span being extracted.
151+ foreach ( var childNode in current . ChildNodes ( ) )
140152 {
141- // Don't dive into lambdas and local functions. They reset the async/await context.
142- if ( syntaxFacts . IsAnonymousOrLocalFunction ( current ) )
143- continue ;
144-
145- if ( syntaxFacts . IsAwaitExpression ( current ) )
146- return true ;
147-
148- // Only dive into child nodes within the span being extracted.
149- foreach ( var childNode in current . ChildNodes ( ) )
150- {
151- if ( childNode . Span . OverlapsWith ( span ) )
152- stack . Push ( childNode ) ;
153- }
153+ if ( childNode . Span . OverlapsWith ( span ) )
154+ stack . Push ( childNode ) ;
154155 }
155-
156- return false ;
157156 }
157+
158+ return false ;
158159 }
159160
160- public bool ShouldCallConfigureAwaitFalse ( )
161+ public bool ContainsAwaitExpression ( )
161162 {
162- var syntaxFacts = SemanticDocument . GetRequiredLanguageService < ISyntaxFactsService > ( ) ;
163-
164- var firstToken = GetFirstTokenInSelection ( ) ;
165- var lastToken = GetLastTokenInSelection ( ) ;
166-
167- var span = TextSpan . FromBounds ( firstToken . SpanStart , lastToken . Span . End ) ;
168-
169- foreach ( var node in SemanticDocument . Root . DescendantNodesAndSelf ( ) )
170- {
171- if ( ! node . Span . OverlapsWith ( span ) )
172- continue ;
173-
174- if ( IsConfigureAwaitFalse ( node ) && ! UnderAnonymousOrLocalMethod ( node . GetFirstToken ( ) , firstToken , lastToken ) )
175- return true ;
176- }
163+ return _containsAwaitExpression ??= CheckNodesInSelection (
164+ static ( syntaxFacts , node ) => syntaxFacts . IsAwaitExpression ( node ) ) ;
165+ }
177166
178- return false ;
167+ public bool ContainsConfigureAwaitFalse ( )
168+ {
169+ return _containsConfigureAwaitFalse ??= CheckNodesInSelection (
170+ static ( syntaxFacts , node ) => IsConfigureAwaitFalse ( syntaxFacts , node ) ) ;
179171
180- bool IsConfigureAwaitFalse ( SyntaxNode node )
172+ static bool IsConfigureAwaitFalse ( ISyntaxFacts syntaxFacts , SyntaxNode node )
181173 {
182174 if ( ! syntaxFacts . IsInvocationExpression ( node ) )
183175 return false ;
0 commit comments