提交 21c8e2fa 编写于 作者: J Jason Malinowski

Nullable annotate our extension ordering code and delete IOrderableMetadata

I expect that IOrderableMetadata existed back from a time where we
were working with both MEFv1 interface metadata views and MEFv2
concrete type views. Nothing today needs it anymore, so we can just
delete it.
上级 f3ff7201
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
namespace Microsoft.CodeAnalysis
{
/// <summary>
/// This interface exists purely to enable some shared code that operates over orderable metadata.
/// This interface should not be used directly with MEF, used OrderableMetadata instead.
/// </summary>
internal interface IOrderableMetadata
{
IEnumerable<string> After { get; }
IEnumerable<string> Before { get; }
string Name { get; }
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#nullable enable
using System.Collections.Generic;
using System.ComponentModel;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis
{
internal class OrderableMetadata : IOrderableMetadata
internal class OrderableMetadata
{
[DefaultValue(new string[] { })]
public object After { get; }
public object? After { get; }
[DefaultValue(new string[] { })]
public object Before { get; }
public object? Before { get; }
internal IEnumerable<string> AfterTyped { get; set; }
internal IEnumerable<string> BeforeTyped { get; set; }
public string Name { get; }
IEnumerable<string> IOrderableMetadata.After => AfterTyped;
IEnumerable<string> IOrderableMetadata.Before => BeforeTyped;
public string? Name { get; }
public OrderableMetadata(IDictionary<string, object> data)
{
var readOnlyData = (IReadOnlyDictionary<string, object>)data;
this.AfterTyped = readOnlyData.GetEnumerableMetadata<string>("After").WhereNotNull();
this.BeforeTyped = readOnlyData.GetEnumerableMetadata<string>("Before").WhereNotNull();
this.Name = (string)data.GetValueOrDefault("Name");
this.Name = (string?)data.GetValueOrDefault("Name");
}
public OrderableMetadata(string name, IEnumerable<string> after = null, IEnumerable<string> before = null)
public OrderableMetadata(string? name, IEnumerable<string>? after = null, IEnumerable<string>? before = null)
{
this.AfterTyped = after ?? SpecializedCollections.EmptyEnumerable<string>();
this.BeforeTyped = before ?? SpecializedCollections.EmptyEnumerable<string>();
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Shared.Utilities
{
internal partial class ExtensionOrderer
{
private class Graph<TExtension, TMetadata>
where TMetadata : IOrderableMetadata
where TMetadata : OrderableMetadata
{
public readonly Dictionary<Lazy<TExtension, TMetadata>, Node<TExtension, TMetadata>> Nodes =
new Dictionary<Lazy<TExtension, TMetadata>, Node<TExtension, TMetadata>>();
public IEnumerable<Lazy<TExtension, TMetadata>> FindExtensions(string name)
{
Contract.ThrowIfNull(name);
return this.Nodes.Keys.Where(k => k.Metadata.Name == name);
}
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Shared.Utilities
{
......@@ -11,7 +12,7 @@ internal static partial class ExtensionOrderer
{
internal static IList<Lazy<TExtension, TMetadata>> Order<TExtension, TMetadata>(
IEnumerable<Lazy<TExtension, TMetadata>> extensions)
where TMetadata : IOrderableMetadata
where TMetadata : OrderableMetadata
{
var graph = GetGraph(extensions);
return graph.TopologicalSort();
......@@ -19,7 +20,7 @@ internal static partial class ExtensionOrderer
private static Graph<TExtension, TMetadata> GetGraph<TExtension, TMetadata>(
IEnumerable<Lazy<TExtension, TMetadata>> extensions)
where TMetadata : IOrderableMetadata
where TMetadata : OrderableMetadata
{
var list = extensions.ToList();
var graph = new Graph<TExtension, TMetadata>();
......@@ -32,7 +33,7 @@ internal static partial class ExtensionOrderer
foreach (var extension in list)
{
var extensionNode = graph.Nodes[extension];
foreach (var before in Before(extension))
foreach (var before in extension.Metadata.BeforeTyped)
{
foreach (var beforeExtension in graph.FindExtensions(before))
{
......@@ -41,7 +42,7 @@ internal static partial class ExtensionOrderer
}
}
foreach (var after in After(extension))
foreach (var after in extension.Metadata.AfterTyped)
{
foreach (var afterExtension in graph.FindExtensions(after))
{
......@@ -54,18 +55,6 @@ internal static partial class ExtensionOrderer
return graph;
}
private static IEnumerable<string> Before<TExtension, TMetadata>(Lazy<TExtension, TMetadata> extension)
where TMetadata : IOrderableMetadata
{
return extension.Metadata.Before ?? SpecializedCollections.EmptyEnumerable<string>();
}
private static IEnumerable<string> After<TExtension, TMetadata>(Lazy<TExtension, TMetadata> extension)
where TMetadata : IOrderableMetadata
{
return extension.Metadata.After ?? SpecializedCollections.EmptyEnumerable<string>();
}
internal static class TestAccessor
{
/// <summary>
......@@ -75,7 +64,7 @@ internal static class TestAccessor
/// <exception cref="ArgumentException">A cycle was detected in the extension ordering.</exception>
internal static void CheckForCycles<TExtension, TMetadata>(
IEnumerable<Lazy<TExtension, TMetadata>> extensions)
where TMetadata : IOrderableMetadata
where TMetadata : OrderableMetadata
{
var graph = GetGraph(extensions);
graph.CheckForCycles();
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
......@@ -9,24 +11,10 @@
namespace Microsoft.CodeAnalysis.UnitTests
{
public class ExtensionOrdererTests : TestBase
public class ExtensionOrdererTests
{
private class Extension { }
private class ExtensionMetadata : IOrderableMetadata
{
public string Name { get; }
public IEnumerable<string> Before { get; }
public IEnumerable<string> After { get; }
public ExtensionMetadata(string name = null, IEnumerable<string> before = null, IEnumerable<string> after = null)
{
this.Name = name;
this.Before = before;
this.After = after;
}
}
[Fact]
public void TestNoCycle1()
{
......@@ -36,7 +24,7 @@ public void TestNoCycle1()
var d = CreateExtension(name: "d", before: new[] { "e" });
var e = CreateExtension(name: "e");
var extensions = new List<Lazy<Extension, ExtensionMetadata>>() { d, b, a, c, e };
var extensions = new List<Lazy<Extension, OrderableMetadata>>() { d, b, a, c, e };
// ExtensionOrderer.TestAccessor.CheckForCycles() will throw ArgumentException if cycle is detected.
ExtensionOrderer.TestAccessor.CheckForCycles(extensions);
......@@ -53,7 +41,7 @@ public void TestNoCycle2()
var d = CreateExtension(name: "d", after: new[] { "e" });
var e = CreateExtension(name: "e");
var extensions = new List<Lazy<Extension, ExtensionMetadata>>() { d, b, a, c, e };
var extensions = new List<Lazy<Extension, OrderableMetadata>>() { d, b, a, c, e };
// ExtensionOrderer.TestAccessor.CheckForCycles() will throw ArgumentException if cycle is detected.
ExtensionOrderer.TestAccessor.CheckForCycles(extensions);
......@@ -70,7 +58,7 @@ public void TestNoCycle3()
var d = CreateExtension(name: "d", before: new[] { "e" }, after: new[] { "c", "b", "a" });
var e = CreateExtension(name: "e", after: new[] { "d", "c", "b", "a" });
var extensions = new List<Lazy<Extension, ExtensionMetadata>>() { d, b, a, c, e };
var extensions = new List<Lazy<Extension, OrderableMetadata>>() { d, b, a, c, e };
// ExtensionOrderer.TestAccessor.CheckForCycles() will throw ArgumentException if cycle is detected.
ExtensionOrderer.TestAccessor.CheckForCycles(extensions);
......@@ -87,7 +75,7 @@ public void TestCycle1()
var d = CreateExtension(name: "d", before: new[] { "e" });
var e = CreateExtension(name: "e", before: new[] { "a" });
var extensions = new List<Lazy<Extension, ExtensionMetadata>>() { a, b, c, d, e };
var extensions = new List<Lazy<Extension, OrderableMetadata>>() { a, b, c, d, e };
// ExtensionOrderer.TestAccessor.CheckForCycles() will throw ArgumentException when cycle is detected.
Assert.Throws<ArgumentException>(() => ExtensionOrderer.TestAccessor.CheckForCycles(extensions));
......@@ -104,7 +92,7 @@ public void TestCycle2()
var d = CreateExtension(name: "d", after: new[] { "e" });
var e = CreateExtension(name: "e", after: new[] { "a" });
var extensions = new List<Lazy<Extension, ExtensionMetadata>>() { a, b, c, d, e };
var extensions = new List<Lazy<Extension, OrderableMetadata>>() { a, b, c, d, e };
// ExtensionOrderer.TestAccessor.CheckForCycles() will throw ArgumentException when cycle is detected.
Assert.Throws<ArgumentException>(() => ExtensionOrderer.TestAccessor.CheckForCycles(extensions));
......@@ -119,7 +107,7 @@ public void TestCycle3()
var b = CreateExtension(name: "b", before: new[] { "a" }, after: new[] { "a" });
var c = CreateExtension(name: "c");
var extensions = new List<Lazy<Extension, ExtensionMetadata>>() { a, b, c };
var extensions = new List<Lazy<Extension, OrderableMetadata>>() { a, b, c };
// ExtensionOrderer.TestAccessor.CheckForCycles() will throw ArgumentException when cycle is detected.
Assert.Throws<ArgumentException>(() => ExtensionOrderer.TestAccessor.CheckForCycles(extensions));
......@@ -134,7 +122,7 @@ public void TestCycle4()
var b = CreateExtension(name: "b", before: new[] { "b" }, after: new[] { "b" });
var c = CreateExtension(name: "c");
var extensions = new List<Lazy<Extension, ExtensionMetadata>>() { a, b, c };
var extensions = new List<Lazy<Extension, OrderableMetadata>>() { a, b, c };
// ExtensionOrderer.TestAccessor.CheckForCycles() will throw ArgumentException when cycle is detected.
Assert.Throws<ArgumentException>(() => ExtensionOrderer.TestAccessor.CheckForCycles(extensions));
......@@ -153,7 +141,7 @@ public void TestCycle5()
var f = CreateExtension(name: "f", before: new[] { "g" });
var g = CreateExtension(name: "g");
var extensions = new List<Lazy<Extension, ExtensionMetadata>>() { a, b, c, d, e, f, g };
var extensions = new List<Lazy<Extension, OrderableMetadata>>() { a, b, c, d, e, f, g };
// ExtensionOrderer.TestAccessor.CheckForCycles() will throw ArgumentException when cycle is detected.
Assert.Throws<ArgumentException>(() => ExtensionOrderer.TestAccessor.CheckForCycles(extensions));
......@@ -172,7 +160,7 @@ public void TestCycle6()
var f = CreateExtension(name: "f", before: new[] { "g" });
var g = CreateExtension(name: "g");
var extensions = new List<Lazy<Extension, ExtensionMetadata>>() { a, b, c, d, e, f, g };
var extensions = new List<Lazy<Extension, OrderableMetadata>>() { a, b, c, d, e, f, g };
// ExtensionOrderer.TestAccessor.CheckForCycles() will throw ArgumentException when cycle is detected.
Assert.Throws<ArgumentException>(() => ExtensionOrderer.TestAccessor.CheckForCycles(extensions));
......@@ -190,7 +178,7 @@ public void TestCycle7()
var e = CreateExtension(name: "e", before: new[] { "f" });
var f = CreateExtension(name: "f", before: new[] { "d" });
var extensions = new List<Lazy<Extension, ExtensionMetadata>>() { a, b, c, d, e, f };
var extensions = new List<Lazy<Extension, OrderableMetadata>>() { a, b, c, d, e, f };
// ExtensionOrderer.TestAccessor.CheckForCycles() will throw ArgumentException when cycle is detected.
Assert.Throws<ArgumentException>(() => ExtensionOrderer.TestAccessor.CheckForCycles(extensions));
......@@ -208,7 +196,7 @@ public void TestCycle8()
var e = CreateExtension(name: "e", before: new[] { "f" });
var f = CreateExtension(name: "f", before: new[] { "a" });
var extensions = new List<Lazy<Extension, ExtensionMetadata>>() { a, b, c, d, e, f };
var extensions = new List<Lazy<Extension, OrderableMetadata>>() { a, b, c, d, e, f };
// ExtensionOrderer.TestAccessor.CheckForCycles() will throw ArgumentException when cycle is detected.
Assert.Throws<ArgumentException>(() => ExtensionOrderer.TestAccessor.CheckForCycles(extensions));
......@@ -217,28 +205,23 @@ public void TestCycle8()
}
#region Helpers
private Lazy<Extension, ExtensionMetadata> CreateExtension(string name = null, IEnumerable<string> before = null, IEnumerable<string> after = null)
{
return new Lazy<Extension, ExtensionMetadata>(new ExtensionMetadata(name, before, after));
}
private IEnumerable<string> GetNames(IEnumerable<Lazy<Extension, ExtensionMetadata>> actual)
private Lazy<Extension, OrderableMetadata> CreateExtension(string? name = null, IEnumerable<string>? before = null, IEnumerable<string>? after = null)
{
return actual.Select(i => i.Metadata.Name);
return new Lazy<Extension, OrderableMetadata>(new OrderableMetadata(name, before: before, after: after));
}
private void VerifyOrder(IEnumerable<string> expected, IEnumerable<Lazy<Extension, ExtensionMetadata>> actual)
private IEnumerable<string?> GetNames(IEnumerable<Lazy<Extension, OrderableMetadata>> actual)
{
var expectedOrder = string.Join(string.Empty, expected);
var actualOrder = string.Join(string.Empty, GetNames(actual));
Assert.Equal(expectedOrder, actualOrder);
return actual.Select(i => i.Metadata.Name);
}
private void VerifyOrder(string expected, IEnumerable<Lazy<Extension, ExtensionMetadata>> actual)
private void VerifyOrder(string expected, IEnumerable<Lazy<Extension, OrderableMetadata>> actual)
{
var actualOrder = string.Join(string.Empty, GetNames(actual));
Assert.Equal(expected, actualOrder);
}
#endregion
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册