-
Notifications
You must be signed in to change notification settings - Fork 418
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Codeactions with options/ui. #1406
Changes from 18 commits
eea9dfc
cbf1877
70d3dc9
9d95a01
84224b5
5437959
761f657
274e3c7
ca9ecb3
a7c21ff
8a298e5
c773575
f17aeeb
9dd4cef
2a199b1
fca2bb4
17eb6d9
ac93122
4659787
596cbe6
5690dc1
401e66e
4a65088
9efd76d
f1a6061
a06b47b
f136bf1
a04812a
0332ef6
1f47071
e60dc68
1aeab24
963c708
515f691
c6a3683
57543fc
2afb64a
9949e56
1138ac8
79e0390
7099e22
26aaac9
9b9ac63
0471c2e
dab7a8c
03c31f6
a463572
bbc31ad
2c13068
90c7d93
fbf7d36
49c01c1
281ad00
22e1789
672a012
c8085c0
67277c1
01a5aca
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,6 +16,7 @@ | |
<PackageReference Include="Microsoft.Extensions.Caching.Memory" /> | ||
<PackageReference Include="Microsoft.CodeAnalysis.Common" /> | ||
<PackageReference Include="System.ComponentModel.Composition" /> | ||
<PackageReference Include="Castle.Core" Version="4.3.1" /> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We probably want to avoid a dependency for Castle.Core? |
||
</ItemGroup> | ||
|
||
</Project> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
using System; | ||
using System.Composition; | ||
using System.Reflection; | ||
using Microsoft.CodeAnalysis.Host.Mef; | ||
|
||
namespace OmniSharp | ||
{ | ||
[MetadataAttribute] | ||
[AttributeUsage(AttributeTargets.Class)] | ||
public class ExportWorkspaceServiceFactoryWithAssemblyQualifiedNameAttribute : ExportAttribute | ||
{ | ||
public string ServiceType { get; } | ||
public string Layer { get; } | ||
|
||
// Theres builtin public attribute for this, but since we target internal types | ||
// this is needed to build service. MEF doesn't care is it internal or not. | ||
public ExportWorkspaceServiceFactoryWithAssemblyQualifiedNameAttribute(string typeAssembly, string typeName, string layer = ServiceLayer.Host) | ||
: base(typeof(IWorkspaceServiceFactory)) | ||
{ | ||
var type = Assembly.Load(typeAssembly).GetType(typeName) | ||
?? throw new InvalidOperationException($"Could not resolve '{typeName} from '{typeAssembly}'"); | ||
|
||
Console.WriteLine($"Resolved to type: {type.AssemblyQualifiedName}"); | ||
this.ServiceType = type.AssemblyQualifiedName; | ||
this.Layer = layer ?? throw new ArgumentNullException(nameof(layer)); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Collections.Immutable; | ||
using System.Linq; | ||
using System.Reflection; | ||
using System.Threading.Tasks; | ||
using Castle.DynamicProxy; | ||
using Microsoft.CodeAnalysis; | ||
|
||
namespace OmniSharp | ||
{ | ||
public class ExtractInterfaceWorkspaceService : IInterceptor | ||
{ | ||
public void Intercept(IInvocation invocation) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To avoid a dependency on Castle.Core, you can have a look in MetadataHelper on how this could be done. |
||
{ | ||
// IExtractInterfaceOptionsService and extract interface results are internal types -> workaround with proxy. | ||
// This service simply passes all members through as selected and doesn't try show UI. | ||
// When roslyn exposes this interface and members -> remove this workaround. | ||
|
||
var resultTypeInternal = Assembly.Load("Microsoft.CodeAnalysis.Features").GetType("Microsoft.CodeAnalysis.ExtractInterface.ExtractInterfaceOptionsResult"); | ||
var enumType = resultTypeInternal.GetNestedTypes().Single(x => x.Name == "ExtractLocation"); | ||
|
||
var toSameFileEnumValue = Enum.Parse(enumType, "SameFile"); | ||
|
||
var interfaceName = invocation.Arguments[3] ?? throw new InvalidOperationException($"{nameof(ExtractInterfaceWorkspaceService)} default interface name was null."); | ||
|
||
var resultObject = Activator.CreateInstance(resultTypeInternal, new object[] { | ||
false, // isCancelled | ||
((List<ISymbol>)invocation.Arguments[2]).ToImmutableArray(), // InterfaceMembers selected -> select all. | ||
interfaceName, | ||
$"{interfaceName}.cs", | ||
toSameFileEnumValue | ||
}); | ||
|
||
var fromResultMethod = typeof(Task).GetMethod("FromResult").MakeGenericMethod(resultTypeInternal).Invoke(null, new[] { resultObject }); | ||
invocation.ReturnValue = fromResultMethod; | ||
} | ||
|
||
private static Type MakeGenerictTaskTypeFromResult(Type resultTypeInternal) | ||
{ | ||
var taskType = typeof(Task<>); | ||
Type[] typeArgs = { resultTypeInternal }; | ||
var taskGenericType = taskType.MakeGenericType(typeArgs); | ||
return taskGenericType; | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
using System.Composition; | ||
using System.Reflection; | ||
using Castle.DynamicProxy; | ||
using Microsoft.CodeAnalysis.Host; | ||
using Microsoft.CodeAnalysis.Host.Mef; | ||
|
||
namespace OmniSharp | ||
{ | ||
[Shared] | ||
[ExportWorkspaceServiceFactoryWithAssemblyQualifiedName("Microsoft.CodeAnalysis.Features", "Microsoft.CodeAnalysis.ExtractInterface.IExtractInterfaceOptionsService")] | ||
public class ExtractInterfaceWorkspaceServiceFactory : IWorkspaceServiceFactory | ||
{ | ||
public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) | ||
{ | ||
// Generates proxy class to get around issue that IExtractInterfaceOptionsService is internal at this point. | ||
ProxyGenerator generator = new ProxyGenerator(); | ||
var internalType = Assembly.Load("Microsoft.CodeAnalysis.Features").GetType("Microsoft.CodeAnalysis.ExtractInterface.IExtractInterfaceOptionsService"); | ||
return (IWorkspaceService)generator.CreateInterfaceProxyWithoutTarget(internalType, new[] { typeof(IWorkspaceService)}, new ExtractInterfaceWorkspaceService()); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
using System; | ||
using System.Reflection; | ||
using Castle.DynamicProxy; | ||
|
||
namespace OmniSharp | ||
{ | ||
public class PickMemberWorkspaceService : IInterceptor | ||
{ | ||
public void Intercept(IInvocation invocation) | ||
{ | ||
// IPickMember and PickMemberResults are internal types -> workaround with proxy. | ||
// This service simply passes all members through as selected and doesn't try show UI. | ||
// When roslyn exposes this interface and members -> remove this workaround. | ||
var resultTypeInternal = Assembly.Load("Microsoft.CodeAnalysis.Features").GetType("Microsoft.CodeAnalysis.PickMembers.PickMembersResult"); | ||
var resultInstance = Activator.CreateInstance(resultTypeInternal, new object[] { invocation.Arguments[1], invocation.Arguments[2] }); | ||
invocation.ReturnValue = resultInstance; | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
using System.Composition; | ||
using System.Reflection; | ||
using Castle.DynamicProxy; | ||
using Microsoft.CodeAnalysis.Host; | ||
using Microsoft.CodeAnalysis.Host.Mef; | ||
|
||
namespace OmniSharp | ||
{ | ||
[Shared] | ||
[ExportWorkspaceServiceFactoryWithAssemblyQualifiedName("Microsoft.CodeAnalysis.Features", "Microsoft.CodeAnalysis.PickMembers.IPickMembersService")] | ||
public class PickMemberWorkspaceServiceFactory : IWorkspaceServiceFactory | ||
{ | ||
public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) | ||
{ | ||
// Generates proxy class to get around issue that IPickMembersService is internal at this point. | ||
ProxyGenerator generator = new ProxyGenerator(); | ||
var internalType = Assembly.Load("Microsoft.CodeAnalysis.Features").GetType("Microsoft.CodeAnalysis.PickMembers.IPickMembersService"); | ||
return (IWorkspaceService)generator.CreateInterfaceProxyWithoutTarget(internalType, new[] { typeof(IWorkspaceService)}, new PickMemberWorkspaceService()); | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's do the blacklisting based on the original Roslyn type name instead of the title text