Skip to content

Commit 65942dc

Browse files
authored
Merge pull request #60492 from genlu/NRTSyncNamespace
Enable NRT in AbstractSyncNamespaceCodeRefactoringProvider
2 parents 6888cd6 + 84c0f52 commit 65942dc

File tree

4 files changed

+32
-35
lines changed

4 files changed

+32
-35
lines changed

src/Features/CSharp/Portable/CodeRefactorings/SyncNamespace/CSharpSyncNamespaceCodeRefactoringProvider.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5-
#nullable disable
6-
75
using System.Collections.Immutable;
86
using System.Composition;
97
using System.Diagnostics.CodeAnalysis;
@@ -28,14 +26,15 @@ public CSharpSyncNamespaceCodeRefactoringProvider()
2826
{
2927
}
3028

31-
protected override async Task<SyntaxNode> TryGetApplicableInvocationNodeAsync(Document document, TextSpan span, CancellationToken cancellationToken)
29+
protected override async Task<SyntaxNode?> TryGetApplicableInvocationNodeAsync(Document document, TextSpan span, CancellationToken cancellationToken)
3230
{
3331
if (!span.IsEmpty)
3432
return null;
3533

36-
var position = span.Start;
34+
if (await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false) is not CompilationUnitSyntax compilationUnit)
35+
return null;
3736

38-
var compilationUnit = (CompilationUnitSyntax)await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
37+
var position = span.Start;
3938
var namespaceDecls = compilationUnit.DescendantNodes(n => n is CompilationUnitSyntax or BaseNamespaceDeclarationSyntax)
4039
.OfType<BaseNamespaceDeclarationSyntax>().ToImmutableArray();
4140

src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractSyncNamespaceCodeRefactoringProvider.MoveFileCodeAction.cs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5-
#nullable disable
6-
75
using System;
86
using System.Collections.Generic;
97
using System.Collections.Immutable;
@@ -14,6 +12,7 @@
1412
using System.Threading.Tasks;
1513
using Microsoft.CodeAnalysis.CodeActions;
1614
using Microsoft.CodeAnalysis.PooledObjects;
15+
using Microsoft.CodeAnalysis.Shared.Extensions;
1716
using Roslyn.Utilities;
1817

1918
namespace Microsoft.CodeAnalysis.CodeRefactorings.SyncNamespace
@@ -42,12 +41,11 @@ public MoveFileCodeAction(State state, ImmutableArray<string> newFolders)
4241

4342
protected override async Task<IEnumerable<CodeActionOperation>> ComputeOperationsAsync(CancellationToken cancellationToken)
4443
{
45-
var id = _state.Document.Id;
44+
var document = _state.Document;
4645
var solution = _state.Document.Project.Solution;
47-
var document = solution.GetDocument(id);
4846
var newDocumentId = DocumentId.CreateNewId(document.Project.Id, document.Name);
4947

50-
solution = solution.RemoveDocument(id);
48+
solution = solution.RemoveDocument(document.Id);
5149

5250
var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
5351
solution = solution.AddDocument(newDocumentId, document.Name, text, folders: _newfolders);

src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractSyncNamespaceCodeRefactoringProvider.State.cs

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5-
#nullable disable
6-
75
using System.Collections.Generic;
86
using System.Diagnostics;
97
using System.IO;
@@ -43,29 +41,29 @@ internal sealed class State
4341
/// This is the new name we want to change the namespace to.
4442
/// Empty string means global namespace, whereas null means change namespace action is not available.
4543
/// </summary>
46-
public string TargetNamespace { get; }
44+
public string? TargetNamespace { get; }
4745

4846
/// <summary>
4947
/// This is the part of the declared namespace that is contained in default namespace.
5048
/// We will use this to construct target folder to move the file to.
5149
/// For example, if default namespace is `A` and declared namespace is `A.B.C`,
5250
/// this would be `B.C`.
5351
/// </summary>
54-
public string RelativeDeclaredNamespace { get; }
52+
public string? RelativeDeclaredNamespace { get; }
5553

5654
private State(
5755
Document document,
5856
SyntaxNode container,
59-
string targetNamespace,
60-
string relativeDeclaredNamespace)
57+
string? targetNamespace,
58+
string? relativeDeclaredNamespace)
6159
{
6260
Document = document;
6361
Container = container;
6462
TargetNamespace = targetNamespace;
6563
RelativeDeclaredNamespace = relativeDeclaredNamespace;
6664
}
6765

