Skip to content

Commit 6196f4f

Browse files
Initial stubs for inverting #if
1 parent e0ace0d commit 6196f4f

File tree

2 files changed

+58
-11
lines changed

2 files changed

+58
-11
lines changed

src/Features/Core/Portable/InvertIf/AbstractInvertIfCodeRefactoringProvider.StatementRange.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@
88
namespace Microsoft.CodeAnalysis.InvertIf;
99

1010
internal abstract partial class AbstractInvertIfCodeRefactoringProvider<
11-
TSyntaxKind, TStatementSyntax, TIfStatementSyntax, TEmbeddedStatement>
11+
TSyntaxKind,
12+
TStatementSyntax,
13+
TIfStatementSyntax,
14+
TEmbeddedStatementSyntax,
15+
TDirectiveSyntaxSyntax>
1216
{
1317
protected readonly struct StatementRange
1418
{

src/Features/Core/Portable/InvertIf/AbstractInvertIfCodeRefactoringProvider.cs

Lines changed: 53 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,15 @@
2222
namespace Microsoft.CodeAnalysis.InvertIf;
2323

2424
internal abstract partial class AbstractInvertIfCodeRefactoringProvider<
25-
TSyntaxKind, TStatementSyntax, TIfStatementSyntax, TEmbeddedStatement> : CodeRefactoringProvider
25+
TSyntaxKind,
26+
TStatementSyntax,
27+
TIfStatementSyntax,
28+
TEmbeddedStatementSyntax,
29+
TDirectiveSyntaxSyntax> : CodeRefactoringProvider
2630
where TSyntaxKind : struct, Enum
2731
where TStatementSyntax : SyntaxNode
2832
where TIfStatementSyntax : TStatementSyntax
33+
where TDirectiveSyntaxSyntax : SyntaxNode
2934
{
3035
private enum InvertIfStyle
3136
{
@@ -60,30 +65,68 @@ private enum InvertIfStyle
6065
protected abstract StatementRange GetIfBodyStatementRange(TIfStatementSyntax ifNode);
6166
protected abstract SyntaxNode GetCondition(TIfStatementSyntax ifNode);
6267

63-
protected abstract IEnumerable<TStatementSyntax> UnwrapBlock(TEmbeddedStatement ifBody);
64-
protected abstract TEmbeddedStatement GetIfBody(TIfStatementSyntax ifNode);
65-
protected abstract TEmbeddedStatement GetElseBody(TIfStatementSyntax ifNode);
66-
protected abstract TEmbeddedStatement GetEmptyEmbeddedStatement();
68+
protected abstract IEnumerable<TStatementSyntax> UnwrapBlock(TEmbeddedStatementSyntax ifBody);
69+
protected abstract TEmbeddedStatementSyntax GetIfBody(TIfStatementSyntax ifNode);
70+
protected abstract TEmbeddedStatementSyntax GetElseBody(TIfStatementSyntax ifNode);
71+
protected abstract TEmbeddedStatementSyntax GetEmptyEmbeddedStatement();
6772

68-
protected abstract TEmbeddedStatement AsEmbeddedStatement(
73+
protected abstract TEmbeddedStatementSyntax AsEmbeddedStatement(
6974
IEnumerable<TStatementSyntax> statements,
70-
TEmbeddedStatement original);
75+
TEmbeddedStatementSyntax original);
7176

7277
protected abstract TIfStatementSyntax UpdateIf(
7378
SourceText sourceText,
7479
TIfStatementSyntax ifNode,
7580
SyntaxNode condition,
76-
TEmbeddedStatement trueStatement,
77-
TEmbeddedStatement? falseStatement = default);
81+
TEmbeddedStatementSyntax trueStatement,
82+
TEmbeddedStatementSyntax? falseStatement = default);
7883

7984
protected abstract SyntaxNode WithStatements(
8085
SyntaxNode node,
8186
IEnumerable<TStatementSyntax> statements);
8287

8388
public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
8489
{
85-
var (document, _, cancellationToken) = context;
90+
if (await TryComputeRefactoringForIfDirectiveAsync(context).ConfigureAwait(false))
91+
return;
92+
93+
await TryComputeRefactorForIfStatementAsync(context).ConfigureAwait(false);
94+
}
95+
96+
private async ValueTask<bool> TryComputeRefactoringForIfDirectiveAsync(CodeRefactoringContext context)
97+
{
98+
var (document, textSpan, cancellationToken) = context;
99+
if (textSpan.IsEmpty)
100+
return false;
101+
102+
var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
103+
104+
var token = root.FindToken(textSpan.Start, findInsideTrivia: true);
105+
var directive = token.GetAncestor<TDirectiveSyntaxSyntax>();
106+
if (directive is null)
107+
return false;
86108

109+
var syntaxFacts = document.GetRequiredLanguageService<ISyntaxFactsService>();
110+
var syntaxKinds = syntaxFacts.SyntaxKinds;
111+
112+
if (directive.RawKind != syntaxKinds.IfDirectiveTrivia)
113+
return false;
114+
115+
var conditionalDirectives = syntaxFacts.GetMatchingConditionalDirectives(directive, cancellationToken);
116+
if (conditionalDirectives.Length != 3)
117+
return false;
118+
119+
if (conditionalDirectives[0].RawKind != syntaxKinds.IfDirectiveTrivia ||
120+
conditionalDirectives[1].RawKind != syntaxKinds.ElseDirectiveTrivia ||
121+
conditionalDirectives[2].RawKind != syntaxKinds.EndIfDirectiveTrivia)
122+
{
123+
return false;
124+
}
125+
}
126+
127+
private async ValueTask TryComputeRefactorForIfStatementAsync(CodeRefactoringContext context)
128+
{
129+
var (document, textSpan, cancellationToken) = context;
87130
var ifNode = await context.TryGetRelevantNodeAsync<TIfStatementSyntax>().ConfigureAwait(false);
88131
if (ifNode == null)
89132
return;

0 commit comments

Comments
 (0)