Skip to content

Commit d4afaea

Browse files
author
Andrew Hall
authored
Disable move type when the options service isn't present (#36334)
Use MEF to provide implementation contract
1 parent b07e89b commit d4afaea

File tree

7 files changed

+68
-27
lines changed

7 files changed

+68
-27
lines changed

src/EditorFeatures/CSharpTest/MoveToNamespace/MoveToNamespaceTests.cs

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
// Copyright(c) Microsoft.All Rights Reserved.Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
22

33
using System.Collections.Generic;
4-
using System.Collections.Immutable;
4+
using System.Linq;
5+
using System.Threading;
56
using System.Threading.Tasks;
7+
using Microsoft.CodeAnalysis.CodeRefactorings;
8+
using Microsoft.CodeAnalysis.CSharp.MoveToNamespace;
69
using Microsoft.CodeAnalysis.Editor.UnitTests;
710
using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces;
11+
using Microsoft.CodeAnalysis.MoveToNamespace;
812
using Microsoft.CodeAnalysis.Test.Utilities;
913
using Microsoft.CodeAnalysis.Test.Utilities.MoveToNamespace;
1014
using Microsoft.VisualStudio.Composition;
@@ -16,14 +20,15 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.MoveToNamespace
1620
[UseExportProvider]
1721
public class MoveToNamespaceTests : AbstractMoveToNamespaceTests
1822
{
19-
private static readonly IExportProviderFactory CSharpExportProviderFactory =
23+
private static readonly IExportProviderFactory ExportProviderFactory =
2024
ExportProviderCache.GetOrCreateExportProviderFactory(
21-
TestExportProvider.EntireAssemblyCatalogWithCSharpAndVisualBasic
22-
.WithPart(typeof(TestMoveToNamespaceOptionsService))
23-
.WithPart(typeof(TestSymbolRenamedCodeActionOperationFactoryWorkspaceService)));
25+
TestExportProvider.EntireAssemblyCatalogWithCSharpAndVisualBasic.WithPart(typeof(TestMoveToNamespaceOptionsService)));
2426

2527
protected override TestWorkspace CreateWorkspaceFromFile(string initialMarkup, TestParameters parameters)
26-
=> TestWorkspace.CreateCSharp(initialMarkup, parameters.parseOptions, parameters.compilationOptions, exportProvider: CSharpExportProviderFactory.CreateExportProvider());
28+
=> CreateWorkspaceFromFile(initialMarkup, parameters, ExportProviderFactory);
29+
30+
protected TestWorkspace CreateWorkspaceFromFile(string initialMarkup, TestParameters parameters, IExportProviderFactory exportProviderFactory)
31+
=> TestWorkspace.CreateCSharp(initialMarkup, parameters.parseOptions, parameters.compilationOptions, exportProvider: exportProviderFactory.CreateExportProvider());
2732

2833
protected override ParseOptions GetScriptOptions() => Options.Script;
2934

@@ -1080,5 +1085,34 @@ class C2
10801085
{
10811086
{"Two.C2", "Three.C2" }
10821087
});
1088+
1089+
[WpfFact, Trait(Traits.Feature, Traits.Features.MoveToNamespace)]
1090+
[WorkItem(35577, "https://github.com/dotnet/roslyn/issues/35577")]
1091+
public async Task MoveToNamespace_WithoutOptionsService()
1092+
{
1093+
var code = @"namespace A[||]
1094+
{
1095+
class MyClass
1096+
{
1097+
void Method() { }
1098+
}
1099+
}";
1100+
1101+
var exportProviderWithoutOptionsService = ExportProviderCache.GetOrCreateExportProviderFactory(
1102+
TestExportProvider.EntireAssemblyCatalogWithCSharpAndVisualBasic.WithoutPartsOfType(typeof(IMoveToNamespaceOptionsService)));
1103+
1104+
using (var workspace = CreateWorkspaceFromFile(code, new TestParameters(), exportProviderWithoutOptionsService))
1105+
using (var testState = new TestState(workspace))
1106+
{
1107+
Assert.Null(testState.TestMoveToNamespaceOptionsService);
1108+
1109+
var actions = await testState.MoveToNamespaceService.GetCodeActionsAsync(
1110+
testState.InvocationDocument,
1111+
testState.TestInvocationDocument.SelectedSpans.Single(),
1112+
CancellationToken.None);
1113+
1114+
Assert.Empty(actions);
1115+
}
1116+
}
10831117
}
10841118
}

