Skip to content

Commit

Permalink
Merge pull request #1672 from OmniSharp/feature/implement-type-options
Browse files Browse the repository at this point in the history
added implement type options
  • Loading branch information
bjorkstromm authored Jan 9, 2020
2 parents 6754728 + 435e96a commit dcb36c7
Show file tree
Hide file tree
Showing 4 changed files with 210 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using System;
using System.Composition;
using System.Reflection;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Options;
using OmniSharp.Options;
using OmniSharp.Roslyn.Options;
using OmniSharp.Services;
using OmniSharp.Utilities;

namespace OmniSharp.Roslyn.CSharp.Services
{
[Export(typeof(IWorkspaceOptionsProvider)), Shared]
public class ImplementTypeWorkspaceOptionsProvider : IWorkspaceOptionsProvider
{
private readonly IAssemblyLoader _assemblyLoader;
private readonly Lazy<Assembly> _csharpFeatureAssembly;
private readonly Lazy<Type> _implementTypeOptions;

[ImportingConstructor]
public ImplementTypeWorkspaceOptionsProvider(IAssemblyLoader assemblyLoader)
{
_assemblyLoader = assemblyLoader;
_csharpFeatureAssembly = _assemblyLoader.LazyLoad(Configuration.RoslynFeatures);
_implementTypeOptions = _csharpFeatureAssembly.LazyGetType("Microsoft.CodeAnalysis.ImplementType.ImplementTypeOptions");
}

public int Order => 110;

public OptionSet Process(OptionSet currentOptionSet, OmniSharpOptions omniSharpOptions, IOmniSharpEnvironment omnisharpEnvironment)
{
if (omniSharpOptions.ImplementTypeOptions.InsertionBehavior != null)
{
if (_implementTypeOptions.Value.GetField("InsertionBehavior", BindingFlags.Public | BindingFlags.Static)?.GetValue(null) is IOption insertionBehaviorOptionValue)
{
currentOptionSet = currentOptionSet.WithChangedOption(new OptionKey(insertionBehaviorOptionValue, LanguageNames.CSharp), (int)omniSharpOptions.ImplementTypeOptions.InsertionBehavior);
}
}

if (omniSharpOptions.ImplementTypeOptions.PropertyGenerationBehavior != null)
{
if (_implementTypeOptions.Value.GetField("PropertyGenerationBehavior", BindingFlags.Public | BindingFlags.Static)?.GetValue(null) is IOption propertyGenerationBehaviorOptionValue)
{
currentOptionSet = currentOptionSet.WithChangedOption(new OptionKey(propertyGenerationBehaviorOptionValue, LanguageNames.CSharp), (int)omniSharpOptions.ImplementTypeOptions.PropertyGenerationBehavior);
}
}

return currentOptionSet;
}
}
}
20 changes: 20 additions & 0 deletions src/OmniSharp.Shared/Options/ImplementTypeOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
namespace OmniSharp.Options
{
public class ImplementTypeOptions
{
public ImplementTypeInsertionBehavior? InsertionBehavior { get; set; }
public ImplementTypePropertyGenerationBehavior? PropertyGenerationBehavior { get; set; }
}

public enum ImplementTypeInsertionBehavior
{
WithOtherMembersOfTheSameKind = 0,
AtTheEnd = 1,
}

public enum ImplementTypePropertyGenerationBehavior
{
PreferThrowingProperties = 0,
PreferAutoProperties = 1,
}
}
2 changes: 2 additions & 0 deletions src/OmniSharp.Shared/Options/OmniSharpOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ public class OmniSharpOptions

public RenameOptions RenameOptions { get; set; } = new RenameOptions();

public ImplementTypeOptions ImplementTypeOptions { get; set; } = new ImplementTypeOptions();

public OmniSharpExtensionsOptions Plugins { get; set; } = new OmniSharpExtensionsOptions();
}
}
137 changes: 137 additions & 0 deletions tests/OmniSharp.Roslyn.CSharp.Tests/ImplementTypeFacts.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using OmniSharp.Models;
using OmniSharp.Models.V2.CodeActions;
using OmniSharp.Roslyn.CSharp.Services.Refactoring.V2;
using TestUtility;
using Xunit;
using Xunit.Abstractions;

namespace OmniSharp.Roslyn.CSharp.Tests
{
public class ImplementTypeFacts : AbstractCodeActionsTestFixture
{
public ImplementTypeFacts(ITestOutputHelper output)
: base(output)
{
}

[Theory]
[InlineData("PreferAutoProperties", "public string Name { get; set; }")]
[InlineData("PreferThrowingProperties", "public string Name { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); }")]
[InlineData(null, "public string Name { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); }")]
public async Task ImplementInterface_PropertyGeneration(string implementTypePropertyGenerationBehavior, string expectedChange)
{
const string code = @"
interface IFoo
{
string Name { get; set; }
}
class Foo : I$$Foo
{
}";

var hostProperties = implementTypePropertyGenerationBehavior != null ? new Dictionary<string, string>
{
["ImplementTypeOptions:PropertyGenerationBehavior"] = implementTypePropertyGenerationBehavior
} : null;
await VerifyImplementType(code, expectedChange, hostProperties);
}

[Fact]
public async Task ImplementInterface_Insertion_AtTheEnd()
{
const string code = @"
public interface IFoo
{
string Name { get; set; }
void Do();
string Name2 { get; set; }
}
public class Foo : I$$Foo
{
}";

const string expectedChange = @"
public string Name { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); }
public void Do()
{
throw new System.NotImplementedException();
}
public string Name2 { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); }
";

await VerifyImplementType(code, expectedChange, new Dictionary<string, string>
{
["ImplementTypeOptions:InsertionBehavior"] = "AtTheEnd"
});
}

[Theory]
[InlineData("WithOtherMembersOfTheSameKind")]
[InlineData(null)]
public async Task ImplementInterface_Insertion_WithOtherMembersOfTheSameKind(string implementTypeInsertionBehavior)
{
const string code = @"
public interface IFoo
{
string Name { get; set; }
void Do();
string Name2 { get; set; }
}
public class Foo : I$$Foo
{
}";

const string expectedChange = @"
public string Name { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); }
public string Name2 { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); }
public void Do()
{
throw new System.NotImplementedException();
}
";

var hostProperties = implementTypeInsertionBehavior != null ? new Dictionary<string, string>
{
["ImplementTypeOptions:InsertionBehavior"] = implementTypeInsertionBehavior
} : null;
await VerifyImplementType(code, expectedChange, hostProperties);
}

private async Task VerifyImplementType(string code, string expectedChange, Dictionary<string, string> hostProperties)
{
var testFile = new TestFile("test.cs", code);
using (var host = CreateOmniSharpHost(new[] { testFile }, hostProperties))
{
var requestHandler = host.GetRequestHandler<RunCodeActionService>(OmniSharpEndpoints.V2.RunCodeAction);
var point = testFile.Content.GetPointFromPosition();

var request = new RunCodeActionRequest
{
Line = point.Line,
Column = point.Offset,
FileName = testFile.FileName,
Buffer = testFile.Content.Code,
Identifier = "False;False;AssemblyName;global::IFoo;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction",
WantsTextChanges = true,
WantsAllCodeActionOperations = true
};

var response = await requestHandler.Handle(request);
var changes = response.Changes.ToArray();

Assert.Single(changes);
Assert.NotNull(changes[0].FileName);
AssertIgnoringIndent(expectedChange, ((ModifiedFileResponse)changes[0]).Changes.First().NewText);
}
}
}
}

0 comments on commit dcb36c7

Please sign in to comment.