68-
public static async Task<State> CreateAsync(
66+
public static async Task<State?> CreateAsync(
6967
AbstractSyncNamespaceCodeRefactoringProvider<TNamespaceDeclarationSyntax, TCompilationUnitSyntax, TMemberDeclarationSyntax> provider,
7068
Document document,
7169
TextSpan textSpan,
@@ -93,15 +91,15 @@ public static async Task<State> CreateAsync(
9391
return null;
9492
}
9593

96-
var changeNamespaceService = document.GetLanguageService<IChangeNamespaceService>();
94+
var changeNamespaceService = document.GetRequiredLanguageService<IChangeNamespaceService>();
9795
var canChange = await changeNamespaceService.CanChangeNamespaceAsync(document, applicableNode, cancellationToken).ConfigureAwait(false);
9896

9997
if (!canChange || !IsDocumentPathRootedInProjectFolder(document))
10098
{
10199
return null;
102100
}
103101

104-
var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>();
102+
var syntaxFacts = document.GetRequiredLanguageService<ISyntaxFactsService>();
105103

106104
// We can't determine what the expected namespace would be without knowing the default namespace.
107105
var defaultNamespace = GetDefaultNamespace(document, syntaxFacts);
@@ -152,36 +150,40 @@ public static async Task<State> CreateAsync(
152150
/// </summary>
153151
private static bool IsDocumentPathRootedInProjectFolder(Document document)
154152
{
153+
var absoluteDircetoryPath = PathUtilities.GetDirectoryName(document.FilePath);
154+
if (absoluteDircetoryPath is null)
155+
return false;
156+
155157
var projectRoot = PathUtilities.GetDirectoryName(document.Project.FilePath);
156-
var folderPath = Path.Combine(document.Folders.ToArray());
158+
if (projectRoot is null)
159+
return false;
157160

158-
var absoluteDircetoryPath = PathUtilities.GetDirectoryName(document.FilePath);
161+
var folderPath = Path.Combine(document.Folders.ToArray());
159162
var logicalDirectoryPath = PathUtilities.CombineAbsoluteAndRelativePaths(projectRoot, folderPath);
163+
if (logicalDirectoryPath is null)
164+
return false;
160165

161166
return PathUtilities.PathsEqual(absoluteDircetoryPath, logicalDirectoryPath);
162167
}
163168

164-
private static string GetDefaultNamespace(Document document, ISyntaxFactsService syntaxFacts)
169+
private static string? GetDefaultNamespace(Document document, ISyntaxFactsService syntaxFacts)
165170
{
166171
var solution = document.Project.Solution;
167172
var linkedIds = document.GetLinkedDocumentIds();
168-
var documents = linkedIds.SelectAsArray(id => solution.GetDocument(id)).Add(document);
173+
var documents = linkedIds.SelectAsArray(id => solution.GetRequiredDocument(id)).Add(document);
169174

170175
// For all projects containing all the linked documents, bail if
171176
// 1. Any of them doesn't have default namespace, or
172177
// 2. Multiple default namespace are found. (this might be possible by tweaking project file).
173178
// The refactoring depends on a single default namespace to operate.
174-
var defaultNamespaceFromProjects = new HashSet<string>(
179+
var defaultNamespaceFromProjects = new HashSet<string?>(
175180
documents.Select(d => d.Project.DefaultNamespace),
176181
syntaxFacts.StringComparer);
177182

178-
if (defaultNamespaceFromProjects.Count != 1
179-
|| defaultNamespaceFromProjects.First() == null)
180-
{
183+
if (defaultNamespaceFromProjects.Count > 1)
181184
return null;
182-
}
183185

184-
return defaultNamespaceFromProjects.Single();
186+
return defaultNamespaceFromProjects.SingleOrDefault();
185187
}
186188

187189
/// <summary>
@@ -195,7 +197,7 @@ private static string GetDefaultNamespace(Document document, ISyntaxFactsService
195197
/// the relative namespace is "".
196198
/// - If <paramref name="relativeTo"/> is "" then the relative namespace us <paramref name="namespace"/>.
197199
/// </summary>
198-
private static string GetRelativeNamespace(string relativeTo, string @namespace, ISyntaxFactsService syntaxFacts)
200+
private static string? GetRelativeNamespace(string relativeTo, string @namespace, ISyntaxFactsService syntaxFacts)
199201
{
200202
Debug.Assert(relativeTo != null && @namespace != null);
201203

@@ -213,7 +215,7 @@ private static string GetRelativeNamespace(string relativeTo, string @namespace,
213215
}
214216

215217
var containingText = relativeTo + ".";
216-
var namespacePrefix = @namespace.Substring(0, containingText.Length);
218+
var namespacePrefix = @namespace[..containingText.Length];
217219

218220
return syntaxFacts.StringComparer.Equals(containingText, namespacePrefix)
219221
? @namespace[(relativeTo.Length + 1)..]

src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractSyncNamespaceCodeRefactoringProvider.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5-
#nullable disable
6-
75
using System;
86
using System.Threading;
97
using System.Threading.Tasks;
@@ -69,7 +67,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte
6967
// is global namespace, i.e. default namespace is "" and the file is located at project
7068
// root directory, and no namespace declaration in the document, respectively.
7169

72-
var service = document.GetLanguageService<IChangeNamespaceService>();
70+
var service = document.GetRequiredLanguageService<IChangeNamespaceService>();
7371

7472
var solutionChangeAction = new ChangeNamespaceCodeAction(
7573
state.TargetNamespace.Length == 0
@@ -91,7 +89,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte
9189
/// declaration in global namespace and there's no namespace declaration in this document.
9290
/// (3) otherwise, null.
9391
/// </returns>
94-
protected abstract Task<SyntaxNode> TryGetApplicableInvocationNodeAsync(Document document, TextSpan span, CancellationToken cancellationToken);
92+
protected abstract Task<SyntaxNode?> TryGetApplicableInvocationNodeAsync(Document document, TextSpan span, CancellationToken cancellationToken);
9593

9694
protected abstract string EscapeIdentifier(string identifier);
9795

0 commit comments

Comments
 (0)