src/EditorFeatures/TestUtilities/MoveToNamespace/AbstractMoveToNamespaceTests.TestState.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public void Dispose()
2727
public Document InvocationDocument => Workspace.CurrentSolution.GetDocument(TestInvocationDocument.Id);
2828

2929
public TestMoveToNamespaceOptionsService TestMoveToNamespaceOptionsService
30-
=> (TestMoveToNamespaceOptionsService)Workspace.Services.GetService<IMoveToNamespaceOptionsService>();
30+
=> (TestMoveToNamespaceOptionsService)MoveToNamespaceService.OptionsService;
3131

3232
public IMoveToNamespaceService MoveToNamespaceService
3333
=> InvocationDocument.GetLanguageService<IMoveToNamespaceService>();

src/EditorFeatures/TestUtilities/MoveToNamespace/TestMoveToNamespaceOptionsService.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
2-
using System;
32
using System.Collections.Immutable;
43
using Microsoft.CodeAnalysis.LanguageServices;
54
using Microsoft.CodeAnalysis.MoveToNamespace;
6-
using Microsoft.CodeAnalysis.Host.Mef;
75
using System.Composition;
86

97
namespace Microsoft.CodeAnalysis.Test.Utilities.MoveToNamespace
108
{
11-
[ExportWorkspaceService(typeof(IMoveToNamespaceOptionsService)), Shared]
9+
[Export(typeof(IMoveToNamespaceOptionsService)), Shared]
10+
[PartNotDiscoverable]
1211
class TestMoveToNamespaceOptionsService : IMoveToNamespaceOptionsService
1312
{
1413
internal static readonly MoveToNamespaceOptionsResult DefaultOptions = new MoveToNamespaceOptionsResult("TestNewNamespaceValue");

src/Features/CSharp/Portable/MoveToNamespace/CSharpMoveToNamespaceService.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ internal class CSharpMoveToNamespaceService :
1313
AbstractMoveToNamespaceService<NamespaceDeclarationSyntax, TypeDeclarationSyntax>
1414
{
1515
[ImportingConstructor]
16-
public CSharpMoveToNamespaceService()
16+
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
17+
public CSharpMoveToNamespaceService(
18+
[Import(AllowDefault = true)] IMoveToNamespaceOptionsService optionsService)
19+
: base(optionsService)
1720
{
1821
}
1922

src/Features/Core/Portable/MoveToNamespace/AbstractMoveToNamespaceService.cs

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
using Microsoft.CodeAnalysis.Shared.Extensions;
1313
using Microsoft.CodeAnalysis.Text;
1414
using Microsoft.CodeAnalysis.LanguageServices;
15-
using System.Text;
1615
using System.Diagnostics;
1716

1817
namespace Microsoft.CodeAnalysis.MoveToNamespace
@@ -23,6 +22,7 @@ internal interface IMoveToNamespaceService : ILanguageService
2322
Task<MoveToNamespaceAnalysisResult> AnalyzeTypeAtPositionAsync(Document document, int position, CancellationToken cancellationToken);
2423
Task<MoveToNamespaceResult> MoveToNamespaceAsync(MoveToNamespaceAnalysisResult analysisResult, string targetNamespace, CancellationToken cancellationToken);
2524
MoveToNamespaceOptionsResult GetChangeNamespaceOptions(Document document, string defaultNamespace, ImmutableArray<string> namespaces);
25+
IMoveToNamespaceOptionsService OptionsService { get; }
2626
}
2727

2828
internal abstract class AbstractMoveToNamespaceService<TNamespaceDeclarationSyntax, TNamedTypeDeclarationSyntax>
@@ -35,16 +35,28 @@ internal abstract class AbstractMoveToNamespaceService<TNamespaceDeclarationSynt
3535
protected abstract string GetNamespaceName(TNamedTypeDeclarationSyntax namedTypeSyntax);
3636
protected abstract bool IsContainedInNamespaceDeclaration(TNamespaceDeclarationSyntax namespaceSyntax, int position);
3737

38+
public IMoveToNamespaceOptionsService OptionsService { get; }
39+
40+
protected AbstractMoveToNamespaceService(IMoveToNamespaceOptionsService moveToNamespaceOptionsService)
41+
{
42+
OptionsService = moveToNamespaceOptionsService;
43+
}
44+
3845
public async Task<ImmutableArray<AbstractMoveToNamespaceCodeAction>> GetCodeActionsAsync(
3946
Document document,
4047
TextSpan span,
4148
CancellationToken cancellationToken)
4249
{
43-
var typeAnalysisResult = await AnalyzeTypeAtPositionAsync(document, span.Start, cancellationToken).ConfigureAwait(false);
44-
45-
if (typeAnalysisResult.CanPerform)
50+
// Code actions cannot be completed without the options needed
51+
// to fill in missing information.
52+
if (OptionsService != null)
4653
{
47-
return ImmutableArray.Create(AbstractMoveToNamespaceCodeAction.Generate(this, typeAnalysisResult));
54+
var typeAnalysisResult = await AnalyzeTypeAtPositionAsync(document, span.Start, cancellationToken).ConfigureAwait(false);
55+
56+
if (typeAnalysisResult.CanPerform)
57+
{
58+
return ImmutableArray.Create(AbstractMoveToNamespaceCodeAction.Generate(this, typeAnalysisResult));
59+
}
4860
}
4961

5062
return ImmutableArray<AbstractMoveToNamespaceCodeAction>.Empty;
@@ -237,14 +249,8 @@ public MoveToNamespaceOptionsResult GetChangeNamespaceOptions(
237249
ImmutableArray<string> namespaces)
238250
{
239251
var syntaxFactsService = document.GetLanguageService<ISyntaxFactsService>();
240-
var moveToNamespaceOptionsService = document.Project.Solution.Workspace.Services.GetService<IMoveToNamespaceOptionsService>();
241-
242-
if (moveToNamespaceOptionsService == null)
243-
{
244-
return MoveToNamespaceOptionsResult.Cancelled;
245-
}
246252

247-
return moveToNamespaceOptionsService.GetChangeNamespaceOptions(
253+
return OptionsService.GetChangeNamespaceOptions(
248254
defaultNamespace,
249255
namespaces,
250256
syntaxFactsService);

src/Features/Core/Portable/MoveToNamespace/MoveToNamespaceCodeActionProvider.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ public MoveToNamespaceCodeActionProvider()
1919

2020
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
2121
{
22-
var service = context.Document.GetLanguageService<IMoveToNamespaceService>();
23-
var actions = await service.GetCodeActionsAsync(context.Document, context.Span, context.CancellationToken).ConfigureAwait(false);
22+
var moveToNamespaceService = context.Document.GetLanguageService<IMoveToNamespaceService>();
23+
var actions = await moveToNamespaceService.GetCodeActionsAsync(context.Document, context.Span, context.CancellationToken).ConfigureAwait(false);
2424
context.RegisterRefactorings(actions);
2525
}
2626
}

src/VisualStudio/Core/Def/Implementation/MoveToNamespace/VisualStudioMoveToNamespaceOptionsService.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,12 @@
22

33
using System.Collections.Immutable;
44
using System.Composition;
5-
using Microsoft.CodeAnalysis.Host.Mef;
65
using Microsoft.CodeAnalysis.LanguageServices;
76
using Microsoft.CodeAnalysis.MoveToNamespace;
87

98
namespace Microsoft.VisualStudio.LanguageServices.Implementation.MoveToNamespace
109
{
11-
[ExportWorkspaceService(typeof(IMoveToNamespaceOptionsService), layer: ServiceLayer.Host), Shared]
10+
[Export(typeof(IMoveToNamespaceOptionsService)), Shared]
1211
internal class VisualStudioMoveToNamespaceOptionsService : IMoveToNamespaceOptionsService
1312
{
1413
[ImportingConstructor]

0 commit comments

Comments
 (0)