Skip to content

Commit 6f1801d

Browse files
common helper
1 parent 5d19d55 commit 6f1801d

File tree

1 file changed

+38
-46
lines changed

1 file changed

+38
-46
lines changed

src/Features/Core/Portable/ExtractMethod/SelectionResult.cs

Lines changed: 38 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)