-
Notifications
You must be signed in to change notification settings - Fork 420
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
Order code actions #1078
Order code actions #1078
Changes from 11 commits
4dabba9
653e4be
82c3a2c
14b1499
2fb5746
2e2b5c7
b8eefcf
751051c
20d35af
0467d17
81b0935
b1a92b6
9a7fb14
d83bb8d
7ba0db9
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 |
---|---|---|
@@ -0,0 +1,85 @@ | ||
// Adapted from ExtensionOrderer in Roslyn | ||
using System.Collections.Generic; | ||
|
||
namespace OmniSharp.Roslyn.CSharp.Services.Refactoring.V2 | ||
{ | ||
internal class Graph<T> | ||
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. Is this adapted from Roslyn? 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. Yes, this is taken from Extension Orderer used by Roslyn and modified a bit for the current case. 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. Ok, we might want to add a comment stating as such. 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. @DustinCampbell can we get that API opened up publicly? 😀 |
||
{ | ||
//Dictionary to map between nodes and the names | ||
private Dictionary<string, ProviderNode<T>> Nodes { get; } | ||
private List<ProviderNode<T>> AllNodes { get; } | ||
private Graph(List<ProviderNode<T>> nodesList) | ||
{ | ||
Nodes = new Dictionary<string, ProviderNode<T>>(); | ||
AllNodes = nodesList; | ||
} | ||
internal static Graph<T> GetGraph(List<ProviderNode<T>> nodesList) | ||
{ | ||
var graph = new Graph<T>(nodesList); | ||
|
||
foreach (ProviderNode<T> node in graph.AllNodes) | ||
{ | ||
graph.Nodes[node.ProviderName] = node; | ||
} | ||
|
||
foreach (ProviderNode<T> node in graph.AllNodes) | ||
{ | ||
foreach (var before in node.Before) | ||
{ | ||
if (graph.Nodes.ContainsKey(before)) | ||
{ | ||
var beforeNode = graph.Nodes[before]; | ||
beforeNode.NodesBeforeMeSet.Add(node); | ||
} | ||
} | ||
|
||
foreach (var after in node.After) | ||
{ | ||
if (graph.Nodes.ContainsKey(after)) | ||
{ | ||
var afterNode = graph.Nodes[after]; | ||
node.NodesBeforeMeSet.Add(afterNode); | ||
} | ||
} | ||
} | ||
|
||
return graph; | ||
} | ||
|
||
public bool HasCycles() | ||
{ | ||
foreach (var node in this.AllNodes) | ||
{ | ||
if (node.CheckForCycles()) | ||
return true; | ||
} | ||
return false; | ||
} | ||
|
||
public List<T> TopologicalSort() | ||
{ | ||
List<T> result = new List<T>(); | ||
var seenNodes = new HashSet<ProviderNode<T>>(); | ||
|
||
foreach (var node in AllNodes) | ||
{ | ||
Visit(node, result, seenNodes); | ||
} | ||
|
||
return result; | ||
} | ||
|
||
private void Visit(ProviderNode<T> node, List<T> result, HashSet<ProviderNode<T>> seenNodes) | ||
{ | ||
if (seenNodes.Add(node)) | ||
{ | ||
foreach (var before in node.NodesBeforeMeSet) | ||
{ | ||
Visit(before, result, seenNodes); | ||
} | ||
|
||
result.Add(node.Provider); | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
// Adapted from ExtensionOrderer in Roslyn | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Reflection; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.CodeFixes; | ||
|
||
namespace OmniSharp.Roslyn.CSharp.Services.Refactoring.V2 | ||
{ | ||
internal class ProviderNode<T> | ||
{ | ||
public string ProviderName { get; set; } | ||
public List<string> Before { get; set; } | ||
public List<string> After { get; set; } | ||
public T Provider { get; set; } | ||
public HashSet<ProviderNode<T>> NodesBeforeMeSet { get; set; } | ||
|
||
public static ProviderNode<T> From(T provider) | ||
{ | ||
var exportAttribute = provider.GetType().GetCustomAttribute(typeof(ExportCodeFixProviderAttribute)); | ||
string providerName = ""; | ||
if (exportAttribute is ExportCodeFixProviderAttribute && ((ExportCodeFixProviderAttribute)exportAttribute).Name != null) | ||
{ | ||
providerName = ((ExportCodeFixProviderAttribute)exportAttribute).Name; | ||
} | ||
|
||
var orderAttributes = provider.GetType().GetCustomAttributes(typeof(ExtensionOrderAttribute), true).Select(attr => (ExtensionOrderAttribute)attr).ToList(); | ||
return new ProviderNode<T>(provider, providerName, orderAttributes); | ||
} | ||
|
||
private ProviderNode(T provider, string providerName, List<ExtensionOrderAttribute> orderAttributes) | ||
{ | ||
Provider = provider; | ||
ProviderName = providerName; | ||
Before = new List<string>(); | ||
After = new List<string>(); | ||
NodesBeforeMeSet = new HashSet<ProviderNode<T>>(); | ||
orderAttributes.ForEach(attr => AddAttribute(attr)); | ||
} | ||
|
||
private void AddAttribute(ExtensionOrderAttribute attribute) | ||
{ | ||
if (attribute.Before != null) | ||
Before.Add(attribute.Before); | ||
if (attribute.After != null) | ||
After.Add(attribute.After); | ||
} | ||
|
||
internal bool CheckForCycles() | ||
{ | ||
return CheckForCycles(new HashSet<ProviderNode<T>>()); | ||
} | ||
|
||
private bool CheckForCycles(HashSet<ProviderNode<T>> seenNodes) | ||
{ | ||
if (!seenNodes.Add(this)) | ||
{ | ||
//Cycle detected | ||
return true; | ||
} | ||
|
||
foreach (var before in this.NodesBeforeMeSet) | ||
{ | ||
if (before.CheckForCycles(seenNodes)) | ||
return true; | ||
} | ||
|
||
seenNodes.Remove(this); | ||
return false; | ||
} | ||
} | ||
} |
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.
Can we cache this? (Eg, does the total set of CodeFixProviders change)