diff --git a/ILSpy/Analyzers/AnalyzerSearchTreeNode.cs b/ILSpy/Analyzers/AnalyzerSearchTreeNode.cs index 8e37d22fb..6b1e3ee63 100644 --- a/ILSpy/Analyzers/AnalyzerSearchTreeNode.cs +++ b/ILSpy/Analyzers/AnalyzerSearchTreeNode.cs @@ -31,15 +31,17 @@ namespace ICSharpCode.ILSpy.Analyzers private readonly ThreadingSupport threading = new ThreadingSupport(); readonly ISymbol symbol; readonly IAnalyzer analyzer; + readonly string analyzerHeader; - public AnalyzerSearchTreeNode(ISymbol symbol, IAnalyzer analyzer) + public AnalyzerSearchTreeNode(ISymbol symbol, IAnalyzer analyzer, string analyzerHeader) { this.symbol = symbol; this.analyzer = analyzer ?? throw new ArgumentNullException(nameof(analyzer)); this.LazyLoading = true; + this.analyzerHeader = analyzerHeader; } - public override object Text => analyzer.Text + (Children.Count > 0 ? " (" + Children.Count + ")" : ""); + public override object Text => analyzerHeader + (Children.Count > 0 ? " (" + Children.Count + ")" : ""); public override object Icon => Images.Search; diff --git a/ILSpy/Analyzers/Builtin/EventImplementsInterfaceAnalyzer.cs b/ILSpy/Analyzers/Builtin/EventImplementsInterfaceAnalyzer.cs index 144f6e1e3..c6efcd98f 100644 --- a/ILSpy/Analyzers/Builtin/EventImplementsInterfaceAnalyzer.cs +++ b/ILSpy/Analyzers/Builtin/EventImplementsInterfaceAnalyzer.cs @@ -27,11 +27,9 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin /// /// Shows events that implement an interface event. /// - [Export(typeof(IAnalyzer))] + [ExportAnalyzer(Header = "Implemented By", Order = 10)] class EventImplementsInterfaceAnalyzer : IAnalyzer { - public string Text => "Implemented By"; - public IEnumerable Analyze(ISymbol analyzedSymbol, AnalyzerContext context) { Debug.Assert(analyzedSymbol is IEvent); diff --git a/ILSpy/Analyzers/Builtin/EventOverriddenByAnalyzer.cs b/ILSpy/Analyzers/Builtin/EventOverriddenByAnalyzer.cs index 7a66292f9..2688f72c3 100644 --- a/ILSpy/Analyzers/Builtin/EventOverriddenByAnalyzer.cs +++ b/ILSpy/Analyzers/Builtin/EventOverriddenByAnalyzer.cs @@ -27,11 +27,9 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin /// /// Shows events that override an event. /// - [Export(typeof(IAnalyzer))] + [ExportAnalyzer(Header = "Overridden By", Order = 20)] class EventOverriddenByAnalyzer : IAnalyzer { - public string Text => "Overridden By"; - public IEnumerable Analyze(ISymbol analyzedSymbol, AnalyzerContext context) { Debug.Assert(analyzedSymbol is IEvent); diff --git a/ILSpy/Analyzers/Builtin/FieldAccessAnalyzer.cs b/ILSpy/Analyzers/Builtin/FieldAccessAnalyzer.cs index 37ee16e2b..e3b414423 100644 --- a/ILSpy/Analyzers/Builtin/FieldAccessAnalyzer.cs +++ b/ILSpy/Analyzers/Builtin/FieldAccessAnalyzer.cs @@ -37,7 +37,7 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin /// /// Finds methods where this field is read. /// - [Export(typeof(IAnalyzer))] + [ExportAnalyzer(Header = "Assigned By", Order = 20)] class AssignedByFieldAccessAnalyzer : FieldAccessAnalyzer { public AssignedByFieldAccessAnalyzer() : base(true) { } @@ -46,7 +46,7 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin /// /// Finds methods where this field is written. /// - [Export(typeof(IAnalyzer))] + [ExportAnalyzer(Header = "Read By", Order = 10)] class ReadByFieldAccessAnalyzer : FieldAccessAnalyzer { public ReadByFieldAccessAnalyzer() : base(false) { } @@ -61,8 +61,6 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin readonly bool showWrites; // true: show writes; false: show read access - public string Text => showWrites ? "Assigned By" : "Read By"; - public FieldAccessAnalyzer(bool showWrites) { this.showWrites = showWrites; diff --git a/ILSpy/Analyzers/Builtin/MethodImplementsInterfaceAnalyzer.cs b/ILSpy/Analyzers/Builtin/MethodImplementsInterfaceAnalyzer.cs index 0b5013328..75c8c4e6a 100644 --- a/ILSpy/Analyzers/Builtin/MethodImplementsInterfaceAnalyzer.cs +++ b/ILSpy/Analyzers/Builtin/MethodImplementsInterfaceAnalyzer.cs @@ -30,11 +30,9 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin /// /// Shows methods that implement an interface method. /// - [Export(typeof(IAnalyzer))] + [ExportAnalyzer(Header = "Implemented By", Order = 40)] class MethodImplementsInterfaceAnalyzer : IAnalyzer { - public string Text => "Implemented By"; - public IEnumerable Analyze(ISymbol analyzedSymbol, AnalyzerContext context) { Debug.Assert(analyzedSymbol is IMethod); diff --git a/ILSpy/Analyzers/Builtin/MethodOverriddenByAnalyzer.cs b/ILSpy/Analyzers/Builtin/MethodOverriddenByAnalyzer.cs index 2c8f25e97..95004dff6 100644 --- a/ILSpy/Analyzers/Builtin/MethodOverriddenByAnalyzer.cs +++ b/ILSpy/Analyzers/Builtin/MethodOverriddenByAnalyzer.cs @@ -27,13 +27,11 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin /// /// Shows methods that override a method. /// - [Export(typeof(IAnalyzer))] + [ExportAnalyzer(Header = "Overridden By", Order = 30)] class MethodOverriddenByAnalyzer : IAnalyzer { const GetMemberOptions Options = GetMemberOptions.IgnoreInheritedMembers | GetMemberOptions.ReturnMemberDefinitions; - public string Text => "Overridden By"; - public IEnumerable Analyze(ISymbol analyzedSymbol, AnalyzerContext context) { Debug.Assert(analyzedSymbol is IMethod); diff --git a/ILSpy/Analyzers/Builtin/MethodUsedByAnalyzer.cs b/ILSpy/Analyzers/Builtin/MethodUsedByAnalyzer.cs index 1b2bd1d21..c89424c05 100644 --- a/ILSpy/Analyzers/Builtin/MethodUsedByAnalyzer.cs +++ b/ILSpy/Analyzers/Builtin/MethodUsedByAnalyzer.cs @@ -31,13 +31,11 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin /// /// Shows entities that are used by a method. /// - [Export(typeof(IAnalyzer))] + [ExportAnalyzer(Header = "Used By", Order = 20)] class MethodUsedByAnalyzer : IAnalyzer { const GetMemberOptions Options = GetMemberOptions.IgnoreInheritedMembers | GetMemberOptions.ReturnMemberDefinitions; - public string Text => "Used By"; - public bool Show(ISymbol symbol) => symbol is IMethod method && !method.IsVirtual; public IEnumerable Analyze(ISymbol analyzedSymbol, AnalyzerContext context) diff --git a/ILSpy/Analyzers/Builtin/MethodUsesAnalyzer.cs b/ILSpy/Analyzers/Builtin/MethodUsesAnalyzer.cs index 01c00bbd3..8c6436890 100644 --- a/ILSpy/Analyzers/Builtin/MethodUsesAnalyzer.cs +++ b/ILSpy/Analyzers/Builtin/MethodUsesAnalyzer.cs @@ -33,12 +33,10 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin /// /// Shows entities that are used by a method. /// - [Export(typeof(IAnalyzer))] + [ExportAnalyzer(Header = "Uses", Order = 10)] class MethodUsesAnalyzer : IAnalyzer { - public string Text => "Uses"; - - public bool Show(ISymbol symbol) => symbol is IMethod method && !method.IsVirtual; + public bool Show(ISymbol symbol) => symbol is IMethod method && method.HasBody; public IEnumerable Analyze(ISymbol symbol, AnalyzerContext context) { diff --git a/ILSpy/Analyzers/Builtin/MethodVirtualUsedByAnalyzer.cs b/ILSpy/Analyzers/Builtin/MethodVirtualUsedByAnalyzer.cs index 06fb4f4c2..8bdc3aee5 100644 --- a/ILSpy/Analyzers/Builtin/MethodVirtualUsedByAnalyzer.cs +++ b/ILSpy/Analyzers/Builtin/MethodVirtualUsedByAnalyzer.cs @@ -31,13 +31,11 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin /// /// Shows entities that are used by a method. /// - [Export(typeof(IAnalyzer))] + [ExportAnalyzer(Header = "Used By", Order = 20)] class MethodVirtualUsedByAnalyzer : IAnalyzer { const GetMemberOptions Options = GetMemberOptions.IgnoreInheritedMembers | GetMemberOptions.ReturnMemberDefinitions; - public string Text => "Used By"; - public bool Show(ISymbol symbol) => symbol is IMethod method && method.IsVirtual; public IEnumerable Analyze(ISymbol analyzedSymbol, AnalyzerContext context) diff --git a/ILSpy/Analyzers/Builtin/PropertyImplementsInterfaceAnalyzer.cs b/ILSpy/Analyzers/Builtin/PropertyImplementsInterfaceAnalyzer.cs index af58769e9..938e0e4e2 100644 --- a/ILSpy/Analyzers/Builtin/PropertyImplementsInterfaceAnalyzer.cs +++ b/ILSpy/Analyzers/Builtin/PropertyImplementsInterfaceAnalyzer.cs @@ -27,11 +27,9 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin /// /// Shows properties that implement an interface property. /// - [Export(typeof(IAnalyzer))] + [ExportAnalyzer(Header = "Implemented By", Order = 10)] class PropertyImplementsInterfaceAnalyzer : IAnalyzer { - public string Text => "Implemented By"; - public IEnumerable Analyze(ISymbol analyzedSymbol, AnalyzerContext context) { Debug.Assert(analyzedSymbol is IProperty); diff --git a/ILSpy/Analyzers/Builtin/PropertyOverriddenByAnalyzer.cs b/ILSpy/Analyzers/Builtin/PropertyOverriddenByAnalyzer.cs index df26da28f..b253a447d 100644 --- a/ILSpy/Analyzers/Builtin/PropertyOverriddenByAnalyzer.cs +++ b/ILSpy/Analyzers/Builtin/PropertyOverriddenByAnalyzer.cs @@ -30,11 +30,9 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin /// /// Shows properties that override a property. /// - [Export(typeof(IAnalyzer))] + [ExportAnalyzer(Header = "Overridden By", Order = 20)] class PropertyOverriddenByAnalyzer : IAnalyzer { - public string Text => "Overridden By"; - public IEnumerable Analyze(ISymbol analyzedSymbol, AnalyzerContext context) { Debug.Assert(analyzedSymbol is IProperty); diff --git a/ILSpy/Analyzers/Builtin/TypeExposedByAnalyzer.cs b/ILSpy/Analyzers/Builtin/TypeExposedByAnalyzer.cs index c48275cbc..87bd95e01 100644 --- a/ILSpy/Analyzers/Builtin/TypeExposedByAnalyzer.cs +++ b/ILSpy/Analyzers/Builtin/TypeExposedByAnalyzer.cs @@ -30,11 +30,9 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin /// /// Finds all entities that expose a type. /// - [Export(typeof(IAnalyzer))] + [ExportAnalyzer(Header = "Exposed By", Order = 40)] class TypeExposedByAnalyzer : IAnalyzer { - public string Text => "Exposed By"; - public bool Show(ISymbol entity) => entity is ITypeDefinition; public IEnumerable Analyze(ISymbol analyzedSymbol, AnalyzerContext context) diff --git a/ILSpy/Analyzers/Builtin/TypeExtensionMethodsAnalyzer.cs b/ILSpy/Analyzers/Builtin/TypeExtensionMethodsAnalyzer.cs index b51a7a5a5..1d2a1d960 100644 --- a/ILSpy/Analyzers/Builtin/TypeExtensionMethodsAnalyzer.cs +++ b/ILSpy/Analyzers/Builtin/TypeExtensionMethodsAnalyzer.cs @@ -8,11 +8,9 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin /// /// Finds all extension methods defined for a type. /// - [Export(typeof(IAnalyzer))] + [ExportAnalyzer(Header = "Extension Methods", Order = 50)] class TypeExtensionMethodsAnalyzer : IAnalyzer { - public string Text => "Extension Methods"; - public bool Show(ISymbol symbol) => symbol is ITypeDefinition entity && !entity.IsStatic; public IEnumerable Analyze(ISymbol analyzedSymbol, AnalyzerContext context) diff --git a/ILSpy/Analyzers/Builtin/TypeInstantiatedByAnalyzer.cs b/ILSpy/Analyzers/Builtin/TypeInstantiatedByAnalyzer.cs index 31c0c1819..cfb9252d6 100644 --- a/ILSpy/Analyzers/Builtin/TypeInstantiatedByAnalyzer.cs +++ b/ILSpy/Analyzers/Builtin/TypeInstantiatedByAnalyzer.cs @@ -34,13 +34,11 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin /// /// Shows methods that instantiate a type. /// - [Export(typeof(IAnalyzer))] + [ExportAnalyzer(Header = "Instantiated By", Order = 20)] class TypeInstantiatedByAnalyzer : IAnalyzer { const GetMemberOptions Options = GetMemberOptions.IgnoreInheritedMembers | GetMemberOptions.ReturnMemberDefinitions; - public string Text => "Instantiated By"; - public IEnumerable Analyze(ISymbol analyzedSymbol, AnalyzerContext context) { Debug.Assert(analyzedSymbol is ITypeDefinition); diff --git a/ILSpy/Analyzers/Builtin/TypeUsedByAnalyzer.cs b/ILSpy/Analyzers/Builtin/TypeUsedByAnalyzer.cs index d45ec521e..862bc162f 100644 --- a/ILSpy/Analyzers/Builtin/TypeUsedByAnalyzer.cs +++ b/ILSpy/Analyzers/Builtin/TypeUsedByAnalyzer.cs @@ -32,11 +32,9 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin /// /// Shows entities that use a type. /// - [Export(typeof(IAnalyzer))] + [ExportAnalyzer(Header = "Used By", Order = 30)] class TypeUsedByAnalyzer : IAnalyzer { - public string Text => "Used By"; - public IEnumerable Analyze(ISymbol analyzedSymbol, AnalyzerContext context) { Debug.Assert(analyzedSymbol is ITypeDefinition); diff --git a/ILSpy/Analyzers/IAnalyzer.cs b/ILSpy/Analyzers/IAnalyzer.cs index c1281f8fa..c9a6db526 100644 --- a/ILSpy/Analyzers/IAnalyzer.cs +++ b/ILSpy/Analyzers/IAnalyzer.cs @@ -18,6 +18,7 @@ using System; using System.Collections.Generic; +using System.ComponentModel.Composition; using System.Linq; using System.Reflection.Metadata; using System.Threading; @@ -33,11 +34,6 @@ namespace ICSharpCode.ILSpy.Analyzers /// public interface IAnalyzer { - /// - /// The caption used in the analyzer tree view. - /// - string Text { get; } - /// /// Returns true, if the analyzer should be shown for a symbol, otherwise false. /// @@ -80,4 +76,22 @@ namespace ICSharpCode.ILSpy.Analyzers return new AnalyzerScope(AssemblyList, entity); } } + + [MetadataAttribute] + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] + public class ExportAnalyzerAttribute : ExportAttribute, IAnalyzerMetadata + { + public ExportAnalyzerAttribute() : base("Analyzer", typeof(IAnalyzer)) + { } + + public string Header { get; set; } + + public int Order { get; set; } + } + + public interface IAnalyzerMetadata + { + string Header { get; } + int Order { get; } + } } diff --git a/ILSpy/Analyzers/TreeNodes/AnalyzedEventTreeNode.cs b/ILSpy/Analyzers/TreeNodes/AnalyzedEventTreeNode.cs index 02c7f71bc..07e73c157 100644 --- a/ILSpy/Analyzers/TreeNodes/AnalyzedEventTreeNode.cs +++ b/ILSpy/Analyzers/TreeNodes/AnalyzedEventTreeNode.cs @@ -54,10 +54,11 @@ namespace ICSharpCode.ILSpy.Analyzers.TreeNodes //foreach (var accessor in analyzedEvent.OtherMethods) // this.Children.Add(new AnalyzedAccessorTreeNode(accessor, null)); - foreach (var lazy in App.ExportProvider.GetExports()) { + var analyzers = App.ExportProvider.GetExports("Analyzer"); + foreach (var lazy in analyzers.OrderBy(item => item.Metadata.Order)) { var analyzer = lazy.Value; if (analyzer.Show(analyzedEvent)) { - this.Children.Add(new AnalyzerSearchTreeNode(analyzedEvent, analyzer)); + this.Children.Add(new AnalyzerSearchTreeNode(analyzedEvent, analyzer, lazy.Metadata.Header)); } } } diff --git a/ILSpy/Analyzers/TreeNodes/AnalyzedFieldTreeNode.cs b/ILSpy/Analyzers/TreeNodes/AnalyzedFieldTreeNode.cs index c89a77313..c429e14ab 100644 --- a/ILSpy/Analyzers/TreeNodes/AnalyzedFieldTreeNode.cs +++ b/ILSpy/Analyzers/TreeNodes/AnalyzedFieldTreeNode.cs @@ -17,6 +17,7 @@ // DEALINGS IN THE SOFTWARE. using System; +using System.Linq; using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.ILSpy.TreeNodes; @@ -38,10 +39,11 @@ namespace ICSharpCode.ILSpy.Analyzers.TreeNodes protected override void LoadChildren() { - foreach (var lazy in App.ExportProvider.GetExports()) { + var analyzers = App.ExportProvider.GetExports("Analyzer"); + foreach (var lazy in analyzers.OrderBy(item => item.Metadata.Order)) { var analyzer = lazy.Value; if (analyzer.Show(analyzedField)) { - this.Children.Add(new AnalyzerSearchTreeNode(analyzedField, analyzer)); + this.Children.Add(new AnalyzerSearchTreeNode(analyzedField, analyzer, lazy.Metadata.Header)); } } } diff --git a/ILSpy/Analyzers/TreeNodes/AnalyzedMethodTreeNode.cs b/ILSpy/Analyzers/TreeNodes/AnalyzedMethodTreeNode.cs index 53c2790b4..783427b16 100644 --- a/ILSpy/Analyzers/TreeNodes/AnalyzedMethodTreeNode.cs +++ b/ILSpy/Analyzers/TreeNodes/AnalyzedMethodTreeNode.cs @@ -17,6 +17,7 @@ // DEALINGS IN THE SOFTWARE. using System; +using System.Linq; using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.ILSpy.TreeNodes; @@ -40,10 +41,11 @@ namespace ICSharpCode.ILSpy.Analyzers.TreeNodes protected override void LoadChildren() { - foreach (var lazy in App.ExportProvider.GetExports()) { + var analyzers = App.ExportProvider.GetExports("Analyzer"); + foreach (var lazy in analyzers.OrderBy(item => item.Metadata.Order)) { var analyzer = lazy.Value; if (analyzer.Show(analyzedMethod)) { - this.Children.Add(new AnalyzerSearchTreeNode(analyzedMethod, analyzer)); + this.Children.Add(new AnalyzerSearchTreeNode(analyzedMethod, analyzer, lazy.Metadata.Header)); } } } diff --git a/ILSpy/Analyzers/TreeNodes/AnalyzedPropertyTreeNode.cs b/ILSpy/Analyzers/TreeNodes/AnalyzedPropertyTreeNode.cs index b230ed789..c1c81541e 100644 --- a/ILSpy/Analyzers/TreeNodes/AnalyzedPropertyTreeNode.cs +++ b/ILSpy/Analyzers/TreeNodes/AnalyzedPropertyTreeNode.cs @@ -17,6 +17,7 @@ // DEALINGS IN THE SOFTWARE. using System; +using System.Linq; using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.ILSpy.TreeNodes; @@ -48,10 +49,11 @@ namespace ICSharpCode.ILSpy.Analyzers.TreeNodes //foreach (var accessor in analyzedProperty.OtherMethods) // this.Children.Add(new AnalyzedPropertyAccessorTreeNode(accessor, null)); - foreach (var lazy in App.ExportProvider.GetExports()) { + var analyzers = App.ExportProvider.GetExports("Analyzer"); + foreach (var lazy in analyzers.OrderBy(item => item.Metadata.Order)) { var analyzer = lazy.Value; if (analyzer.Show(analyzedProperty)) { - this.Children.Add(new AnalyzerSearchTreeNode(analyzedProperty, analyzer)); + this.Children.Add(new AnalyzerSearchTreeNode(analyzedProperty, analyzer, lazy.Metadata.Header)); } } } diff --git a/ILSpy/Analyzers/TreeNodes/AnalyzedTypeTreeNode.cs b/ILSpy/Analyzers/TreeNodes/AnalyzedTypeTreeNode.cs index 497de3bd5..6c9622d7b 100644 --- a/ILSpy/Analyzers/TreeNodes/AnalyzedTypeTreeNode.cs +++ b/ILSpy/Analyzers/TreeNodes/AnalyzedTypeTreeNode.cs @@ -17,6 +17,7 @@ // DEALINGS IN THE SOFTWARE. using System; +using System.Linq; using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.ILSpy.TreeNodes; @@ -38,10 +39,11 @@ namespace ICSharpCode.ILSpy.Analyzers.TreeNodes protected override void LoadChildren() { - foreach (var lazy in App.ExportProvider.GetExports()) { + var analyzers = App.ExportProvider.GetExports("Analyzer"); + foreach (var lazy in analyzers.OrderBy(item => item.Metadata.Order)) { var analyzer = lazy.Value; if (analyzer.Show(analyzedType)) { - this.Children.Add(new AnalyzerSearchTreeNode(analyzedType, analyzer)); + this.Children.Add(new AnalyzerSearchTreeNode(analyzedType, analyzer, lazy.Metadata.Header)); } } }