├── .gitattributes ├── .gitignore ├── Directory.Build.props ├── Directory.Build.targets ├── InheritanceMargin.sln ├── LICENSE.txt ├── PreviewLarge.png ├── README.md ├── Reference ├── Microsoft.CodeAnalysis.EditorFeatures.Text.dll └── SharedKey.snk ├── TunnelVisionLabs.InheritanceMargin.ruleset ├── Tvl.VisualStudio.InheritanceMargin.CSharp.Legacy ├── CSharpInheritanceAnalyzer.cs ├── CSharpMemberIdentifierEqualityComparer.cs ├── MemberTarget.cs ├── RoslynMemberTarget.cs ├── RoslynTypeTarget.cs ├── SpecializedMatchingMemberCollector.cs ├── Tvl.VisualStudio.InheritanceMargin.CSharp.11.0.csproj ├── Tvl.VisualStudio.InheritanceMargin.CSharp.12.0.csproj ├── TypeCollector.cs ├── TypeDeclarationNodeSelector.cs └── TypeTarget.cs ├── Tvl.VisualStudio.InheritanceMargin.CSharp ├── AbstractTarget.cs ├── BackgroundParser.cs ├── CSharpInheritanceAnalyzer.cs ├── MemberTarget.cs ├── Properties │ └── AssemblyInfo.cs ├── Tvl.VisualStudio.InheritanceMargin.CSharp.14.0.csproj ├── Tvl.VisualStudio.InheritanceMargin.CSharp.15.0.csproj ├── Tvl.VisualStudio.InheritanceMargin.CSharp.16.0.csproj ├── Tvl.VisualStudio.InheritanceMargin.CSharp.17.0.csproj ├── Tvl.VisualStudio.InheritanceMargin.CSharp.Roslyn.csproj └── TypeTarget.cs ├── Tvl.VisualStudio.InheritanceMargin.Interfaces ├── IInheritanceParser.cs ├── IInheritanceTag.cs ├── IInheritanceTagFactory.cs ├── IInheritanceTarget.cs ├── InheritanceGlyph.cs ├── InheritanceParseResultEventArgs.cs ├── MefBindingWorkaround.cs ├── Properties │ └── AssemblyInfo.cs └── Tvl.VisualStudio.InheritanceMargin.Interfaces.csproj ├── Tvl.VisualStudio.InheritanceMargin ├── CSharpInheritanceTagger.cs ├── CSharpInheritanceTaggerProvider.cs ├── CommandTranslation │ ├── CommandId.cs │ ├── CommandRouter.cs │ └── CommandTargetParameters.cs ├── InheritanceGlyphFactory.cs ├── InheritanceGlyphFactoryProvider.cs ├── InheritanceGlyphMouseHandler.cs ├── InheritanceGlyphMouseHandlerProvider.cs ├── InheritanceMargin.vsct ├── InheritanceMarginConstants.cs ├── InheritanceMarginPackage.cs ├── InheritanceTag.cs ├── InheritanceTagFactory.cs ├── Properties │ ├── AssemblyInfo.cs │ └── launchSettings.json ├── ProvideBindingPathAttribute.cs ├── Resources │ ├── has-implementations.png │ ├── implements.png │ ├── is-overridden.png │ ├── override-is-overridden-combined.png │ ├── override-is-overridden-combined2.png │ └── overrides.png ├── RoslynUtilities.cs ├── Tvl.VisualStudio.InheritanceMargin.csproj ├── VSIXImage_large.png ├── VSIXImage_small.png ├── VSPackage.resx └── source.extension.vsixmanifest ├── appveyor.yml ├── global.json ├── stylecop.json └── version.json /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Per-user files 2 | *.csproj.user 3 | *.suo 4 | 5 | # Temporary files created by the IDE 6 | .vs/ 7 | 8 | # NuGet packages 9 | packages/ 10 | 11 | # Build output 12 | bin/ 13 | obj/ 14 | -------------------------------------------------------------------------------- /Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | true 6 | full 7 | 8 | 9 | 10 | pdbonly 11 | 12 | 13 | 14 | true 15 | $(MSBuildThisFileDirectory)TunnelVisionLabs.InheritanceMargin.ruleset 16 | true 17 | $(MSBuildThisFileDirectory)Reference\SharedKey.snk 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | Tunnel Vision Laboratories, LLC 27 | Copyright © Sam Harwell 2014 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /Directory.Build.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /InheritanceMargin.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.28315.86 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{3E5B8C5F-AEEB-484A-80C8-F5660CB8FA27}" 7 | ProjectSection(SolutionItems) = preProject 8 | appveyor.yml = appveyor.yml 9 | LICENSE.txt = LICENSE.txt 10 | README.md = README.md 11 | stylecop.json = stylecop.json 12 | TunnelVisionLabs.InheritanceMargin.ruleset = TunnelVisionLabs.InheritanceMargin.ruleset 13 | EndProjectSection 14 | EndProject 15 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tvl.VisualStudio.InheritanceMargin", "Tvl.VisualStudio.InheritanceMargin\Tvl.VisualStudio.InheritanceMargin.csproj", "{C5BE4BE1-F167-4D34-980A-1A2F83C5D74A}" 16 | EndProject 17 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tvl.VisualStudio.InheritanceMargin.Interfaces", "Tvl.VisualStudio.InheritanceMargin.Interfaces\Tvl.VisualStudio.InheritanceMargin.Interfaces.csproj", "{F4B709E6-8926-42E6-914A-749CB473F37B}" 18 | EndProject 19 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tvl.VisualStudio.InheritanceMargin.CSharp.11.0", "Tvl.VisualStudio.InheritanceMargin.CSharp.Legacy\Tvl.VisualStudio.InheritanceMargin.CSharp.11.0.csproj", "{2ACB7340-8400-4D5D-8624-A4E7FE8FC474}" 20 | EndProject 21 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tvl.VisualStudio.InheritanceMargin.CSharp.12.0", "Tvl.VisualStudio.InheritanceMargin.CSharp.Legacy\Tvl.VisualStudio.InheritanceMargin.CSharp.12.0.csproj", "{FBB6E057-77DA-4FF6-A867-EF741971E511}" 22 | EndProject 23 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tvl.VisualStudio.InheritanceMargin.CSharp.Roslyn", "Tvl.VisualStudio.InheritanceMargin.CSharp\Tvl.VisualStudio.InheritanceMargin.CSharp.Roslyn.csproj", "{912F988E-C5D9-413A-9B81-86D0AA67947B}" 24 | EndProject 25 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tvl.VisualStudio.InheritanceMargin.CSharp.14.0", "Tvl.VisualStudio.InheritanceMargin.CSharp\Tvl.VisualStudio.InheritanceMargin.CSharp.14.0.csproj", "{7D84BB06-4C50-4EB4-ABD5-71C63B0C2409}" 26 | EndProject 27 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tvl.VisualStudio.InheritanceMargin.CSharp.15.0", "Tvl.VisualStudio.InheritanceMargin.CSharp\Tvl.VisualStudio.InheritanceMargin.CSharp.15.0.csproj", "{A3EBBB23-61F7-4A28-9179-59221875B713}" 28 | EndProject 29 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tvl.VisualStudio.InheritanceMargin.CSharp.16.0", "Tvl.VisualStudio.InheritanceMargin.CSharp\Tvl.VisualStudio.InheritanceMargin.CSharp.16.0.csproj", "{10788A42-FFD8-4FDD-9F78-34860257D008}" 30 | EndProject 31 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tvl.VisualStudio.InheritanceMargin.CSharp.17.0", "Tvl.VisualStudio.InheritanceMargin.CSharp\Tvl.VisualStudio.InheritanceMargin.CSharp.17.0.csproj", "{FC878788-4674-4975-B90F-7CCFF33E32D5}" 32 | EndProject 33 | Global 34 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 35 | Debug|Any CPU = Debug|Any CPU 36 | Release|Any CPU = Release|Any CPU 37 | EndGlobalSection 38 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 39 | {C5BE4BE1-F167-4D34-980A-1A2F83C5D74A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 40 | {C5BE4BE1-F167-4D34-980A-1A2F83C5D74A}.Debug|Any CPU.Build.0 = Debug|Any CPU 41 | {C5BE4BE1-F167-4D34-980A-1A2F83C5D74A}.Release|Any CPU.ActiveCfg = Release|Any CPU 42 | {C5BE4BE1-F167-4D34-980A-1A2F83C5D74A}.Release|Any CPU.Build.0 = Release|Any CPU 43 | {F4B709E6-8926-42E6-914A-749CB473F37B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 44 | {F4B709E6-8926-42E6-914A-749CB473F37B}.Debug|Any CPU.Build.0 = Debug|Any CPU 45 | {F4B709E6-8926-42E6-914A-749CB473F37B}.Release|Any CPU.ActiveCfg = Release|Any CPU 46 | {F4B709E6-8926-42E6-914A-749CB473F37B}.Release|Any CPU.Build.0 = Release|Any CPU 47 | {2ACB7340-8400-4D5D-8624-A4E7FE8FC474}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 48 | {2ACB7340-8400-4D5D-8624-A4E7FE8FC474}.Debug|Any CPU.Build.0 = Debug|Any CPU 49 | {2ACB7340-8400-4D5D-8624-A4E7FE8FC474}.Release|Any CPU.ActiveCfg = Release|Any CPU 50 | {2ACB7340-8400-4D5D-8624-A4E7FE8FC474}.Release|Any CPU.Build.0 = Release|Any CPU 51 | {FBB6E057-77DA-4FF6-A867-EF741971E511}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 52 | {FBB6E057-77DA-4FF6-A867-EF741971E511}.Debug|Any CPU.Build.0 = Debug|Any CPU 53 | {FBB6E057-77DA-4FF6-A867-EF741971E511}.Release|Any CPU.ActiveCfg = Release|Any CPU 54 | {FBB6E057-77DA-4FF6-A867-EF741971E511}.Release|Any CPU.Build.0 = Release|Any CPU 55 | {912F988E-C5D9-413A-9B81-86D0AA67947B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 56 | {912F988E-C5D9-413A-9B81-86D0AA67947B}.Debug|Any CPU.Build.0 = Debug|Any CPU 57 | {912F988E-C5D9-413A-9B81-86D0AA67947B}.Release|Any CPU.ActiveCfg = Release|Any CPU 58 | {912F988E-C5D9-413A-9B81-86D0AA67947B}.Release|Any CPU.Build.0 = Release|Any CPU 59 | {7D84BB06-4C50-4EB4-ABD5-71C63B0C2409}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 60 | {7D84BB06-4C50-4EB4-ABD5-71C63B0C2409}.Debug|Any CPU.Build.0 = Debug|Any CPU 61 | {7D84BB06-4C50-4EB4-ABD5-71C63B0C2409}.Release|Any CPU.ActiveCfg = Release|Any CPU 62 | {7D84BB06-4C50-4EB4-ABD5-71C63B0C2409}.Release|Any CPU.Build.0 = Release|Any CPU 63 | {A3EBBB23-61F7-4A28-9179-59221875B713}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 64 | {A3EBBB23-61F7-4A28-9179-59221875B713}.Debug|Any CPU.Build.0 = Debug|Any CPU 65 | {A3EBBB23-61F7-4A28-9179-59221875B713}.Release|Any CPU.ActiveCfg = Release|Any CPU 66 | {A3EBBB23-61F7-4A28-9179-59221875B713}.Release|Any CPU.Build.0 = Release|Any CPU 67 | {10788A42-FFD8-4FDD-9F78-34860257D008}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 68 | {10788A42-FFD8-4FDD-9F78-34860257D008}.Debug|Any CPU.Build.0 = Debug|Any CPU 69 | {10788A42-FFD8-4FDD-9F78-34860257D008}.Release|Any CPU.ActiveCfg = Release|Any CPU 70 | {10788A42-FFD8-4FDD-9F78-34860257D008}.Release|Any CPU.Build.0 = Release|Any CPU 71 | {FC878788-4674-4975-B90F-7CCFF33E32D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 72 | {FC878788-4674-4975-B90F-7CCFF33E32D5}.Debug|Any CPU.Build.0 = Debug|Any CPU 73 | {FC878788-4674-4975-B90F-7CCFF33E32D5}.Release|Any CPU.ActiveCfg = Release|Any CPU 74 | {FC878788-4674-4975-B90F-7CCFF33E32D5}.Release|Any CPU.Build.0 = Release|Any CPU 75 | EndGlobalSection 76 | GlobalSection(SolutionProperties) = preSolution 77 | HideSolutionNode = FALSE 78 | EndGlobalSection 79 | GlobalSection(ExtensibilityGlobals) = postSolution 80 | SolutionGuid = {E2CC4FE1-7257-44CA-B677-9A80EDFCDE0B} 81 | EndGlobalSection 82 | EndGlobal 83 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Tunnel Vision Laboratories, LLC 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /PreviewLarge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tunnelvisionlabs/InheritanceMargin/7c3ebf3d71d0185d8b6f74a4b4c1c99f3f9217e6/PreviewLarge.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Inheritance Margin extension for Visual Studio 2012+ 2 | 3 | [![Build status](https://ci.appveyor.com/api/projects/status/0n5me6pqj21fh0fo/branch/master?svg=true)](https://ci.appveyor.com/project/sharwell/inheritancemargin/branch/master) 4 | 5 | This extension adds inheritance glyphs to the glyph margin in the Visual Studio text editor. Glyphs are displayed for the following items: 6 | 7 | * Interface methods/properties/events which are implemented by the current item 8 | * Virtual methods/properties/events in base classes which are overridden by the current item 9 | * Types which extend or implement the current type 10 | * For interfaces: 11 | * Methods/properties/events in derived types which implement the current item 12 | * Interfaces which extend the current interface 13 | * Classes which implement the current interface 14 | * For base classes: 15 | * Methods/properties/events in derived types which override the current item 16 | * Classes which extend the current class 17 | 18 | ![Preview](PreviewLarge.png) 19 | 20 | ## Limitations 21 | 22 | * **C# only:** The current version only supports C#. In the future, I plan to support other languages via other MEF extensions. 23 | * **Updates while you type:** The glyphs for a file are only updated when that file is opened and when text in that file changes. If changes in open files are not being reflected, you can either close and reopen the affected file or type in the file to force an update. 24 | * **ReSharper users:** ReSharper provides its own version of a similar feature, so this extension isn't necessary for ReSharper users. 25 | 26 | I've tested this extension in one of my reasonably large projects (44 projects, 2000+ C# source files), and the extension should never impact the performance of the editor. Depending on the complexity of the current file (size, number of classes/methods, number of derived classes, etc), it may take several seconds for the glyphs to update after the file is opened or text is changed. During this time you should be able to work like normal. If you experience text editor slowdowns due to this extension, please [let us know](https://github.com/tunnelvisionlabs/InheritanceMargin/issues) and we'll work to correct it. 27 | -------------------------------------------------------------------------------- /Reference/Microsoft.CodeAnalysis.EditorFeatures.Text.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tunnelvisionlabs/InheritanceMargin/7c3ebf3d71d0185d8b6f74a4b4c1c99f3f9217e6/Reference/Microsoft.CodeAnalysis.EditorFeatures.Text.dll -------------------------------------------------------------------------------- /Reference/SharedKey.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tunnelvisionlabs/InheritanceMargin/7c3ebf3d71d0185d8b6f74a4b4c1c99f3f9217e6/Reference/SharedKey.snk -------------------------------------------------------------------------------- /TunnelVisionLabs.InheritanceMargin.ruleset: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin.CSharp.Legacy/CSharpInheritanceAnalyzer.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved. 2 | // Licensed under the MIT License. See LICENSE.txt in the project root for license information. 3 | 4 | namespace Tvl.VisualStudio.InheritanceMargin.CSharp 5 | { 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Linq; 9 | using System.Runtime.InteropServices; 10 | using System.Threading.Tasks; 11 | using Microsoft.RestrictedUsage.CSharp.Compiler; 12 | using Microsoft.RestrictedUsage.CSharp.Compiler.IDE; 13 | using Microsoft.RestrictedUsage.CSharp.Core; 14 | using Microsoft.RestrictedUsage.CSharp.Extensions; 15 | using Microsoft.RestrictedUsage.CSharp.Semantics; 16 | using Microsoft.RestrictedUsage.CSharp.Syntax; 17 | using Microsoft.VisualStudio.Shell; 18 | using Microsoft.VisualStudio.Text; 19 | using Microsoft.VisualStudio.Text.Editor; 20 | using Microsoft.VisualStudio.Text.Tagging; 21 | using Tvl.VisualStudio.OutputWindow.Interfaces; 22 | using CSRPOSDATA = Microsoft.VisualStudio.CSharp.Services.Language.Interop.CSRPOSDATA; 23 | using ICSharpTextBuffer = Microsoft.VisualStudio.CSharp.Services.Language.Interop.ICSharpTextBuffer; 24 | using ILangService = Microsoft.VisualStudio.CSharp.Services.Language.Interop.ILangService; 25 | using IProject = Microsoft.VisualStudio.CSharp.Services.Language.Interop.IProject; 26 | using Stopwatch = System.Diagnostics.Stopwatch; 27 | using StringBuilder = System.Text.StringBuilder; 28 | 29 | internal class CSharpInheritanceAnalyzer : BackgroundParser 30 | { 31 | private readonly SVsServiceProvider _serviceProvider; 32 | private readonly IInheritanceTagFactory _tagFactory; 33 | 34 | public CSharpInheritanceAnalyzer(ITextView textView, ITextBuffer textBuffer, TaskScheduler taskScheduler, ITextDocumentFactoryService textDocumentFactoryService, IOutputWindowService outputWindowService, SVsServiceProvider serviceProvider, IInheritanceTagFactory tagFactory) 35 | : base(textBuffer, taskScheduler, textDocumentFactoryService, outputWindowService) 36 | { 37 | if (serviceProvider == null) 38 | throw new ArgumentNullException("serviceProvider"); 39 | 40 | _serviceProvider = serviceProvider; 41 | _tagFactory = tagFactory; 42 | textView.Closed += (sender, e) => Dispose(); 43 | } 44 | 45 | /// 46 | public override string Name 47 | { 48 | get 49 | { 50 | return "C# Inheritance Analyzer"; 51 | } 52 | } 53 | 54 | [DllImport("CSLangSvc.dll", PreserveSig = false)] 55 | internal static extern void LangService_GetInstance(out ILangService langService); 56 | 57 | public static Tuple ResolveMemberIdentifier(IEnumerable projectList, CSharpMemberIdentifier memberId) 58 | { 59 | return Resolve(projectList, project => project.ResolveMemberIdentifier(memberId), memberId.AssemblyIdentifier); 60 | } 61 | 62 | public static Tuple ResolveTypeIdentifier(IEnumerable projectList, CSharpTypeIdentifier typeId) 63 | { 64 | return Resolve(projectList, project => project.ResolveTypeIdentifier(typeId), typeId.AssemblyIdentifier); 65 | } 66 | 67 | public static Tuple Resolve(IEnumerable compilations, Func resolver, CSharpAssemblyIdentifier definingAssembly) 68 | where T : class 69 | { 70 | Compilation compilation = null; 71 | T result = default(T); 72 | foreach (Compilation c in compilations) 73 | { 74 | T t = resolver(c); 75 | if (t != null) 76 | { 77 | result = t; 78 | compilation = c; 79 | } 80 | 81 | if (c.MainAssembly.SymbolicIdentifier.Equals(definingAssembly)) 82 | { 83 | return Tuple.Create(t, c); 84 | } 85 | } 86 | 87 | if (compilation != null && result != null) 88 | { 89 | return Tuple.Create(result, compilation); 90 | } 91 | 92 | return null; 93 | } 94 | 95 | public static void NavigateToType(CSharpTypeIdentifier typeIdentifier) 96 | { 97 | bool result = false; 98 | try 99 | { 100 | CSharpType currentType = ResolveType(typeIdentifier); 101 | if (currentType == null) 102 | return; 103 | 104 | var sourceLocations = currentType.SourceLocations; 105 | if (sourceLocations == null || sourceLocations.Count == 0) 106 | return; 107 | 108 | var location = sourceLocations[0]; 109 | if (location.FileName == null || !location.Position.IsValid) 110 | return; 111 | 112 | CSRPOSDATA position = new CSRPOSDATA() 113 | { 114 | LineIndex = location.Position.Line, 115 | ColumnIndex = location.Position.Character 116 | }; 117 | 118 | ILangService languageService; 119 | CSharpInheritanceAnalyzer.LangService_GetInstance(out languageService); 120 | if (languageService == null) 121 | return; 122 | 123 | IProject project = null; 124 | languageService.OpenSourceFile(project, location.FileName.Value, position); 125 | } 126 | catch (ApplicationException) 127 | { 128 | ////_callHierarchy.LanguageService.DisplayErrorMessage(exception.Message); 129 | return; 130 | } 131 | catch (InvalidOperationException) 132 | { 133 | ////this._callHierarchy.LanguageService.DisplayErrorMessage(exception2.Message); 134 | return; 135 | } 136 | 137 | if (!result) 138 | { 139 | ////NativeMessageId.Create(this._callHierarchy.LanguageService, jrc_StringResource_identifiers.IDS_HIDDEN_DEFINITION, new object[0]).DisplayError(this._callHierarchy.LanguageService); 140 | } 141 | } 142 | 143 | public static void NavigateToMember(CSharpMemberIdentifier memberIdentifier) 144 | { 145 | bool result = false; 146 | try 147 | { 148 | CSharpMember currentMember = ResolveMember(memberIdentifier); 149 | if (currentMember == null) 150 | return; 151 | 152 | var sourceLocations = currentMember.SourceLocations; 153 | if (sourceLocations == null || sourceLocations.Count == 0) 154 | return; 155 | 156 | var location = sourceLocations[0]; 157 | if (location.FileName == null || !location.Position.IsValid) 158 | return; 159 | 160 | CSRPOSDATA position = new CSRPOSDATA() 161 | { 162 | LineIndex = location.Position.Line, 163 | ColumnIndex = location.Position.Character 164 | }; 165 | 166 | ILangService languageService; 167 | CSharpInheritanceAnalyzer.LangService_GetInstance(out languageService); 168 | if (languageService == null) 169 | return; 170 | 171 | IProject project = null; 172 | languageService.OpenSourceFile(project, location.FileName.Value, position); 173 | } 174 | catch (ApplicationException) 175 | { 176 | ////_callHierarchy.LanguageService.DisplayErrorMessage(exception.Message); 177 | return; 178 | } 179 | catch (InvalidOperationException) 180 | { 181 | ////this._callHierarchy.LanguageService.DisplayErrorMessage(exception2.Message); 182 | return; 183 | } 184 | 185 | if (!result) 186 | { 187 | ////NativeMessageId.Create(this._callHierarchy.LanguageService, jrc_StringResource_identifiers.IDS_HIDDEN_DEFINITION, new object[0]).DisplayError(this._callHierarchy.LanguageService); 188 | } 189 | } 190 | 191 | private static CSharpType ResolveType(CSharpTypeIdentifier memberIdentifier) 192 | { 193 | IDECompilerHost host = new IDECompilerHost(); 194 | var currentCompilations = host.Compilers.Select(i => i.GetCompilation()).ToList(); 195 | var resolved = ResolveTypeIdentifier(currentCompilations, memberIdentifier); 196 | if (resolved != null) 197 | return resolved.Item1; 198 | 199 | return null; 200 | } 201 | 202 | private static CSharpMember ResolveMember(CSharpMemberIdentifier memberIdentifier) 203 | { 204 | IDECompilerHost host = new IDECompilerHost(); 205 | var currentCompilations = host.Compilers.Select(i => i.GetCompilation()).ToList(); 206 | var resolved = ResolveMemberIdentifier(currentCompilations, memberIdentifier); 207 | if (resolved != null) 208 | return resolved.Item1; 209 | 210 | return null; 211 | } 212 | 213 | /// 214 | /// If is a , this method selects 215 | /// all children of . Otherwise, 216 | /// this method returns a collection containing itself. 217 | /// 218 | /// The node. 219 | /// 220 | /// If is a , this method returns 221 | /// . Otherwise, this method returns 222 | /// a collection containing itself. 223 | /// 224 | private static IEnumerable SelectDeclaratorsFromFields(ParseTreeNode node) 225 | { 226 | FieldDeclarationNode fieldDeclarationNode = node as FieldDeclarationNode; 227 | if (fieldDeclarationNode == null) 228 | return Enumerable.Repeat(node, 1); 229 | 230 | return fieldDeclarationNode.VariableDeclarators; 231 | } 232 | 233 | /// 234 | protected override void ReParseImpl() 235 | { 236 | Stopwatch stopwatch = Stopwatch.StartNew(); 237 | 238 | ITextSnapshot snapshot = TextBuffer.CurrentSnapshot; 239 | 240 | try 241 | { 242 | ITextDocument textDocument = TextDocument; 243 | string fileName = textDocument != null ? textDocument.FilePath : null; 244 | IDECompilerHost host = new IDECompilerHost(); 245 | IProject project = null; 246 | 247 | ILangService languageService; 248 | LangService_GetInstance(out languageService); 249 | if (languageService != null) 250 | { 251 | ICSharpTextBuffer csharpBuffer = languageService.FindTextBuffer(fileName); 252 | if (csharpBuffer != null) 253 | project = csharpBuffer.Project; 254 | } 255 | 256 | List> tags = new List>(); 257 | 258 | if (host != null && project != null && !string.IsNullOrEmpty(fileName)) 259 | { 260 | Compilation compilation = host.CreateCompiler(project).GetCompilation(); 261 | SourceFile sourceFile; 262 | if (!compilation.SourceFiles.TryGetValue(new FileName(fileName), out sourceFile)) 263 | { 264 | InheritanceParseResultEventArgs errorResult = new InheritanceParseResultEventArgs(snapshot, stopwatch.Elapsed, tags); 265 | OnParseComplete(errorResult); 266 | return; 267 | } 268 | 269 | ParseTree parseTree = sourceFile.GetParseTree(); 270 | 271 | SpecializedMatchingMemberCollector collector = new SpecializedMatchingMemberCollector(host.Compilers.Select(i => i.GetCompilation()), false); 272 | 273 | IEnumerable nodes = SelectTypes(parseTree); 274 | foreach (var node in nodes) 275 | { 276 | CSharpType type = null; 277 | 278 | type = compilation.GetTypeFromTypeDeclaration(node); 279 | if (type == null) 280 | { 281 | MarkDirty(true); 282 | return; 283 | } 284 | 285 | if (type.IsSealed) 286 | continue; 287 | 288 | // types which implement or derive from this type 289 | ISet derivedClasses = collector.GetDerivedTypes(type.SymbolicIdentifier); 290 | 291 | if (derivedClasses.Count == 0) 292 | continue; 293 | 294 | StringBuilder builder = new StringBuilder(); 295 | string elementKindDisplayName = 296 | "types"; 297 | 298 | builder.AppendLine("Derived " + elementKindDisplayName + ":"); 299 | foreach (var derived in derivedClasses) 300 | builder.AppendLine(" " + derived.GetFullTypeName()); 301 | 302 | int nameIndex = node.Token; 303 | Token token = parseTree.LexData.Tokens[nameIndex]; 304 | ITextSnapshotLine line = snapshot.GetLineFromLineNumber(token.StartPosition.Line); 305 | SnapshotSpan span = new SnapshotSpan(snapshot, new Span(line.Start + token.StartPosition.Character, token.EndPosition.Character - token.StartPosition.Character)); 306 | 307 | InheritanceGlyph tag = type.IsInterface ? InheritanceGlyph.HasImplementations : InheritanceGlyph.Overridden; 308 | 309 | var targets = derivedClasses.Select(i => new TypeTarget(i.GetFullTypeName(), i.SymbolicIdentifier)); 310 | tags.Add(new TagSpan(span, _tagFactory.CreateTag(tag, builder.ToString().TrimEnd(), targets))); 311 | } 312 | 313 | nodes = parseTree.SelectMethodsPropertiesAndFields(); 314 | nodes = nodes.SelectMany(SelectDeclaratorsFromFields); 315 | foreach (var node in nodes) 316 | { 317 | if (node is AccessorDeclarationNode) 318 | { 319 | // these nodes always result in an ArgumentException in GetMemberFromMemberDeclaration 320 | continue; 321 | } 322 | 323 | CSharpMember member; 324 | try 325 | { 326 | member = compilation.GetMemberFromMemberDeclaration(node); 327 | } 328 | catch (ArgumentException) 329 | { 330 | continue; 331 | } 332 | 333 | if (member == null) 334 | { 335 | MarkDirty(true); 336 | return; 337 | } 338 | 339 | if (!SpecializedMatchingMemberCollector.IsSupportedMemberType(member)) 340 | continue; 341 | 342 | // methods which this method implements 343 | ISet implementedMethods = collector.GetImplementedInterfaceMembers(member.SymbolicIdentifier); 344 | 345 | // methods which this method overrides 346 | ISet overriddenMethods = collector.GetOverriddenBaseMembers(member.SymbolicIdentifier); 347 | 348 | // methods which override this method 349 | ISet overridingMethods = collector.GetOverridersFromDerivedTypes(member.SymbolicIdentifier); 350 | 351 | // methods which implement this method 352 | ISet implementingMethods = collector.GetImplementorsForInterfaceMember(member.SymbolicIdentifier); 353 | 354 | if (implementingMethods.Count == 0 && implementedMethods.Count == 0 && overriddenMethods.Count == 0 && overridingMethods.Count == 0) 355 | continue; 356 | 357 | StringBuilder builder = new StringBuilder(); 358 | string elementKindDisplayName = 359 | member.IsProperty ? "properties" : 360 | member.IsEvent ? "events" : 361 | "methods"; 362 | 363 | if (implementedMethods.Count > 0) 364 | { 365 | builder.AppendLine("Implemented " + elementKindDisplayName + ":"); 366 | foreach (var methodId in implementedMethods) 367 | builder.AppendLine(" " + methodId.ToString()); 368 | } 369 | 370 | if (overriddenMethods.Count > 0) 371 | { 372 | builder.AppendLine("Overridden " + elementKindDisplayName + ":"); 373 | foreach (var methodId in overriddenMethods) 374 | builder.AppendLine(" " + methodId.ToString()); 375 | } 376 | 377 | if (implementingMethods.Count > 0) 378 | { 379 | builder.AppendLine("Implementing " + elementKindDisplayName + " in derived types:"); 380 | foreach (var methodId in implementingMethods) 381 | builder.AppendLine(" " + methodId.ToString()); 382 | } 383 | 384 | if (overridingMethods.Count > 0) 385 | { 386 | builder.AppendLine("Overriding " + elementKindDisplayName + " in derived types:"); 387 | foreach (var methodId in overridingMethods) 388 | builder.AppendLine(" " + methodId.ToString()); 389 | } 390 | 391 | int nameIndex = node.Token; 392 | Token token = parseTree.LexData.Tokens[nameIndex]; 393 | ITextSnapshotLine line = snapshot.GetLineFromLineNumber(token.StartPosition.Line); 394 | SnapshotSpan span = new SnapshotSpan(snapshot, new Span(line.Start + token.StartPosition.Character, token.EndPosition.Character - token.StartPosition.Character)); 395 | 396 | InheritanceGlyph tag; 397 | if (implementedMethods.Count > 0) 398 | { 399 | if (overridingMethods.Count > 0) 400 | tag = InheritanceGlyph.ImplementsAndOverridden; 401 | else if (implementingMethods.Count > 0) 402 | tag = InheritanceGlyph.ImplementsAndHasImplementations; 403 | else 404 | tag = InheritanceGlyph.Implements; 405 | } 406 | else if (implementingMethods.Count > 0) 407 | { 408 | tag = InheritanceGlyph.HasImplementations; 409 | } 410 | else if (overriddenMethods.Count > 0) 411 | { 412 | if (overridingMethods.Count > 0) 413 | tag = InheritanceGlyph.OverridesAndOverridden; 414 | else 415 | tag = InheritanceGlyph.Overrides; 416 | } 417 | else 418 | { 419 | tag = InheritanceGlyph.Overridden; 420 | } 421 | 422 | List members = new List(); 423 | members.AddRange(implementedMethods); 424 | members.AddRange(overriddenMethods); 425 | members.AddRange(implementingMethods); 426 | members.AddRange(overridingMethods); 427 | 428 | var targets = members.Select(i => new MemberTarget(i)); 429 | tags.Add(new TagSpan(span, _tagFactory.CreateTag(tag, builder.ToString().TrimEnd(), targets))); 430 | } 431 | } 432 | 433 | InheritanceParseResultEventArgs result = new InheritanceParseResultEventArgs(snapshot, stopwatch.Elapsed, tags); 434 | OnParseComplete(result); 435 | } 436 | catch (InvalidOperationException) 437 | { 438 | MarkDirty(true); 439 | throw; 440 | } 441 | } 442 | 443 | private IEnumerable SelectTypes(ParseTree parseTree) 444 | { 445 | if (parseTree == null) 446 | return Enumerable.Empty(); 447 | 448 | return new TypeCollector(parseTree.RootNode); 449 | } 450 | 451 | private IEnumerable FindHideBySigMethod(CSharpType type, CSharpMember member, bool checkBaseTypes, bool includeInheritedInterfaces) 452 | { 453 | List results = new List(); 454 | FindHideBySigMethod(results, type, member, checkBaseTypes, includeInheritedInterfaces); 455 | return results; 456 | } 457 | 458 | private void FindHideBySigMethod(List results, CSharpType type, CSharpMember member, bool checkBaseTypes, bool includeInheritedInterfaces) 459 | { 460 | foreach (var potential in type.Members) 461 | { 462 | if (!member.IsSameSignature(potential)) 463 | continue; 464 | 465 | results.Add(potential); 466 | } 467 | 468 | if (checkBaseTypes) 469 | { 470 | CSharpType baseType = type.BaseClass; 471 | if (baseType != null) 472 | FindHideBySigMethod(results, baseType, member, checkBaseTypes, includeInheritedInterfaces); 473 | } 474 | 475 | if (includeInheritedInterfaces) 476 | { 477 | IList interfaces = type.BaseInterfaces; 478 | if (interfaces != null) 479 | { 480 | foreach (CSharpType interfaceType in interfaces.OfType()) 481 | FindHideBySigMethod(results, interfaceType, member, checkBaseTypes, includeInheritedInterfaces); 482 | } 483 | } 484 | } 485 | 486 | private List GetTypeDeclarationNodes(ParseTree parseTree) 487 | { 488 | TypeDeclarationNodeSelector collector = new TypeDeclarationNodeSelector(); 489 | collector.Visit(parseTree.RootNode); 490 | return collector.Nodes; 491 | } 492 | } 493 | } 494 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin.CSharp.Legacy/CSharpMemberIdentifierEqualityComparer.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved. 2 | // Licensed under the MIT License. See LICENSE.txt in the project root for license information. 3 | 4 | namespace Tvl.VisualStudio.InheritanceMargin.CSharp 5 | { 6 | using System.Collections.Generic; 7 | using Microsoft.RestrictedUsage.CSharp.Semantics; 8 | 9 | internal class CSharpMemberIdentifierEqualityComparer : IEqualityComparer 10 | { 11 | /// 12 | public bool Equals(CSharpMemberIdentifier left, CSharpMemberIdentifier right) 13 | { 14 | if (object.ReferenceEquals(left, right)) 15 | return true; 16 | 17 | if (object.ReferenceEquals(left, null) || object.ReferenceEquals(right, null)) 18 | return false; 19 | 20 | return left.Equals(right); 21 | } 22 | 23 | /// 24 | public int GetHashCode(CSharpMemberIdentifier identifier) 25 | { 26 | return identifier.GetHashCode(); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin.CSharp.Legacy/MemberTarget.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved. 2 | // Licensed under the MIT License. See LICENSE.txt in the project root for license information. 3 | 4 | namespace Tvl.VisualStudio.InheritanceMargin.CSharp 5 | { 6 | using Microsoft.RestrictedUsage.CSharp.Semantics; 7 | 8 | internal sealed class MemberTarget : IInheritanceTarget 9 | { 10 | private readonly CSharpMemberIdentifier _memberIdentifier; 11 | 12 | public MemberTarget(CSharpMemberIdentifier memberIdentifier) 13 | { 14 | _memberIdentifier = memberIdentifier; 15 | } 16 | 17 | /// 18 | public string DisplayName 19 | { 20 | get 21 | { 22 | return _memberIdentifier.ToString(); 23 | } 24 | } 25 | 26 | /// 27 | public void NavigateTo() 28 | { 29 | CSharpInheritanceAnalyzer.NavigateToMember(_memberIdentifier); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin.CSharp.Legacy/RoslynMemberTarget.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved. 2 | // Licensed under the MIT License. See LICENSE.txt in the project root for license information. 3 | 4 | #if ROSLYN 5 | 6 | namespace Tvl.VisualStudio.InheritanceMargin.CSharp 7 | { 8 | using Microsoft.CodeAnalysis; 9 | using Microsoft.CodeAnalysis.Text; 10 | 11 | internal sealed class MemberTarget : IInheritanceTarget 12 | { 13 | private readonly SourceTextContainer _textContainer; 14 | private readonly ISymbol _memberIdentifier; 15 | private readonly Project _project; 16 | private readonly Solution _solution; 17 | 18 | public MemberTarget(SourceTextContainer textContainer, ISymbol memberIdentifier, Project project, Solution solution) 19 | { 20 | _textContainer = textContainer; 21 | _memberIdentifier = memberIdentifier; 22 | _project = project; 23 | _solution = solution; 24 | } 25 | 26 | public string DisplayName 27 | { 28 | get 29 | { 30 | return _memberIdentifier.ToString(); 31 | } 32 | } 33 | 34 | public void NavigateTo() 35 | { 36 | CSharpInheritanceAnalyzer.NavigateToSymbol(_textContainer, _memberIdentifier, _project); 37 | } 38 | } 39 | } 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin.CSharp.Legacy/RoslynTypeTarget.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved. 2 | // Licensed under the MIT License. See LICENSE.txt in the project root for license information. 3 | 4 | #if ROSLYN 5 | 6 | namespace Tvl.VisualStudio.InheritanceMargin.CSharp 7 | { 8 | using Microsoft.CodeAnalysis; 9 | using Microsoft.CodeAnalysis.Text; 10 | 11 | internal sealed class TypeTarget : IInheritanceTarget 12 | { 13 | private readonly SourceTextContainer _textContainer; 14 | private readonly ISymbol _typeIdentifier; 15 | private readonly Solution _solution; 16 | 17 | public TypeTarget(SourceTextContainer textContainer, ISymbol typeIdentifier, Solution solution) 18 | { 19 | _textContainer = textContainer; 20 | _typeIdentifier = typeIdentifier; 21 | _solution = solution; 22 | } 23 | 24 | public string DisplayName 25 | { 26 | get 27 | { 28 | return _typeIdentifier.ToString(); 29 | } 30 | } 31 | 32 | public void NavigateTo() 33 | { 34 | CSharpInheritanceAnalyzer.NavigateToSymbol(_textContainer, _typeIdentifier, _solution.GetProject(_typeIdentifier.ContainingAssembly)); 35 | } 36 | } 37 | } 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin.CSharp.Legacy/SpecializedMatchingMemberCollector.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved. 2 | // Licensed under the MIT License. See LICENSE.txt in the project root for license information. 3 | 4 | namespace Tvl.VisualStudio.InheritanceMargin.CSharp 5 | { 6 | using System.Collections.Generic; 7 | using Microsoft.RestrictedUsage.CSharp.Compiler; 8 | using Microsoft.RestrictedUsage.CSharp.Semantics; 9 | using Microsoft.RestrictedUsage.CSharp.Utilities; 10 | using Microsoft.VisualStudio.CSharp.Services.Language.Refactoring; 11 | 12 | internal class SpecializedMatchingMemberCollector : MatchingMemberCollector 13 | { 14 | public SpecializedMatchingMemberCollector(IEnumerable allProjects, bool searchOverloads) 15 | : base(allProjects, searchOverloads) 16 | { 17 | } 18 | 19 | public static new bool IsSupportedMemberType(CSharpMember member) 20 | { 21 | return MatchingMemberCollector.IsSupportedMemberType(member); 22 | } 23 | 24 | public ISet GetImplementedInterfaceMembers(CSharpMemberIdentifier memberId) 25 | { 26 | CSharpMember member = CSharpInheritanceAnalyzer.ResolveMemberIdentifier(AllProjects, memberId).Item1; 27 | ISet resultList = CreateHashSet(new CSharpMemberIdentifierEqualityComparer()); 28 | if (!IsSupportedMemberType(member)) 29 | return resultList; 30 | 31 | AddImplementedInterfaceMembers(member, resultList); 32 | return resultList; 33 | } 34 | 35 | public ISet GetImplementorsForInterfaceMember(CSharpMemberIdentifier memberId) 36 | { 37 | CSharpMember member = CSharpInheritanceAnalyzer.ResolveMemberIdentifier(AllProjects, memberId).Item1; 38 | ISet resultList = CreateHashSet(new CSharpMemberIdentifierEqualityComparer()); 39 | if (!IsSupportedMemberType(member)) 40 | return resultList; 41 | 42 | AddImplementorsForInterfaceMember(member, resultList); 43 | return resultList; 44 | } 45 | 46 | public ISet GetOverriddenBaseMembers(CSharpMemberIdentifier memberId) 47 | { 48 | CSharpMember member = CSharpInheritanceAnalyzer.ResolveMemberIdentifier(AllProjects, memberId).Item1; 49 | ISet resultList = CreateHashSet(new CSharpMemberIdentifierEqualityComparer()); 50 | if (!IsSupportedMemberType(member)) 51 | return resultList; 52 | 53 | AddOverridenBaseMembers(member, resultList); 54 | return resultList; 55 | } 56 | 57 | public ISet GetOverridersFromDerivedTypes(CSharpMemberIdentifier memberId) 58 | { 59 | CSharpMember member = CSharpInheritanceAnalyzer.ResolveMemberIdentifier(AllProjects, memberId).Item1; 60 | ISet resultList = CreateHashSet(new CSharpMemberIdentifierEqualityComparer()); 61 | if (!IsSupportedMemberType(member)) 62 | return resultList; 63 | 64 | AddVirtualOverridersFromDerivedTypes(member, resultList); 65 | return resultList; 66 | } 67 | 68 | public ISet GetDerivedTypes(CSharpTypeIdentifier typeId) 69 | { 70 | ISet result = new HashSet(); 71 | foreach (Compilation compilation in AllProjects) 72 | { 73 | CSharpType baseType = compilation.ResolveTypeIdentifier(typeId); 74 | if (baseType == null) 75 | continue; 76 | 77 | BaseTypeCollector collector = baseType.IsInterface ? GetBaseInterfaceCollector() : GetBaseClassCollector(); 78 | foreach (CSharpType type in compilation.MainAssembly.Types) 79 | { 80 | // an interface can't be derived from a class 81 | if (type.IsInterface && !baseType.IsInterface) 82 | continue; 83 | 84 | var baseTypes = collector.GetBaseTypes(type); 85 | if (baseType.TypeParameters != null && baseType.TypeParameters.Count > 0) 86 | { 87 | foreach (var candidate in baseTypes) 88 | { 89 | if (Equals(baseType, candidate.DefiningType)) 90 | { 91 | result.Add(type); 92 | break; 93 | } 94 | } 95 | } 96 | else 97 | { 98 | if (baseTypes.Contains(baseType)) 99 | result.Add(type); 100 | } 101 | } 102 | } 103 | 104 | return result; 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin.CSharp.Legacy/Tvl.VisualStudio.InheritanceMargin.CSharp.11.0.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | obj\vs2012\ 5 | obj\vs2012\ 6 | 7 | 8 | 9 | 10 | 11 | net45 12 | Tvl.VisualStudio.InheritanceMargin.CSharp 13 | 14 | bin\vs2012\$(Configuration)\ 15 | $(DefaultItemExcludes);obj/vs2013/** 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin.CSharp.Legacy/Tvl.VisualStudio.InheritanceMargin.CSharp.12.0.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | obj\vs2013\ 5 | obj\vs2013\ 6 | 7 | 8 | 9 | 10 | 11 | net45 12 | Tvl.VisualStudio.InheritanceMargin.CSharp 13 | 14 | bin\vs2013\$(Configuration)\ 15 | $(DefaultItemExcludes);obj/vs2012/** 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin.CSharp.Legacy/TypeCollector.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved. 2 | // Licensed under the MIT License. See LICENSE.txt in the project root for license information. 3 | 4 | namespace Tvl.VisualStudio.InheritanceMargin.CSharp 5 | { 6 | using System.Collections.Generic; 7 | using Microsoft.RestrictedUsage.CSharp.Syntax; 8 | using IEnumerable = System.Collections.IEnumerable; 9 | using IEnumerator = System.Collections.IEnumerator; 10 | 11 | internal class TypeCollector : ParseTreeVisitor, IEnumerable 12 | { 13 | private readonly List _nodes = new List(); 14 | 15 | public TypeCollector(ParseTreeNode node) 16 | { 17 | Visit(node); 18 | } 19 | 20 | /// 21 | public IEnumerator GetEnumerator() 22 | { 23 | return _nodes.GetEnumerator(); 24 | } 25 | 26 | /// 27 | IEnumerator IEnumerable.GetEnumerator() 28 | { 29 | return GetEnumerator(); 30 | } 31 | 32 | /// 33 | public override bool TraverseInteriorTree(ParseTreeNode node) 34 | { 35 | return false; 36 | } 37 | 38 | /// 39 | public override void VisitAccessorDeclarationNode(AccessorDeclarationNode node) 40 | { 41 | // Types cannot be declared in an accessor, so we stop here 42 | } 43 | 44 | /// 45 | public override void VisitConstructorDeclarationNode(ConstructorDeclarationNode node) 46 | { 47 | // Types cannot be declared in a constructor, so we stop here 48 | } 49 | 50 | /// 51 | public override void VisitDelegateDeclarationNode(DelegateDeclarationNode node) 52 | { 53 | } 54 | 55 | /// 56 | public override void VisitEnumMemberDeclarationNode(EnumMemberDeclarationNode node) 57 | { 58 | } 59 | 60 | /// 61 | public override void VisitFieldDeclarationNode(FieldDeclarationNode node) 62 | { 63 | } 64 | 65 | /// 66 | public override void VisitMemberDeclarationNode(MemberDeclarationNode node) 67 | { 68 | } 69 | 70 | /// 71 | public override void VisitMethodDeclarationNode(MethodDeclarationNode node) 72 | { 73 | } 74 | 75 | /// 76 | public override void VisitNamespaceDeclarationNode(NamespaceDeclarationNode node) 77 | { 78 | VisitList(node.NamespaceMemberDeclarations); 79 | } 80 | 81 | /// 82 | public override void VisitNestedTypeDeclarationNode(NestedTypeDeclarationNode node) 83 | { 84 | Visit(node.Type); 85 | } 86 | 87 | /// 88 | public override void VisitOperatorDeclarationNode(OperatorDeclarationNode node) 89 | { 90 | } 91 | 92 | /// 93 | public override void VisitParseTreeNode(ParseTreeNode node) 94 | { 95 | } 96 | 97 | /// 98 | public override void VisitPropertyDeclarationNode(PropertyDeclarationNode node) 99 | { 100 | } 101 | 102 | /// 103 | public override void VisitTypeDeclarationNode(TypeDeclarationNode node) 104 | { 105 | _nodes.Add(node); 106 | 107 | for (MemberDeclarationNode node2 = node.MemberDeclarations; node2 != null; node2 = node2.Next) 108 | { 109 | Visit(node2); 110 | } 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin.CSharp.Legacy/TypeDeclarationNodeSelector.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved. 2 | // Licensed under the MIT License. See LICENSE.txt in the project root for license information. 3 | 4 | namespace Tvl.VisualStudio.InheritanceMargin.CSharp 5 | { 6 | using System.Collections.Generic; 7 | using Microsoft.RestrictedUsage.CSharp.Syntax; 8 | 9 | internal class TypeDeclarationNodeSelector : ParseTreeVisitor 10 | { 11 | private readonly List _nodes = new List(); 12 | 13 | public List Nodes 14 | { 15 | get 16 | { 17 | return _nodes; 18 | } 19 | } 20 | 21 | /// 22 | public override bool TraverseInteriorTree(ParseTreeNode node) 23 | { 24 | return false; 25 | } 26 | 27 | /// 28 | public override void VisitTypeDeclarationNode(TypeDeclarationNode node) 29 | { 30 | _nodes.Add(node); 31 | base.VisitTypeDeclarationNode(node); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin.CSharp.Legacy/TypeTarget.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved. 2 | // Licensed under the MIT License. See LICENSE.txt in the project root for license information. 3 | 4 | namespace Tvl.VisualStudio.InheritanceMargin.CSharp 5 | { 6 | using Microsoft.RestrictedUsage.CSharp.Semantics; 7 | 8 | internal sealed class TypeTarget : IInheritanceTarget 9 | { 10 | private readonly string _displayName; 11 | private readonly CSharpTypeIdentifier _typeIdentifier; 12 | 13 | public TypeTarget(string displayName, CSharpTypeIdentifier typeIdentifier) 14 | { 15 | _displayName = displayName; 16 | _typeIdentifier = typeIdentifier; 17 | } 18 | 19 | /// 20 | public string DisplayName 21 | { 22 | get 23 | { 24 | return _displayName; 25 | } 26 | } 27 | 28 | /// 29 | public void NavigateTo() 30 | { 31 | CSharpInheritanceAnalyzer.NavigateToType(_typeIdentifier); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin.CSharp/AbstractTarget.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved. 2 | // Licensed under the MIT License. See LICENSE.txt in the project root for license information. 3 | 4 | namespace Tvl.VisualStudio.InheritanceMargin.CSharp 5 | { 6 | using System.Collections.Generic; 7 | using System.Collections.Immutable; 8 | using Microsoft.CodeAnalysis; 9 | using Microsoft.CodeAnalysis.Text; 10 | 11 | internal abstract class AbstractTarget : IInheritanceTarget 12 | { 13 | private readonly SourceTextContainer _textContainer; 14 | private readonly ProjectId _projectId; 15 | private readonly string _displayName; 16 | private readonly KeyValuePair[] _symbolPath; 17 | 18 | protected AbstractTarget(SourceTextContainer textContainer, Project currentProject, Solution solution, ISymbol symbol) 19 | { 20 | Project project = solution.GetProject(symbol.ContainingAssembly) ?? currentProject; 21 | 22 | _textContainer = textContainer; 23 | _projectId = project.Id; 24 | _displayName = symbol.ToString(); 25 | 26 | List> symbolPath = new List>(); 27 | for (ISymbol currentSymbol = symbol.OriginalDefinition; currentSymbol != null; currentSymbol = currentSymbol.ContainingSymbol) 28 | { 29 | ImmutableArray parameters = default(ImmutableArray); 30 | ImmutableArray typeParameters = default(ImmutableArray); 31 | switch (currentSymbol.Kind) 32 | { 33 | case SymbolKind.Method: 34 | parameters = ((IMethodSymbol)currentSymbol).Parameters; 35 | typeParameters = ((IMethodSymbol)currentSymbol).TypeParameters; 36 | break; 37 | 38 | case SymbolKind.Property: 39 | parameters = ((IPropertySymbol)currentSymbol).Parameters; 40 | break; 41 | 42 | default: 43 | break; 44 | } 45 | 46 | if (!parameters.IsDefaultOrEmpty) 47 | { 48 | for (int i = parameters.Length - 1; i >= 0; i--) 49 | { 50 | symbolPath.Add(new KeyValuePair(SymbolKind.Parameter, parameters[i].ToString())); 51 | } 52 | } 53 | 54 | if (currentSymbol.Kind == SymbolKind.Namespace && ((INamespaceSymbol)currentSymbol).IsGlobalNamespace) 55 | break; 56 | 57 | if (currentSymbol.Kind == SymbolKind.NetModule || currentSymbol.Kind == SymbolKind.Assembly) 58 | break; 59 | 60 | string metadataName = currentSymbol.MetadataName; 61 | if (currentSymbol.Kind == SymbolKind.Method && !typeParameters.IsDefaultOrEmpty) 62 | metadataName = metadataName + '`' + typeParameters.Length; 63 | 64 | symbolPath.Add(new KeyValuePair(currentSymbol.Kind, metadataName)); 65 | } 66 | 67 | symbolPath.Reverse(); 68 | _symbolPath = symbolPath.ToArray(); 69 | } 70 | 71 | /// 72 | public string DisplayName 73 | { 74 | get 75 | { 76 | return _displayName; 77 | } 78 | } 79 | 80 | /// 81 | public void NavigateTo() 82 | { 83 | CSharpInheritanceAnalyzer.NavigateToSymbol(_textContainer, _projectId, _symbolPath); 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin.CSharp/BackgroundParser.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved. 2 | // Licensed under the MIT License. See LICENSE.txt in the project root for license information. 3 | 4 | namespace Tvl.VisualStudio.InheritanceMargin.CSharp 5 | { 6 | using System; 7 | using System.Diagnostics; 8 | using System.Threading; 9 | using System.Threading.Tasks; 10 | using Microsoft.VisualStudio.Text; 11 | using Tvl.VisualStudio.OutputWindow.Interfaces; 12 | using ErrorHandler = Microsoft.VisualStudio.ErrorHandler; 13 | using Path = System.IO.Path; 14 | using Timer = System.Threading.Timer; 15 | 16 | internal abstract class BackgroundParser : IInheritanceParser, IDisposable 17 | { 18 | private readonly WeakReference _textBuffer; 19 | private readonly TaskScheduler _taskScheduler; 20 | private readonly ITextDocumentFactoryService _textDocumentFactoryService; 21 | private readonly IOutputWindowService _outputWindowService; 22 | private readonly string _outputWindowName; 23 | private readonly Timer _timer; 24 | 25 | private TimeSpan _reparseDelay; 26 | private DateTimeOffset _lastEdit; 27 | private bool _dirty; 28 | private int _parsing; 29 | 30 | [Obsolete] 31 | public BackgroundParser(ITextBuffer textBuffer, ITextDocumentFactoryService textDocumentFactoryService, IOutputWindowService outputWindowService) 32 | : this(textBuffer, TaskScheduler.Default, textDocumentFactoryService, outputWindowService, PredefinedOutputWindowPanes.TvlDiagnostics) 33 | { 34 | } 35 | 36 | public BackgroundParser(ITextBuffer textBuffer, TaskScheduler taskScheduler, ITextDocumentFactoryService textDocumentFactoryService, IOutputWindowService outputWindowService) 37 | : this(textBuffer, taskScheduler, textDocumentFactoryService, outputWindowService, PredefinedOutputWindowPanes.TvlDiagnostics) 38 | { 39 | } 40 | 41 | public BackgroundParser(ITextBuffer textBuffer, TaskScheduler taskScheduler, ITextDocumentFactoryService textDocumentFactoryService, IOutputWindowService outputWindowService, string outputPaneName) 42 | { 43 | if (textBuffer == null) 44 | throw new ArgumentNullException("textBuffer"); 45 | if (taskScheduler == null) 46 | throw new ArgumentNullException("taskScheduler"); 47 | if (textDocumentFactoryService == null) 48 | throw new ArgumentNullException("textDocumentFactoryService"); 49 | if (outputWindowService == null) 50 | throw new ArgumentNullException("outputWindowService"); 51 | 52 | _textBuffer = new WeakReference(textBuffer); 53 | _taskScheduler = taskScheduler; 54 | _textDocumentFactoryService = textDocumentFactoryService; 55 | _outputWindowService = outputWindowService; 56 | _outputWindowName = outputPaneName; 57 | 58 | textBuffer.PostChanged += TextBufferPostChanged; 59 | 60 | _dirty = true; 61 | _reparseDelay = TimeSpan.FromMilliseconds(1500); 62 | _timer = new Timer(ParseTimerCallback, null, _reparseDelay, _reparseDelay); 63 | _lastEdit = DateTimeOffset.MinValue; 64 | } 65 | 66 | /// 67 | public event EventHandler ParseComplete; 68 | 69 | public ITextBuffer TextBuffer 70 | { 71 | get 72 | { 73 | return (ITextBuffer)_textBuffer.Target; 74 | } 75 | } 76 | 77 | public ITextDocument TextDocument 78 | { 79 | get 80 | { 81 | ITextBuffer textBuffer = TextBuffer; 82 | if (textBuffer == null) 83 | return null; 84 | 85 | ITextDocument textDocument; 86 | if (!TextDocumentFactoryService.TryGetTextDocument(textBuffer, out textDocument)) 87 | return null; 88 | 89 | return textDocument; 90 | } 91 | } 92 | 93 | public bool Disposed 94 | { 95 | get; 96 | private set; 97 | } 98 | 99 | public TimeSpan ReparseDelay 100 | { 101 | get 102 | { 103 | return _reparseDelay; 104 | } 105 | 106 | set 107 | { 108 | TimeSpan originalDelay = _reparseDelay; 109 | try 110 | { 111 | _reparseDelay = value; 112 | _timer.Change(value, value); 113 | } 114 | catch (ArgumentException) 115 | { 116 | _reparseDelay = originalDelay; 117 | } 118 | } 119 | } 120 | 121 | public virtual string Name 122 | { 123 | get 124 | { 125 | return string.Empty; 126 | } 127 | } 128 | 129 | protected ITextDocumentFactoryService TextDocumentFactoryService 130 | { 131 | get 132 | { 133 | return _textDocumentFactoryService; 134 | } 135 | } 136 | 137 | protected IOutputWindowService OutputWindowService 138 | { 139 | get 140 | { 141 | return _outputWindowService; 142 | } 143 | } 144 | 145 | /// 146 | public void Dispose() 147 | { 148 | Dispose(true); 149 | GC.SuppressFinalize(this); 150 | } 151 | 152 | /// 153 | public void RequestParse(bool forceReparse) 154 | { 155 | TryReparse(forceReparse); 156 | } 157 | 158 | protected virtual void Dispose(bool disposing) 159 | { 160 | if (disposing) 161 | { 162 | ITextBuffer textBuffer = TextBuffer; 163 | if (textBuffer != null) 164 | textBuffer.PostChanged -= TextBufferPostChanged; 165 | 166 | _timer.Dispose(); 167 | } 168 | 169 | Disposed = true; 170 | } 171 | 172 | protected abstract void ReParseImpl(); 173 | 174 | protected virtual void OnParseComplete(InheritanceParseResultEventArgs e) 175 | { 176 | if (e == null) 177 | throw new ArgumentNullException("e"); 178 | 179 | var t = ParseComplete; 180 | if (t != null) 181 | t(this, e); 182 | } 183 | 184 | protected void MarkDirty(bool resetTimer) 185 | { 186 | _dirty = true; 187 | _lastEdit = DateTimeOffset.Now; 188 | 189 | if (resetTimer) 190 | _timer.Change(_reparseDelay, _reparseDelay); 191 | } 192 | 193 | private void TextBufferPostChanged(object sender, EventArgs e) 194 | { 195 | MarkDirty(true); 196 | } 197 | 198 | private void ParseTimerCallback(object state) 199 | { 200 | if (TextBuffer == null) 201 | { 202 | Dispose(); 203 | return; 204 | } 205 | 206 | TryReparse(_dirty); 207 | } 208 | 209 | private void TryReparse(bool forceReparse) 210 | { 211 | if (!_dirty && !forceReparse) 212 | return; 213 | 214 | if (DateTimeOffset.Now - _lastEdit < TimeSpan.FromSeconds(2)) 215 | return; 216 | 217 | if (Interlocked.CompareExchange(ref _parsing, 1, 0) == 0) 218 | { 219 | try 220 | { 221 | Task task = Task.Factory.StartNew(ReParse, CancellationToken.None, TaskCreationOptions.LongRunning, _taskScheduler); 222 | task.ContinueWith(_ => _parsing = 0); 223 | } 224 | catch 225 | { 226 | _parsing = 0; 227 | throw; 228 | } 229 | } 230 | } 231 | 232 | private void ReParse() 233 | { 234 | try 235 | { 236 | _dirty = false; 237 | 238 | IOutputWindowPane outputWindow = null; 239 | if (_outputWindowService != null && !string.IsNullOrEmpty(_outputWindowName)) 240 | outputWindow = _outputWindowService.TryGetPane(_outputWindowName); 241 | 242 | Stopwatch stopwatch = Stopwatch.StartNew(); 243 | 244 | string message = "{0}: Background parse {1}{2} in {3}ms. {4}"; 245 | string name = Name; 246 | if (!string.IsNullOrEmpty(name)) 247 | name = "(" + name + ") "; 248 | 249 | string filename = ""; 250 | ITextDocument textDocument = TextDocument; 251 | if (textDocument != null) 252 | { 253 | filename = textDocument.FilePath; 254 | if (filename != null) 255 | filename = filename.Substring(filename.LastIndexOfAny(new char[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }) + 1); 256 | } 257 | 258 | try 259 | { 260 | ReParseImpl(); 261 | 262 | if (outputWindow != null) 263 | { 264 | long time = stopwatch.ElapsedMilliseconds; 265 | outputWindow.WriteLine(string.Format(message, filename, name, "succeeded", time, string.Empty)); 266 | } 267 | } 268 | catch (Exception e2) 269 | { 270 | if (ErrorHandler.IsCriticalException(e2)) 271 | throw; 272 | 273 | try 274 | { 275 | if (outputWindow != null) 276 | { 277 | long time = stopwatch.ElapsedMilliseconds; 278 | outputWindow.WriteLine(string.Format(message, filename, name, "failed", time, e2.Message + e2.StackTrace)); 279 | } 280 | } 281 | catch (Exception e3) 282 | { 283 | if (ErrorHandler.IsCriticalException(e3)) 284 | throw; 285 | } 286 | } 287 | } 288 | catch (Exception ex) 289 | { 290 | if (ErrorHandler.IsCriticalException(ex)) 291 | throw; 292 | } 293 | } 294 | } 295 | } 296 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin.CSharp/CSharpInheritanceAnalyzer.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved. 2 | // Licensed under the MIT License. See LICENSE.txt in the project root for license information. 3 | 4 | namespace Tvl.VisualStudio.InheritanceMargin.CSharp 5 | { 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Collections.Immutable; 9 | using System.Linq; 10 | using System.Reflection; 11 | using System.Threading; 12 | using System.Threading.Tasks; 13 | using Microsoft.CodeAnalysis; 14 | using Microsoft.CodeAnalysis.CSharp; 15 | using Microsoft.CodeAnalysis.CSharp.Syntax; 16 | using Microsoft.CodeAnalysis.FindSymbols; 17 | using Microsoft.CodeAnalysis.Text; 18 | using Microsoft.VisualStudio.LanguageServices; 19 | using Microsoft.VisualStudio.Text; 20 | using Microsoft.VisualStudio.Text.Editor; 21 | using Microsoft.VisualStudio.Text.Tagging; 22 | using Tvl.VisualStudio.OutputWindow.Interfaces; 23 | using Stopwatch = System.Diagnostics.Stopwatch; 24 | using StringBuilder = System.Text.StringBuilder; 25 | using SVsServiceProvider = Microsoft.VisualStudio.Shell.SVsServiceProvider; 26 | 27 | #if ROSLYN2 28 | using System.Linq.Expressions; 29 | using IEnumerable = System.Collections.IEnumerable; 30 | #endif 31 | 32 | internal class CSharpInheritanceAnalyzer : BackgroundParser 33 | { 34 | private static readonly Lazy DependentTypeFinder = new Lazy(() => typeof(SymbolFinder).Assembly.GetType("Microsoft.CodeAnalysis.FindSymbols.DependentTypeFinder")); 35 | 36 | private static readonly Lazy, CancellationToken, Task>>> FindDerivedClassesAsync = 37 | new Lazy, CancellationToken, Task>>>(() => 38 | { 39 | #if ROSLYN2 40 | return SymbolFinder.FindDerivedClassesAsync; 41 | #else 42 | // Assume we are using Roslyn 1.3... 43 | var methodInfo = DependentTypeFinder.Value.GetMethod( 44 | "FindTransitivelyDerivedClassesAsync", 45 | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, 46 | null, 47 | new[] { typeof(INamedTypeSymbol), typeof(Solution), typeof(IImmutableSet), typeof(CancellationToken) }, 48 | null); 49 | 50 | if (methodInfo == null) 51 | { 52 | // If we are wrong, try the Roslyn 1.0-1.2 method 53 | methodInfo = DependentTypeFinder.Value.GetMethod( 54 | "FindDerivedClassesAsync", 55 | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, 56 | null, 57 | new[] { typeof(INamedTypeSymbol), typeof(Solution), typeof(IImmutableSet), typeof(CancellationToken) }, 58 | null); 59 | } 60 | 61 | return (Func, CancellationToken, Task>>)Delegate.CreateDelegate(typeof(Func, CancellationToken, Task>>), methodInfo); 62 | #endif 63 | }); 64 | 65 | // Roslyn 1.0-1.1 66 | private static readonly Lazy FindDerivedInterfacesAsyncMethodInfo = 67 | new Lazy(() => DependentTypeFinder.Value.GetMethod( 68 | "FindDerivedInterfacesAsync", 69 | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, 70 | null, 71 | new[] { typeof(INamedTypeSymbol), typeof(Solution), typeof(IImmutableSet), typeof(CancellationToken) }, 72 | null)); 73 | 74 | // Roslyn 1.2 75 | private static readonly Lazy GetTypesImmediatelyDerivedFromInterfacesAsyncMethodInfo = 76 | new Lazy(() => DependentTypeFinder.Value.GetMethod( 77 | "GetTypesImmediatelyDerivedFromInterfacesAsync", 78 | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, 79 | null, 80 | new[] { typeof(INamedTypeSymbol), typeof(Solution), typeof(CancellationToken) }, 81 | null)); 82 | 83 | // Roslyn 1.3 84 | private static readonly Lazy FindImmediatelyDerivedAndImplementingTypesAsyncMethodInfo = 85 | new Lazy(() => DependentTypeFinder.Value.GetMethod( 86 | "FindImmediatelyDerivedAndImplementingTypesAsync", 87 | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, 88 | null, 89 | new[] { typeof(INamedTypeSymbol), typeof(Solution), typeof(CancellationToken) }, 90 | null)); 91 | 92 | // Roslyn 3.7-beta2 93 | private static readonly Lazy SymbolFinderFindDerivedInterfacesAsync = 94 | new Lazy(() => typeof(SymbolFinder).GetMethod( 95 | "FindDerivedInterfacesAsync", 96 | BindingFlags.Static | BindingFlags.Public, 97 | null, 98 | new[] { typeof(INamedTypeSymbol), typeof(Solution), typeof(IImmutableSet), typeof(CancellationToken) }, 99 | null)); 100 | 101 | /// 102 | /// Prior to Roslyn 1.2, DependentTypeFinder.FindDerivedInterfacesAsync can be used directly. In Roslyn 103 | /// 1.2, DependentTypeFinder.GetTypesImmediatelyDerivedFromInterfacesAsync must be used instead. In 104 | /// Roslyn 1.3, DependentTypeFinder.FindImmediatelyDerivedAndImplementingTypesAsync must be used instead. 105 | /// 106 | private static readonly Lazy, CancellationToken, Task>>> FindDerivedInterfacesAsync = 107 | new Lazy, CancellationToken, Task>>>(() => 108 | { 109 | #if ROSLYN2 110 | // Roslyn 3.7-beta2 switched to a new public API 111 | if (SymbolFinderFindDerivedInterfacesAsync.Value is MethodInfo symbolFinderMethod) 112 | { 113 | return (Func, CancellationToken, Task>>)Delegate.CreateDelegate(typeof(Func, CancellationToken, Task>>), symbolFinderMethod); 114 | } 115 | 116 | if (FindImmediatelyDerivedAndImplementingTypesAsyncMethodInfo.Value is MethodInfo method 117 | && method.ReturnType == typeof(Task>)) 118 | { 119 | // Roslyn 3.7-beta1 switched back to the form from Roslyn 1.3, with the exception of the return type. 120 | var immediatelyDerived = (Func>>)Delegate.CreateDelegate(typeof(Func>>), method); 121 | return (symbol, solution, projects, cancellationToken) => GetDerivedInterfacesFromImmediatelyDerivedAsync(symbol, solution, projects, immediatelyDerived, cancellationToken); 122 | } 123 | 124 | Func, CancellationToken, Task>> fallbackAccessor = 125 | (symbol, solution, projects, cancellationToken) => Task.FromResult(Enumerable.Empty()); 126 | 127 | Type symbolAndProjectIdT = DependentTypeFinder.Value.Assembly.GetType("Microsoft.CodeAnalysis.FindSymbols.SymbolAndProjectId`1", false, false); 128 | if (symbolAndProjectIdT == null) 129 | return fallbackAccessor; 130 | 131 | Type namedTypeSymbolAndProjectId = symbolAndProjectIdT.MakeGenericType(typeof(INamedTypeSymbol)); 132 | 133 | MethodInfo declaredMethodInfo = DependentTypeFinder.Value.GetMethod( 134 | "FindImmediatelyDerivedAndImplementingTypesAsync", 135 | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, 136 | null, 137 | new[] { typeof(INamedTypeSymbol), typeof(Solution), typeof(CancellationToken) }, 138 | null); 139 | 140 | ParameterExpression typeParameter = Expression.Parameter(typeof(INamedTypeSymbol), "type"); 141 | Expression typeParameterReference; 142 | if (declaredMethodInfo is object) 143 | { 144 | // Our argument matches the one expected by FindImmediatelyDerivedAndImplementingTypesAsync 145 | typeParameterReference = typeParameter; 146 | } 147 | else 148 | { 149 | // Roslyn 3.6 changed the first argument type 150 | declaredMethodInfo = DependentTypeFinder.Value.GetMethod( 151 | "FindImmediatelyDerivedAndImplementingTypesAsync", 152 | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, 153 | null, 154 | new[] { namedTypeSymbolAndProjectId, typeof(Solution), typeof(CancellationToken) }, 155 | null); 156 | if (declaredMethodInfo == null) 157 | return fallbackAccessor; 158 | 159 | typeParameterReference = Expression.New( 160 | namedTypeSymbolAndProjectId.GetConstructors().Single(), 161 | typeParameter, 162 | Expression.Convert(Expression.Constant(null), typeof(ProjectId))); 163 | } 164 | 165 | // Here we build up the actual call to FindDerivedAndImplementingTypesAsync 166 | ParameterExpression solutionParameter = Expression.Parameter(typeof(Solution), "solution"); 167 | ParameterExpression cancellationTokenParameter = Expression.Parameter(typeof(CancellationToken), "cancellationToken"); 168 | Func callAsync = 169 | Expression.Lambda>( 170 | Expression.Call( 171 | declaredMethodInfo, 172 | typeParameterReference, 173 | solutionParameter, 174 | cancellationTokenParameter), 175 | typeParameter, 176 | solutionParameter, 177 | cancellationTokenParameter) 178 | .Compile(); 179 | 180 | // The return type is Task>>. Here we build up a 181 | // method to get the task result, and a method which can extract the type symbol from a 182 | // SymbolAndProjectId. 183 | Type specificTaskType = typeof(Task<>).MakeGenericType(typeof(ImmutableArray<>).MakeGenericType(namedTypeSymbolAndProjectId)); 184 | PropertyInfo resultProperty = specificTaskType.GetProperty(nameof(Task.Result), BindingFlags.Public | BindingFlags.Instance); 185 | ParameterExpression taskParameter = Expression.Parameter(typeof(Task), "task"); 186 | Func readResult = 187 | Expression.Lambda>( 188 | Expression.Convert( 189 | Expression.Property(Expression.Convert(taskParameter, specificTaskType), resultProperty.GetMethod), 190 | typeof(IEnumerable)), 191 | taskParameter) 192 | .Compile(); 193 | 194 | FieldInfo symbolField = namedTypeSymbolAndProjectId.GetField("Symbol", BindingFlags.Public | BindingFlags.Instance); 195 | ParameterExpression symbolAndProjectIdParameter = Expression.Parameter(typeof(object), "symbolAndProjectId"); 196 | Func readSymbolField = 197 | Expression.Lambda>( 198 | Expression.Field( 199 | Expression.Convert(symbolAndProjectIdParameter, namedTypeSymbolAndProjectId), 200 | symbolField), 201 | symbolAndProjectIdParameter) 202 | .Compile(); 203 | 204 | Func>> immediatelyDerivedAsync = 205 | async (symbol, solution, cancellationToken) => 206 | { 207 | Task task = callAsync(symbol, solution, cancellationToken); 208 | await task.ConfigureAwait(false); 209 | 210 | // If we get here, the task completed successfully 211 | IEnumerable result = readResult(task); 212 | return result.Cast().Select(readSymbolField); 213 | }; 214 | 215 | return (symbol, solution, projects, cancellationToken) => 216 | { 217 | return GetDerivedInterfacesFromImmediatelyDerivedAsync(symbol, solution, projects, immediatelyDerivedAsync, cancellationToken); 218 | }; 219 | #else 220 | MethodInfo method = FindDerivedInterfacesAsyncMethodInfo.Value; 221 | if (method == null) 222 | { 223 | method = GetTypesImmediatelyDerivedFromInterfacesAsyncMethodInfo.Value; 224 | if (method == null) 225 | { 226 | method = FindImmediatelyDerivedAndImplementingTypesAsyncMethodInfo.Value; 227 | } 228 | 229 | var immediatelyDerived = (Func>>)Delegate.CreateDelegate(typeof(Func>>), method); 230 | return (symbol, solution, projects, cancellationToken) => GetDerivedInterfacesFromImmediatelyDerivedAsync(symbol, solution, projects, immediatelyDerived, cancellationToken); 231 | } 232 | 233 | return (Func, CancellationToken, Task>>)Delegate.CreateDelegate(typeof(Func, CancellationToken, Task>>), method); 234 | #endif 235 | }); 236 | 237 | private static readonly Lazy, CancellationToken, Task>>> FindImplementingTypesAsync = 238 | new Lazy, CancellationToken, Task>>>(() => 239 | { 240 | #if ROSLYN2 241 | return async (symbol, solution, projects, cancellationToken) => 242 | { 243 | var symbols = await SymbolFinder.FindImplementationsAsync(symbol, solution, projects, cancellationToken).ConfigureAwait(false); 244 | return symbols.OfType(); 245 | }; 246 | #else 247 | // Assume we are using Roslyn 1.3... 248 | var methodInfo = DependentTypeFinder.Value.GetMethod( 249 | "FindTransitivelyImplementingTypesAsync", 250 | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, 251 | null, 252 | new[] { typeof(INamedTypeSymbol), typeof(Solution), typeof(IImmutableSet), typeof(CancellationToken) }, 253 | null); 254 | 255 | if (methodInfo == null) 256 | { 257 | // If we are wrong, try the Roslyn 1.0-1.2 method 258 | methodInfo = DependentTypeFinder.Value.GetMethod( 259 | "FindImplementingTypesAsync", 260 | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, 261 | null, 262 | new[] { typeof(INamedTypeSymbol), typeof(Solution), typeof(IImmutableSet), typeof(CancellationToken) }, 263 | null); 264 | } 265 | 266 | return (Func, CancellationToken, Task>>)Delegate.CreateDelegate(typeof(Func, CancellationToken, Task>>), methodInfo); 267 | #endif 268 | }); 269 | 270 | private readonly SVsServiceProvider _serviceProvider; 271 | private readonly IInheritanceTagFactory _tagFactory; 272 | 273 | public CSharpInheritanceAnalyzer(ITextView textView, ITextBuffer textBuffer, TaskScheduler taskScheduler, ITextDocumentFactoryService textDocumentFactoryService, IOutputWindowService outputWindowService, SVsServiceProvider serviceProvider, IInheritanceTagFactory tagFactory) 274 | : base(textBuffer, taskScheduler, textDocumentFactoryService, outputWindowService) 275 | { 276 | if (serviceProvider == null) 277 | throw new ArgumentNullException("serviceProvider"); 278 | 279 | _serviceProvider = serviceProvider; 280 | _tagFactory = tagFactory; 281 | textView.Closed += (sender, e) => Dispose(); 282 | } 283 | 284 | /// 285 | public override string Name 286 | { 287 | get 288 | { 289 | return "C# Inheritance Analyzer"; 290 | } 291 | } 292 | 293 | public static void NavigateToSymbol(SourceTextContainer textContainer, ProjectId projectId, KeyValuePair[] symbolPath) 294 | { 295 | Workspace workspace; 296 | if (!Workspace.TryGetWorkspace(textContainer, out workspace)) 297 | return; 298 | 299 | VisualStudioWorkspace visualStudioWorkspace = workspace as VisualStudioWorkspace; 300 | if (visualStudioWorkspace == null) 301 | return; 302 | 303 | var project = visualStudioWorkspace.CurrentSolution.GetProject(projectId); 304 | if (project == null) 305 | return; 306 | 307 | var compilation = project.GetCompilationAsync(CancellationToken.None).GetAwaiter().GetResult(); 308 | if (compilation == null) 309 | return; 310 | 311 | ImmutableArray currentSymbols = ImmutableArray.Create(compilation.GlobalNamespace); 312 | int firstParameterIndex = symbolPath.Length; 313 | for (int i = 0; i < symbolPath.Length; i++) 314 | { 315 | bool complete = false; 316 | var pair = symbolPath[i]; 317 | switch (pair.Key) 318 | { 319 | case SymbolKind.Namespace: 320 | // The current symbols must be namespaces 321 | currentSymbols = currentSymbols.SelectMany(currentSymbol => ((INamespaceSymbol)currentSymbol).GetNamespaceMembers().Where(ns => ns.Name == pair.Value)).Select(ns => (ISymbol)ns).ToImmutableArray(); 322 | continue; 323 | 324 | case SymbolKind.NamedType: 325 | // The current symbol must be a namespaces or types 326 | GetNameAndArity(pair.Value, out string typeName, out int arity); 327 | currentSymbols = currentSymbols.SelectMany(currentSymbol => ((INamespaceOrTypeSymbol)currentSymbol).GetTypeMembers(typeName, arity)).Select(sym => (ISymbol)sym).ToImmutableArray(); 328 | continue; 329 | 330 | case SymbolKind.Property: 331 | case SymbolKind.Event: 332 | currentSymbols = currentSymbols.SelectMany(currentSymbol => ((INamedTypeSymbol)currentSymbol).GetMembers().Where(sym => sym.Kind == pair.Key && sym.MetadataName == pair.Value)).ToImmutableArray(); 333 | firstParameterIndex = i + 1; 334 | complete = true; 335 | break; 336 | 337 | case SymbolKind.Method: 338 | GetNameAndArity(pair.Value, out string memberName, out arity); 339 | currentSymbols = currentSymbols.SelectMany(currentSymbol => ((INamedTypeSymbol)currentSymbol).GetMembers().Where(sym => sym.MetadataName == memberName && ((IMethodSymbol)sym).Arity == arity && sym.Kind == pair.Key)).ToImmutableArray(); 340 | firstParameterIndex = i + 1; 341 | complete = true; 342 | break; 343 | 344 | default: 345 | return; 346 | } 347 | 348 | if (complete) 349 | break; 350 | } 351 | 352 | if (firstParameterIndex < symbolPath.Length) 353 | { 354 | string[] parameters = symbolPath.Skip(firstParameterIndex).Select(pair => pair.Value).ToArray(); 355 | Func matchesSignature = 356 | sym => 357 | { 358 | ImmutableArray parameterSymbols; 359 | switch (sym.Kind) 360 | { 361 | case SymbolKind.Property: 362 | parameterSymbols = ((IPropertySymbol)sym).Parameters; 363 | break; 364 | 365 | case SymbolKind.Method: 366 | parameterSymbols = ((IMethodSymbol)sym).Parameters; 367 | break; 368 | 369 | default: 370 | return false; 371 | } 372 | 373 | if (parameterSymbols.Length != parameters.Length) 374 | return false; 375 | 376 | for (int i = 0; i < parameters.Length; i++) 377 | { 378 | if (parameterSymbols[i].ToString() != parameters[i]) 379 | return false; 380 | } 381 | 382 | return true; 383 | }; 384 | 385 | currentSymbols = currentSymbols.Where(matchesSignature).ToImmutableArray(); 386 | } 387 | 388 | ISymbol symbol = currentSymbols.FirstOrDefault(); 389 | if (symbol == null) 390 | return; 391 | 392 | visualStudioWorkspace.TryGoToDefinition(symbol, project, CancellationToken.None); 393 | } 394 | 395 | private static void GetNameAndArity(string metadataName, out string typeName, out int arity) 396 | { 397 | int backtick = metadataName.IndexOf('`'); 398 | if (backtick == -1) 399 | { 400 | typeName = metadataName; 401 | arity = 0; 402 | return; 403 | } 404 | 405 | arity = int.Parse(metadataName.Substring(backtick + 1)); 406 | typeName = metadataName.Substring(0, backtick); 407 | } 408 | 409 | private static async Task> GetDerivedInterfacesFromImmediatelyDerivedAsync( 410 | INamedTypeSymbol type, 411 | Solution solution, 412 | IImmutableSet projects, 413 | Func> immediatelyDerivedAsync, 414 | CancellationToken cancellationToken) 415 | where TNamedTypeSymbolCollection : IEnumerable 416 | { 417 | if (type.TypeKind != TypeKind.Interface) 418 | { 419 | return Enumerable.Empty(); 420 | } 421 | 422 | type = type.OriginalDefinition; 423 | 424 | var result = ImmutableArray.CreateBuilder(); 425 | HashSet visited = new HashSet(); 426 | visited.Add(type); 427 | Queue workList = new Queue(); 428 | workList.Enqueue(type); 429 | while (workList.Count > 0) 430 | { 431 | INamedTypeSymbol current = workList.Dequeue(); 432 | foreach (INamedTypeSymbol derived in await immediatelyDerivedAsync(current, solution, cancellationToken).ConfigureAwait(false)) 433 | { 434 | if (derived.TypeKind != TypeKind.Interface) 435 | continue; 436 | 437 | INamedTypeSymbol original = derived.OriginalDefinition; 438 | if (!visited.Add(original)) 439 | continue; 440 | 441 | result.Add(original); 442 | workList.Enqueue(original); 443 | } 444 | } 445 | 446 | return result.ToImmutable(); 447 | } 448 | 449 | /// 450 | protected override void ReParseImpl() 451 | { 452 | Stopwatch stopwatch = Stopwatch.StartNew(); 453 | 454 | ITextSnapshot snapshot = TextBuffer.CurrentSnapshot; 455 | 456 | try 457 | { 458 | ITextDocument textDocument = TextDocument; 459 | string fileName = textDocument != null ? textDocument.FilePath : null; 460 | Document document = snapshot.GetOpenDocumentInCurrentContextWithChanges(); 461 | SourceTextContainer textContainer = document != null ? document.GetTextAsync().Result.Container : null; 462 | Project project = document != null ? document.Project : null; 463 | Solution solution = project != null ? project.Solution : null; 464 | 465 | List> tags = new List>(); 466 | 467 | if (document != null && !string.IsNullOrEmpty(fileName)) 468 | { 469 | SyntaxTree syntaxTree = document.GetSyntaxTreeAsync().Result; 470 | SyntaxNode syntaxRoot = syntaxTree.GetRoot(); 471 | SemanticModel semanticModel = document.GetSemanticModelAsync().Result; 472 | Compilation compilation = semanticModel.Compilation; 473 | 474 | IDictionary> interfaceImplementations = new Dictionary>(); 475 | 476 | List allMembers = new List(); 477 | IEnumerable typeNodes = syntaxRoot.DescendantNodes().OfType(); 478 | foreach (var typeNode in typeNodes) 479 | { 480 | ISymbol symbol = semanticModel.GetDeclaredSymbol(typeNode); 481 | if (symbol == null) 482 | { 483 | MarkDirty(true); 484 | return; 485 | } 486 | 487 | INamedTypeSymbol typeSymbol = symbol as INamedTypeSymbol; 488 | if (typeSymbol == null) 489 | continue; 490 | 491 | // get implemented interface symbols 492 | foreach (INamedTypeSymbol namedTypeSymbol in typeSymbol.AllInterfaces) 493 | { 494 | foreach (ISymbol member in namedTypeSymbol.GetMembers()) 495 | { 496 | ISymbol implementation = typeSymbol.FindImplementationForInterfaceMember(member); 497 | if (implementation == null || !implementation.ContainingSymbol.Equals(typeSymbol)) 498 | continue; 499 | 500 | ISet symbols; 501 | if (!interfaceImplementations.TryGetValue(implementation, out symbols)) 502 | { 503 | symbols = new HashSet(); 504 | interfaceImplementations[implementation] = symbols; 505 | } 506 | 507 | symbols.Add(member); 508 | } 509 | } 510 | 511 | TypeDeclarationSyntax typeDeclarationSyntax = typeNode as TypeDeclarationSyntax; 512 | if (typeDeclarationSyntax != null) 513 | allMembers.AddRange(typeDeclarationSyntax.Members); 514 | 515 | if (typeSymbol.IsSealed) 516 | continue; 517 | 518 | // types which implement or derive from this type 519 | ISet derivedTypes = new HashSet(); 520 | derivedTypes.UnionWith(FindDerivedClassesAsync.Value(typeSymbol, solution, null, CancellationToken.None).Result); 521 | derivedTypes.UnionWith(FindDerivedInterfacesAsync.Value(typeSymbol, solution, null, CancellationToken.None).Result); 522 | derivedTypes.UnionWith(FindImplementingTypesAsync.Value(typeSymbol, solution, null, CancellationToken.None).Result); 523 | 524 | if (derivedTypes.Count == 0) 525 | continue; 526 | 527 | StringBuilder builder = new StringBuilder(); 528 | string elementKindDisplayName = 529 | "types"; 530 | 531 | builder.AppendLine("Derived " + elementKindDisplayName + ":"); 532 | foreach (var derived in derivedTypes) 533 | builder.AppendLine(" " + derived.ToString()); 534 | 535 | SyntaxToken identifier = typeNode.Accept(IdentifierSyntaxVisitor.Instance); 536 | SnapshotSpan span = new SnapshotSpan(snapshot, new Span(identifier.SpanStart, identifier.Span.Length)); 537 | 538 | InheritanceGlyph tag = typeSymbol.TypeKind == TypeKind.Interface ? InheritanceGlyph.HasImplementations : InheritanceGlyph.Overridden; 539 | 540 | var targets = derivedTypes.Select(i => new TypeTarget(textContainer, project, solution, i)); 541 | tags.Add(new TagSpan(span, _tagFactory.CreateTag(tag, builder.ToString().TrimEnd(), targets))); 542 | } 543 | 544 | foreach (var eventFieldDeclarationSyntax in allMembers.OfType().ToArray()) 545 | allMembers.AddRange(eventFieldDeclarationSyntax.Declaration.Variables); 546 | 547 | foreach (CSharpSyntaxNode memberNode in allMembers) 548 | { 549 | if (!(memberNode is MethodDeclarationSyntax) 550 | && !(memberNode is PropertyDeclarationSyntax) 551 | && !(memberNode is IndexerDeclarationSyntax) 552 | && !(memberNode is EventDeclarationSyntax) 553 | && !(memberNode is VariableDeclaratorSyntax)) 554 | { 555 | continue; 556 | } 557 | 558 | ISymbol symbol = semanticModel.GetDeclaredSymbol(memberNode); 559 | if (symbol == null) 560 | { 561 | MarkDirty(true); 562 | return; 563 | } 564 | 565 | // members which this member implements 566 | ISet implementedMethods = new HashSet(); 567 | if (!interfaceImplementations.TryGetValue(symbol, out implementedMethods)) 568 | implementedMethods = new HashSet(); 569 | 570 | ISet overriddenMethods = new HashSet(); 571 | 572 | IMethodSymbol methodSymbol = symbol as IMethodSymbol; 573 | if (methodSymbol != null) 574 | { 575 | // methods which this method overrides 576 | for (IMethodSymbol current = methodSymbol.OverriddenMethod; 577 | current != null; 578 | current = current.OverriddenMethod) 579 | { 580 | overriddenMethods.Add(current); 581 | } 582 | } 583 | else 584 | { 585 | IPropertySymbol propertySymbol = symbol as IPropertySymbol; 586 | if (propertySymbol != null) 587 | { 588 | // properties which this property overrides 589 | for (IPropertySymbol current = propertySymbol.OverriddenProperty; 590 | current != null; 591 | current = current.OverriddenProperty) 592 | { 593 | overriddenMethods.Add(current); 594 | } 595 | } 596 | else 597 | { 598 | IEventSymbol eventSymbol = symbol as IEventSymbol; 599 | if (eventSymbol != null) 600 | { 601 | // events which this event overrides 602 | for (IEventSymbol current = eventSymbol.OverriddenEvent; 603 | current != null; 604 | current = current.OverriddenEvent) 605 | { 606 | overriddenMethods.Add(current); 607 | } 608 | } 609 | } 610 | } 611 | 612 | ISet implementingMethods = new HashSet(SymbolFinder.FindImplementationsAsync(symbol, solution).Result); 613 | 614 | ISet overridingMethods = new HashSet(SymbolFinder.FindOverridesAsync(symbol, solution).Result); 615 | 616 | if (implementingMethods.Count == 0 && implementedMethods.Count == 0 && overriddenMethods.Count == 0 && overridingMethods.Count == 0) 617 | continue; 618 | 619 | StringBuilder builder = new StringBuilder(); 620 | string elementKindDisplayName = 621 | symbol is IPropertySymbol ? "properties" : 622 | symbol is IEventSymbol ? "events" : 623 | "methods"; 624 | 625 | if (implementedMethods.Count > 0) 626 | { 627 | builder.AppendLine("Implemented " + elementKindDisplayName + ":"); 628 | foreach (var methodId in implementedMethods) 629 | builder.AppendLine(" " + methodId.ToString()); 630 | } 631 | 632 | if (overriddenMethods.Count > 0) 633 | { 634 | builder.AppendLine("Overridden " + elementKindDisplayName + ":"); 635 | foreach (var methodId in overriddenMethods) 636 | builder.AppendLine(" " + methodId.ToString()); 637 | } 638 | 639 | if (implementingMethods.Count > 0) 640 | { 641 | builder.AppendLine("Implementing " + elementKindDisplayName + " in derived types:"); 642 | foreach (var methodId in implementingMethods) 643 | builder.AppendLine(" " + methodId.ToString()); 644 | } 645 | 646 | if (overridingMethods.Count > 0) 647 | { 648 | builder.AppendLine("Overriding " + elementKindDisplayName + " in derived types:"); 649 | foreach (var methodId in overridingMethods) 650 | builder.AppendLine(" " + methodId.ToString()); 651 | } 652 | 653 | SyntaxToken identifier = memberNode.Accept(IdentifierSyntaxVisitor.Instance); 654 | SnapshotSpan span = new SnapshotSpan(snapshot, new Span(identifier.SpanStart, identifier.Span.Length)); 655 | 656 | InheritanceGlyph tag; 657 | if (implementedMethods.Count > 0) 658 | { 659 | if (overridingMethods.Count > 0) 660 | tag = InheritanceGlyph.ImplementsAndOverridden; 661 | else if (implementingMethods.Count > 0) 662 | tag = InheritanceGlyph.ImplementsAndHasImplementations; 663 | else 664 | tag = InheritanceGlyph.Implements; 665 | } 666 | else if (implementingMethods.Count > 0) 667 | { 668 | tag = InheritanceGlyph.HasImplementations; 669 | } 670 | else if (overriddenMethods.Count > 0) 671 | { 672 | if (overridingMethods.Count > 0) 673 | tag = InheritanceGlyph.OverridesAndOverridden; 674 | else 675 | tag = InheritanceGlyph.Overrides; 676 | } 677 | else 678 | { 679 | tag = InheritanceGlyph.Overridden; 680 | } 681 | 682 | List members = new List(); 683 | members.AddRange(implementedMethods); 684 | members.AddRange(overriddenMethods); 685 | members.AddRange(implementingMethods); 686 | members.AddRange(overridingMethods); 687 | 688 | var targets = members.Select(i => new MemberTarget(textContainer, project, solution, i)); 689 | tags.Add(new TagSpan(span, _tagFactory.CreateTag(tag, builder.ToString().TrimEnd(), targets))); 690 | } 691 | } 692 | 693 | InheritanceParseResultEventArgs result = new InheritanceParseResultEventArgs(snapshot, stopwatch.Elapsed, tags); 694 | OnParseComplete(result); 695 | } 696 | catch (InvalidOperationException) 697 | { 698 | MarkDirty(true); 699 | throw; 700 | } 701 | } 702 | 703 | private class IdentifierSyntaxVisitor : CSharpSyntaxVisitor 704 | { 705 | public static readonly IdentifierSyntaxVisitor Instance = new IdentifierSyntaxVisitor(); 706 | 707 | private IdentifierSyntaxVisitor() 708 | { 709 | } 710 | 711 | public override SyntaxToken VisitClassDeclaration(ClassDeclarationSyntax node) 712 | { 713 | return node.Identifier; 714 | } 715 | 716 | public override SyntaxToken VisitConstructorDeclaration(ConstructorDeclarationSyntax node) 717 | { 718 | return node.Identifier; 719 | } 720 | 721 | public override SyntaxToken VisitDelegateDeclaration(DelegateDeclarationSyntax node) 722 | { 723 | return node.Identifier; 724 | } 725 | 726 | public override SyntaxToken VisitDestructorDeclaration(DestructorDeclarationSyntax node) 727 | { 728 | return node.Identifier; 729 | } 730 | 731 | public override SyntaxToken VisitEnumDeclaration(EnumDeclarationSyntax node) 732 | { 733 | return node.Identifier; 734 | } 735 | 736 | public override SyntaxToken VisitEnumMemberDeclaration(EnumMemberDeclarationSyntax node) 737 | { 738 | return node.Identifier; 739 | } 740 | 741 | public override SyntaxToken VisitEventDeclaration(EventDeclarationSyntax node) 742 | { 743 | return node.Identifier; 744 | } 745 | 746 | public override SyntaxToken VisitIndexerDeclaration(IndexerDeclarationSyntax node) 747 | { 748 | return node.ThisKeyword; 749 | } 750 | 751 | public override SyntaxToken VisitInterfaceDeclaration(InterfaceDeclarationSyntax node) 752 | { 753 | return node.Identifier; 754 | } 755 | 756 | public override SyntaxToken VisitMethodDeclaration(MethodDeclarationSyntax node) 757 | { 758 | return node.Identifier; 759 | } 760 | 761 | public override SyntaxToken VisitOperatorDeclaration(OperatorDeclarationSyntax node) 762 | { 763 | return node.OperatorToken; 764 | } 765 | 766 | public override SyntaxToken VisitPropertyDeclaration(PropertyDeclarationSyntax node) 767 | { 768 | return node.Identifier; 769 | } 770 | 771 | public override SyntaxToken VisitStructDeclaration(StructDeclarationSyntax node) 772 | { 773 | return node.Identifier; 774 | } 775 | 776 | public override SyntaxToken VisitVariableDeclarator(VariableDeclaratorSyntax node) 777 | { 778 | return node.Identifier; 779 | } 780 | } 781 | } 782 | } 783 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin.CSharp/MemberTarget.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved. 2 | // Licensed under the MIT License. See LICENSE.txt in the project root for license information. 3 | 4 | namespace Tvl.VisualStudio.InheritanceMargin.CSharp 5 | { 6 | using Microsoft.CodeAnalysis; 7 | using Microsoft.CodeAnalysis.Text; 8 | 9 | internal sealed class MemberTarget : AbstractTarget 10 | { 11 | public MemberTarget(SourceTextContainer textContainer, Project currentProject, Solution solution, ISymbol symbol) 12 | : base(textContainer, currentProject, solution, symbol) 13 | { 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin.CSharp/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved. 2 | // Licensed under the MIT License. See LICENSE.txt in the project root for license information. 3 | 4 | using System; 5 | using System.Reflection; 6 | using System.Runtime.InteropServices; 7 | 8 | // General Information about an assembly is controlled through the following 9 | // set of attributes. Change these attribute values to modify the information 10 | // associated with an assembly. 11 | [assembly: AssemblyDescription("")] 12 | [assembly: AssemblyTrademark("")] 13 | [assembly: AssemblyCulture("")] 14 | [assembly: CLSCompliant(false)] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("a46b4e51-f0ca-4486-af3a-197a5111e5f6")] 23 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin.CSharp/Tvl.VisualStudio.InheritanceMargin.CSharp.14.0.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | obj\vs2015\ 5 | obj\vs2015\ 6 | 7 | 8 | 9 | 10 | 11 | net45 12 | Tvl.VisualStudio.InheritanceMargin.CSharp 13 | 14 | bin\vs2015\$(Configuration)\ 15 | $(DefaultItemExcludes);obj/vs2013.roslyn/**;obj/vs2017/**;obj/vs2019/**;obj/vs17/** 16 | 17 | 18 | 19 | $(DefineConstants);ROSLYN 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin.CSharp/Tvl.VisualStudio.InheritanceMargin.CSharp.15.0.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | obj\vs2017\ 5 | obj\vs2017\ 6 | 7 | 8 | 9 | 10 | 11 | net46 12 | Tvl.VisualStudio.InheritanceMargin.CSharp 13 | 14 | bin\vs2017\$(Configuration)\ 15 | $(DefaultItemExcludes);obj/vs2013.roslyn/**;obj/vs2015/**;obj/vs2019/**;obj/vs17/** 16 | 17 | 18 | 19 | $(DefineConstants);ROSLYN;ROSLYN2 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin.CSharp/Tvl.VisualStudio.InheritanceMargin.CSharp.16.0.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | obj\vs2019\ 5 | obj\vs2019\ 6 | 7 | 8 | 9 | 10 | 11 | net46 12 | Tvl.VisualStudio.InheritanceMargin.CSharp 13 | 14 | bin\vs2019\$(Configuration)\ 15 | $(DefaultItemExcludes);obj/vs2013.roslyn/**;obj/vs2015/**;obj/vs2017/**;obj/vs17/** 16 | 17 | 18 | 19 | $(DefineConstants);ROSLYN;ROSLYN2 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin.CSharp/Tvl.VisualStudio.InheritanceMargin.CSharp.17.0.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | obj\vs17\ 5 | obj\vs17\ 6 | 7 | 8 | 9 | 10 | 11 | net46 12 | Tvl.VisualStudio.InheritanceMargin.CSharp 13 | 14 | bin\vs17\$(Configuration)\ 15 | $(DefaultItemExcludes);obj/vs2013.roslyn/**;obj/vs2015/**;obj/vs2017/**;obj/vs2019/** 16 | 17 | 18 | 19 | $(DefineConstants);ROSLYN;ROSLYN2 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin.CSharp/Tvl.VisualStudio.InheritanceMargin.CSharp.Roslyn.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | obj\vs2013.roslyn\ 5 | obj\vs2013.roslyn\ 6 | 7 | 8 | 9 | 10 | 11 | net45 12 | Tvl.VisualStudio.InheritanceMargin.CSharp 13 | 14 | bin\vs2013.roslyn\$(Configuration)\ 15 | $(DefaultItemExcludes);obj/vs2015/**;obj/vs2017/**;obj/vs2019/**;obj/vs17/** 16 | 17 | 18 | 19 | $(DefineConstants);ROSLYN 20 | 21 | 22 | 23 | 24 | ..\Reference\Microsoft.CodeAnalysis.EditorFeatures.Text.dll 25 | False 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin.CSharp/TypeTarget.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved. 2 | // Licensed under the MIT License. See LICENSE.txt in the project root for license information. 3 | 4 | namespace Tvl.VisualStudio.InheritanceMargin.CSharp 5 | { 6 | using Microsoft.CodeAnalysis; 7 | using Microsoft.CodeAnalysis.Text; 8 | 9 | internal sealed class TypeTarget : AbstractTarget 10 | { 11 | public TypeTarget(SourceTextContainer textContainer, Project currentProject, Solution solution, ISymbol symbol) 12 | : base(textContainer, currentProject, solution, symbol) 13 | { 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin.Interfaces/IInheritanceParser.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved. 2 | // Licensed under the MIT License. See LICENSE.txt in the project root for license information. 3 | 4 | namespace Tvl.VisualStudio.InheritanceMargin 5 | { 6 | using System; 7 | 8 | /// 9 | /// Defines the common interface by which the Visual Studio extension interacts with the various inheritance 10 | /// relation analysis implementations which each target a specific version of Visual Studio. 11 | /// 12 | public interface IInheritanceParser 13 | { 14 | /// 15 | /// Raised after a background inheritance parse operation completes. 16 | /// 17 | event EventHandler ParseComplete; 18 | 19 | /// 20 | /// Requests a background parse operation. 21 | /// 22 | /// to request a new parse result even if the content of the 23 | /// document has not changed; otherwise, . 24 | void RequestParse(bool forceReparse); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin.Interfaces/IInheritanceTag.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved. 2 | // Licensed under the MIT License. See LICENSE.txt in the project root for license information. 3 | 4 | namespace Tvl.VisualStudio.InheritanceMargin 5 | { 6 | using Microsoft.VisualStudio.Text.Editor; 7 | 8 | /// 9 | /// A tag representing an inheritance relation in code. 10 | /// 11 | public interface IInheritanceTag : IGlyphTag 12 | { 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin.Interfaces/IInheritanceTagFactory.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved. 2 | // Licensed under the MIT License. See LICENSE.txt in the project root for license information. 3 | 4 | namespace Tvl.VisualStudio.InheritanceMargin 5 | { 6 | using System.Collections.Generic; 7 | 8 | /// 9 | /// Represents a factory that can create inheritance tags for particular inheritance relations. 10 | /// 11 | public interface IInheritanceTagFactory 12 | { 13 | /// 14 | /// Create an inheritance tag representing a particular inheritance relation. 15 | /// 16 | /// The glyph for this inheritance relation. 17 | /// The text to display in the tool tip for the glyph. 18 | /// A collection of targets of this inheritance relation. 19 | /// An representing the inheritance relation. 20 | IInheritanceTag CreateTag(InheritanceGlyph glyph, string tooltip, IEnumerable targets); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin.Interfaces/IInheritanceTarget.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved. 2 | // Licensed under the MIT License. See LICENSE.txt in the project root for license information. 3 | 4 | namespace Tvl.VisualStudio.InheritanceMargin 5 | { 6 | /// 7 | /// Represents the target of an inheritance relation. 8 | /// 9 | public interface IInheritanceTarget 10 | { 11 | /// 12 | /// Gets the display name of the target of the inheritance relation. 13 | /// 14 | /// 15 | /// The display name of the target of the inheritance relation. 16 | /// 17 | string DisplayName 18 | { 19 | get; 20 | } 21 | 22 | /// 23 | /// Navigates to the target of the inheritance relation. 24 | /// 25 | void NavigateTo(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin.Interfaces/InheritanceGlyph.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved. 2 | // Licensed under the MIT License. See LICENSE.txt in the project root for license information. 3 | 4 | namespace Tvl.VisualStudio.InheritanceMargin 5 | { 6 | /// 7 | /// Identifies the glyph shown in the inheritance margin for a particular inheritance relation. 8 | /// 9 | public enum InheritanceGlyph 10 | { 11 | /// 12 | /// No inheritance relation is present, or the inheritance relation does not fit into one of the other glyphs. 13 | /// 14 | None, 15 | 16 | /// 17 | /// The type or member is implemented elsewhere. 18 | /// 19 | HasImplementations, 20 | 21 | /// 22 | /// The member implements an interface member which is defined elsewhere. 23 | /// 24 | Implements, 25 | 26 | /// 27 | /// The member implements an interface member which is defined elsewhere, and is also itself implemented 28 | /// elsewhere. 29 | /// 30 | ImplementsAndHasImplementations, 31 | 32 | /// 33 | /// The member implements an interface member, and is also itself overridden elsewhere. 34 | /// 35 | ImplementsAndOverridden, 36 | 37 | /// 38 | /// The member is overridden elsewhere. 39 | /// 40 | Overridden, 41 | 42 | /// 43 | /// The member overrides a member of a base type. 44 | /// 45 | Overrides, 46 | 47 | /// 48 | /// The member overrides a member of a base type, and is also itself overridden elsewhere. 49 | /// 50 | OverridesAndOverridden, 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin.Interfaces/InheritanceParseResultEventArgs.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved. 2 | // Licensed under the MIT License. See LICENSE.txt in the project root for license information. 3 | 4 | namespace Tvl.VisualStudio.InheritanceMargin 5 | { 6 | using System; 7 | using System.Collections.Generic; 8 | using Microsoft.VisualStudio.Text; 9 | using Microsoft.VisualStudio.Text.Tagging; 10 | 11 | /// 12 | /// Represents the result of a background parse operation which collections information about type and member 13 | /// inheritance. 14 | /// 15 | public class InheritanceParseResultEventArgs : EventArgs 16 | { 17 | private readonly ITextSnapshot _snapshot; 18 | private readonly TimeSpan _elapsedTime; 19 | private readonly IEnumerable> _tags; 20 | 21 | /// 22 | /// Initializes a new instance of the class. 23 | /// 24 | /// The snapshot which was analyzed. 25 | /// The total time taken to analyze the snapshot. 26 | /// A collection of inheritance tags collected for the snapshot. 27 | public InheritanceParseResultEventArgs(ITextSnapshot snapshot, TimeSpan elapsedTime, IEnumerable> tags) 28 | { 29 | _snapshot = snapshot; 30 | _elapsedTime = elapsedTime; 31 | _tags = tags; 32 | } 33 | 34 | /// 35 | /// Gets the text snapshot which was analyzed. 36 | /// 37 | /// 38 | /// The which was analyzed. 39 | /// 40 | public ITextSnapshot Snapshot 41 | { 42 | get 43 | { 44 | return _snapshot; 45 | } 46 | } 47 | 48 | /// 49 | /// Gets the total time taken to analyze the snapshot. 50 | /// 51 | /// 52 | /// The total time taken to analyze the snapshot. 53 | /// 54 | public TimeSpan ElapsedTime 55 | { 56 | get 57 | { 58 | return _elapsedTime; 59 | } 60 | } 61 | 62 | /// 63 | /// Gets a collection of inheritance tags describing the inheritance relations of types and members located 64 | /// within the snapshot. 65 | /// 66 | /// 67 | /// A collection of inheritance tags describing the inheritance relations of types and members located within 68 | /// the snapshot. 69 | /// 70 | public IEnumerable> Tags 71 | { 72 | get 73 | { 74 | return _tags; 75 | } 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin.Interfaces/MefBindingWorkaround.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved. 2 | // Licensed under the MIT License. See LICENSE.txt in the project root for license information. 3 | 4 | namespace Tvl.VisualStudio.InheritanceMargin.Interfaces 5 | { 6 | using System.ComponentModel.Composition; 7 | 8 | /// 9 | /// This class exists for the sole purpose of working around issue 10 | /// https://github.com/tunnelvisionlabs/InheritanceMargin/issues/6. 11 | /// 12 | /// 13 | /// Applying the is required for the affected version(s) of Visual Studio to 14 | /// place this interfaces assembly in the MEF cache. 15 | /// 16 | [Export] 17 | internal class MefBindingWorkaround 18 | { 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin.Interfaces/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved. 2 | // Licensed under the MIT License. See LICENSE.txt in the project root for license information. 3 | 4 | using System; 5 | using System.Reflection; 6 | using System.Runtime.InteropServices; 7 | 8 | // General Information about an assembly is controlled through the following 9 | // set of attributes. Change these attribute values to modify the information 10 | // associated with an assembly. 11 | [assembly: AssemblyDescription("")] 12 | [assembly: AssemblyTrademark("")] 13 | [assembly: AssemblyCulture("")] 14 | [assembly: CLSCompliant(false)] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("299de297-070f-415d-9a82-fba490c039c8")] 23 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin.Interfaces/Tvl.VisualStudio.InheritanceMargin.Interfaces.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | net45 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin/CSharpInheritanceTagger.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved. 2 | // Licensed under the MIT License. See LICENSE.txt in the project root for license information. 3 | 4 | namespace Tvl.VisualStudio.InheritanceMargin 5 | { 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Linq; 9 | using System.Reflection; 10 | using Microsoft.VisualStudio.Shell; 11 | using Microsoft.VisualStudio.Text; 12 | using Microsoft.VisualStudio.Text.Editor; 13 | using Microsoft.VisualStudio.Text.Tagging; 14 | using _DTE = EnvDTE._DTE; 15 | using DTE = EnvDTE.DTE; 16 | 17 | internal class CSharpInheritanceTagger : ITagger 18 | { 19 | internal static readonly ITagSpan[] NoTags = new ITagSpan[0]; 20 | private static Type _analyzerType; 21 | 22 | private readonly CSharpInheritanceTaggerProvider _provider; 23 | private readonly ITextBuffer _buffer; 24 | private readonly IInheritanceParser _analyzer; 25 | 26 | private ITagSpan[] _tags = NoTags; 27 | 28 | public CSharpInheritanceTagger(CSharpInheritanceTaggerProvider provider, ITextView view, ITextBuffer buffer) 29 | { 30 | if (provider == null) 31 | throw new ArgumentNullException("provider"); 32 | if (buffer == null) 33 | throw new ArgumentNullException("buffer"); 34 | 35 | _provider = provider; 36 | _buffer = buffer; 37 | 38 | if (_analyzerType == null) 39 | _analyzerType = LoadAnalyzerType(provider.GlobalServiceProvider); 40 | 41 | _analyzer = (IInheritanceParser)Activator.CreateInstance(_analyzerType, view, buffer, provider.TaskScheduler, provider.TextDocumentFactoryService, provider.OutputWindowService, provider.GlobalServiceProvider, new InheritanceTagFactory()); 42 | _analyzer.ParseComplete += HandleParseComplete; 43 | _analyzer.RequestParse(false); 44 | } 45 | 46 | /// 47 | public event EventHandler TagsChanged; 48 | 49 | internal static CSharpInheritanceTagger CreateInstance(CSharpInheritanceTaggerProvider provider, ITextView view, ITextBuffer buffer) 50 | { 51 | if (provider == null) 52 | throw new ArgumentNullException("provider"); 53 | if (buffer == null) 54 | throw new ArgumentNullException("buffer"); 55 | 56 | return view.Properties.GetOrCreateSingletonProperty(() => new CSharpInheritanceTagger(provider, view, buffer)); 57 | } 58 | 59 | private static Type LoadAnalyzerType(SVsServiceProvider serviceProvider) 60 | { 61 | Version version; 62 | int vsMajorVersion; 63 | if (Version.TryParse(((DTE)serviceProvider.GetService(typeof(_DTE))).Version, out version)) 64 | { 65 | vsMajorVersion = version.Major; 66 | } 67 | else 68 | { 69 | vsMajorVersion = 11; 70 | } 71 | 72 | bool vs2012 = vsMajorVersion == 11; 73 | bool vs2015 = vsMajorVersion == 14; 74 | bool vs2017 = vsMajorVersion == 15; 75 | bool vs2019 = vsMajorVersion == 16; 76 | bool vs17 = vsMajorVersion == 17; 77 | 78 | string assemblyName; 79 | if (vs2012) 80 | assemblyName = "Tvl.VisualStudio.InheritanceMargin.CSharp.11.0"; 81 | else if (vs2015) 82 | assemblyName = "Tvl.VisualStudio.InheritanceMargin.CSharp.14.0"; 83 | else if (vs2017) 84 | assemblyName = "Tvl.VisualStudio.InheritanceMargin.CSharp.15.0"; 85 | else if (vs2019) 86 | assemblyName = "Tvl.VisualStudio.InheritanceMargin.CSharp.16.0"; 87 | else if (vs17) 88 | assemblyName = "Tvl.VisualStudio.InheritanceMargin.CSharp.17.0"; 89 | else if (RoslynUtilities.IsRoslynInstalled(serviceProvider)) 90 | assemblyName = "Tvl.VisualStudio.InheritanceMargin.CSharp.Roslyn"; 91 | else 92 | assemblyName = "Tvl.VisualStudio.InheritanceMargin.CSharp.12.0"; 93 | 94 | Assembly assembly = Assembly.Load(assemblyName); 95 | return assembly.GetType("Tvl.VisualStudio.InheritanceMargin.CSharp.CSharpInheritanceAnalyzer"); 96 | } 97 | 98 | /// 99 | public IEnumerable> GetTags(NormalizedSnapshotSpanCollection spans) 100 | { 101 | return _tags; 102 | } 103 | 104 | protected virtual void HandleParseComplete(object sender, InheritanceParseResultEventArgs e) 105 | { 106 | IEnumerable> tags = NoTags; 107 | 108 | InheritanceParseResultEventArgs ie = e as InheritanceParseResultEventArgs; 109 | if (ie != null) 110 | { 111 | tags = ie.Tags; 112 | } 113 | 114 | _tags = tags.ToArray(); 115 | OnTagsChanged(new SnapshotSpanEventArgs(new SnapshotSpan(e.Snapshot, new Span(0, e.Snapshot.Length)))); 116 | } 117 | 118 | protected virtual void OnTagsChanged(SnapshotSpanEventArgs e) 119 | { 120 | var t = TagsChanged; 121 | if (t != null) 122 | t(this, e); 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin/CSharpInheritanceTaggerProvider.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved. 2 | // Licensed under the MIT License. See LICENSE.txt in the project root for license information. 3 | 4 | namespace Tvl.VisualStudio.InheritanceMargin 5 | { 6 | using System.ComponentModel.Composition; 7 | using Microsoft.VisualStudio.Shell; 8 | using Microsoft.VisualStudio.Text; 9 | using Microsoft.VisualStudio.Text.Editor; 10 | using Microsoft.VisualStudio.Text.Tagging; 11 | using Microsoft.VisualStudio.Utilities; 12 | using IOutputWindowService = Tvl.VisualStudio.OutputWindow.Interfaces.IOutputWindowService; 13 | using TaskScheduler = System.Threading.Tasks.TaskScheduler; 14 | 15 | [Name("CSharp Inheritance Tagger Provider")] 16 | [TagType(typeof(IInheritanceTag))] 17 | [Export(typeof(IViewTaggerProvider))] 18 | [ContentType("CSharp")] 19 | internal class CSharpInheritanceTaggerProvider : IViewTaggerProvider 20 | { 21 | public CSharpInheritanceTaggerProvider() 22 | { 23 | TaskScheduler = TaskScheduler.Default; 24 | } 25 | 26 | ////[Import(PredefinedTaskSchedulers.BackgroundIntelliSense)] 27 | public TaskScheduler TaskScheduler 28 | { 29 | get; 30 | private set; 31 | } 32 | 33 | [Import] 34 | public ITextDocumentFactoryService TextDocumentFactoryService 35 | { 36 | get; 37 | private set; 38 | } 39 | 40 | [Import] 41 | public IOutputWindowService OutputWindowService 42 | { 43 | get; 44 | private set; 45 | } 46 | 47 | [Import] 48 | public SVsServiceProvider GlobalServiceProvider 49 | { 50 | get; 51 | private set; 52 | } 53 | 54 | /// 55 | public ITagger CreateTagger(ITextView view, ITextBuffer buffer) 56 | where T : ITag 57 | { 58 | if (buffer != null) 59 | return CSharpInheritanceTagger.CreateInstance(this, view, buffer) as ITagger; 60 | 61 | return null; 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin/CommandTranslation/CommandId.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved. 2 | // Licensed under the MIT License. See LICENSE.txt in the project root for license information. 3 | 4 | namespace Tvl.VisualStudio.InheritanceMargin.CommandTranslation 5 | { 6 | using System.Collections.Generic; 7 | 8 | using Guid = System.Guid; 9 | 10 | internal sealed class CommandId 11 | { 12 | public static readonly IEqualityComparer DictionaryEqualityComparer = new EqualityComparer(); 13 | 14 | public CommandId(Guid menuGroup, int commandID) 15 | : this(menuGroup, commandID, commandID) 16 | { 17 | } 18 | 19 | public CommandId(Guid menuGroup, int startID, int endID) 20 | { 21 | Guid = menuGroup; 22 | Id = startID; 23 | EndId = endID; 24 | } 25 | 26 | public int EndId 27 | { 28 | get; 29 | private set; 30 | } 31 | 32 | public Guid Guid 33 | { 34 | get; 35 | private set; 36 | } 37 | 38 | public int Id 39 | { 40 | get; 41 | private set; 42 | } 43 | 44 | private class EqualityComparer : IEqualityComparer 45 | { 46 | public bool Equals(CommandId x, CommandId y) 47 | { 48 | if (object.ReferenceEquals(x, y)) 49 | return true; 50 | 51 | if (x != null) 52 | { 53 | if (y == null) 54 | return false; 55 | 56 | if (x.Guid == y.Guid) 57 | { 58 | if ((y.Id <= x.Id) && (y.EndId >= x.Id)) 59 | return true; 60 | 61 | if ((x.Id <= y.Id) && (x.EndId >= y.Id)) 62 | return true; 63 | } 64 | } 65 | 66 | return false; 67 | } 68 | 69 | public int GetHashCode(CommandId obj) 70 | { 71 | if (obj != null) 72 | return obj.Guid.GetHashCode(); 73 | 74 | return 0; 75 | } 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin/CommandTranslation/CommandRouter.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved. 2 | // Licensed under the MIT License. See LICENSE.txt in the project root for license information. 3 | 4 | namespace Tvl.VisualStudio.InheritanceMargin.CommandTranslation 5 | { 6 | using System; 7 | 8 | using Application = System.Windows.Application; 9 | using COMException = System.Runtime.InteropServices.COMException; 10 | using IInputElement = System.Windows.IInputElement; 11 | using IOleCommandTarget = Microsoft.VisualStudio.OLE.Interop.IOleCommandTarget; 12 | using IVsUIShell = Microsoft.VisualStudio.Shell.Interop.IVsUIShell; 13 | using Marshal = System.Runtime.InteropServices.Marshal; 14 | using Mouse = System.Windows.Input.Mouse; 15 | using OLECMD = Microsoft.VisualStudio.OLE.Interop.OLECMD; 16 | using OLECMDF = Microsoft.VisualStudio.OLE.Interop.OLECMDF; 17 | using OLECMDTEXT = Microsoft.VisualStudio.OLE.Interop.OLECMDTEXT; 18 | using OLECMDTEXTF = Microsoft.VisualStudio.OLE.Interop.OLECMDTEXTF; 19 | using OleConstants = Microsoft.VisualStudio.OLE.Interop.Constants; 20 | using Point = System.Windows.Point; 21 | using POINTS = Microsoft.VisualStudio.Shell.Interop.POINTS; 22 | using RoutedCommand = System.Windows.Input.RoutedCommand; 23 | using SVsServiceProvider = Microsoft.VisualStudio.Shell.SVsServiceProvider; 24 | using SVsUIShell = Microsoft.VisualStudio.Shell.Interop.SVsUIShell; 25 | using VSConstants = Microsoft.VisualStudio.VSConstants; 26 | 27 | internal static class CommandRouter 28 | { 29 | private static SVsServiceProvider ServiceProvider 30 | { 31 | get 32 | { 33 | return InheritanceMarginPackage.Instance.ServiceProvider; 34 | } 35 | } 36 | 37 | public static void DisplayContextMenu(Guid menuGroup, int contextMenuId, IInputElement routing) 38 | { 39 | Point position = Mouse.GetPosition(Application.Current.MainWindow); 40 | Point point2 = Application.Current.MainWindow.PointToScreen(position); 41 | ContextMenuRouter pCmdTrgtActive = new ContextMenuRouter(routing); 42 | IVsUIShell service = ServiceProvider.GetService(typeof(SVsUIShell)) as IVsUIShell; 43 | POINTS[] pos = new POINTS[1]; 44 | pos[0].x = (short)point2.X; 45 | pos[0].y = (short)point2.Y; 46 | Guid rclsidActive = menuGroup; 47 | service.ShowContextMenu(0, ref rclsidActive, contextMenuId, pos, pCmdTrgtActive); 48 | } 49 | 50 | private static int RouteExec(IInputElement routing, ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) 51 | { 52 | return RouteExec( 53 | (args, command) => command.CanExecute(args, routing), 54 | (args, command) => command.Execute(args, routing), 55 | ref pguidCmdGroup, 56 | nCmdID, 57 | nCmdexecopt, 58 | pvaIn, 59 | pvaOut); 60 | } 61 | 62 | private static int RouteExec(Func canExecuteFunc, Action executeFunc, ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) 63 | { 64 | RoutedCommand command = InheritanceMarginPackage.Instance.FindCommand(pguidCmdGroup, nCmdID); 65 | if (command == null) 66 | return (int)OleConstants.MSOCMDERR_E_UNKNOWNGROUP; 67 | 68 | CommandTargetParameters @params = CommandTargetParameters.CreateInstance(nCmdID); 69 | @params.InArgs = (pvaIn == IntPtr.Zero) ? null : Marshal.GetObjectForNativeVariant(pvaIn); 70 | if (canExecuteFunc(@params, command)) 71 | { 72 | try 73 | { 74 | executeFunc(@params, command); 75 | return VSConstants.S_OK; 76 | } 77 | catch (COMException exception) 78 | { 79 | return exception.ErrorCode; 80 | } 81 | } 82 | 83 | return (int)OleConstants.MSOCMDERR_E_NOTSUPPORTED; 84 | } 85 | 86 | private static int RouteQueryStatus(IInputElement routing, ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText) 87 | { 88 | return RouteQueryStatus((args, command) => command.CanExecute(args, routing), ref pguidCmdGroup, cCmds, prgCmds, pCmdText); 89 | } 90 | 91 | private static int RouteQueryStatus(Func canExecuteFunc, ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText) 92 | { 93 | RoutedCommand command = InheritanceMarginPackage.Instance.FindCommand(pguidCmdGroup, prgCmds[0].cmdID); 94 | if (command == null) 95 | return (int)OleConstants.MSOCMDERR_E_UNKNOWNGROUP; 96 | 97 | string commandText = GetCommandText(pCmdText); 98 | CommandTargetParameters @params = CommandTargetParameters.CreateInstance(prgCmds[0].cmdID, commandText); 99 | if (!canExecuteFunc(@params, command)) 100 | return (int)OleConstants.MSOCMDERR_E_NOTSUPPORTED; 101 | 102 | prgCmds[0].cmdf = (uint)OLECMDF.OLECMDF_SUPPORTED; 103 | prgCmds[0].cmdf |= @params.Enabled ? (uint)OLECMDF.OLECMDF_ENABLED : 0; 104 | prgCmds[0].cmdf |= !@params.Visible ? (uint)OLECMDF.OLECMDF_INVISIBLE : 0; 105 | prgCmds[0].cmdf |= @params.Pressed ? (uint)OLECMDF.OLECMDF_LATCHED : 0; 106 | if (@params.Text == null) 107 | @params.Text = string.Empty; 108 | 109 | if (commandText != @params.Text) 110 | SetCommandText(pCmdText, @params.Text); 111 | 112 | return VSConstants.S_OK; 113 | } 114 | 115 | private static string GetCommandText(IntPtr structPtr) 116 | { 117 | if (structPtr == IntPtr.Zero) 118 | return string.Empty; 119 | 120 | OLECMDTEXT olecmdtext = (OLECMDTEXT)Marshal.PtrToStructure(structPtr, typeof(OLECMDTEXT)); 121 | if (olecmdtext.cwActual == 0) 122 | return string.Empty; 123 | 124 | IntPtr offset = Marshal.OffsetOf(typeof(OLECMDTEXT), "rgwz"); 125 | IntPtr ptr = (IntPtr)((long)structPtr + (long)offset); 126 | return Marshal.PtrToStringUni(ptr, (int)olecmdtext.cwActual - 1); 127 | } 128 | 129 | public static void SetCommandText(IntPtr pCmdTextInt, string text) 130 | { 131 | if (text != null) 132 | { 133 | OLECMDTEXT olecmdtext = (OLECMDTEXT)Marshal.PtrToStructure(pCmdTextInt, typeof(OLECMDTEXT)); 134 | if ((olecmdtext.cmdtextf & (uint)OLECMDTEXTF.OLECMDTEXTF_NAME) == 0) 135 | return; 136 | 137 | char[] source = text.ToCharArray(); 138 | IntPtr bufferOffset = Marshal.OffsetOf(typeof(OLECMDTEXT), "rgwz"); 139 | IntPtr lengthOffset = Marshal.OffsetOf(typeof(OLECMDTEXT), "cwActual"); 140 | int length = Math.Min(((int)olecmdtext.cwBuf) - 1, source.Length); 141 | 142 | // copy the new text 143 | long bufferAddress = (long)pCmdTextInt + (long)bufferOffset; 144 | Marshal.Copy(source, 0, (IntPtr)bufferAddress, length); 145 | 146 | // null terminator 147 | Marshal.WriteInt16(pCmdTextInt, (int)bufferOffset + (length * 2), 0); 148 | 149 | // length including null terminator 150 | Marshal.WriteInt32(pCmdTextInt, (int)lengthOffset, length + 1); 151 | } 152 | } 153 | 154 | private class ContextMenuRouter : IOleCommandTarget 155 | { 156 | private readonly IInputElement _route; 157 | 158 | public ContextMenuRouter(IInputElement route) 159 | { 160 | _route = route; 161 | } 162 | 163 | public IInputElement Route 164 | { 165 | get 166 | { 167 | return _route; 168 | } 169 | } 170 | 171 | public int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) 172 | { 173 | return RouteExec(Route, ref pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut); 174 | } 175 | 176 | public int QueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText) 177 | { 178 | return RouteQueryStatus(Route, ref pguidCmdGroup, cCmds, prgCmds, pCmdText); 179 | } 180 | } 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin/CommandTranslation/CommandTargetParameters.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved. 2 | // Licensed under the MIT License. See LICENSE.txt in the project root for license information. 3 | 4 | namespace Tvl.VisualStudio.InheritanceMargin.CommandTranslation 5 | { 6 | internal class CommandTargetParameters 7 | { 8 | private CommandTargetParameters(string text, int id) 9 | { 10 | Text = text; 11 | Id = id; 12 | } 13 | 14 | public bool Enabled 15 | { 16 | get; 17 | set; 18 | } 19 | 20 | public int Id 21 | { 22 | get; 23 | private set; 24 | } 25 | 26 | public object InArgs 27 | { 28 | get; 29 | set; 30 | } 31 | 32 | public bool Pressed 33 | { 34 | get; 35 | set; 36 | } 37 | 38 | public string Text 39 | { 40 | get; 41 | set; 42 | } 43 | 44 | public bool Visible 45 | { 46 | get; 47 | set; 48 | } 49 | 50 | public static CommandTargetParameters CreateInstance(uint id) 51 | { 52 | return new CommandTargetParameters(string.Empty, (int)id); 53 | } 54 | 55 | public static CommandTargetParameters CreateInstance(uint id, string text) 56 | { 57 | return new CommandTargetParameters(text, (int)id); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin/InheritanceGlyphFactory.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved. 2 | // Licensed under the MIT License. See LICENSE.txt in the project root for license information. 3 | 4 | namespace Tvl.VisualStudio.InheritanceMargin 5 | { 6 | using System; 7 | using System.Windows; 8 | using System.Windows.Controls; 9 | using System.Windows.Media.Imaging; 10 | using Microsoft.VisualStudio.Text.Editor; 11 | using Microsoft.VisualStudio.Text.Formatting; 12 | 13 | using CommandBinding = System.Windows.Input.CommandBinding; 14 | 15 | internal class InheritanceGlyphFactory : IGlyphFactory 16 | { 17 | private readonly InheritanceGlyphFactoryProvider _provider; 18 | private readonly IWpfTextView _view; 19 | private readonly IWpfTextViewMargin _margin; 20 | 21 | public InheritanceGlyphFactory(InheritanceGlyphFactoryProvider provider, IWpfTextView view, IWpfTextViewMargin margin) 22 | { 23 | _provider = provider; 24 | _view = view; 25 | _margin = margin; 26 | } 27 | 28 | /// 29 | public UIElement GenerateGlyph(IWpfTextViewLine line, IGlyphTag tag) 30 | { 31 | InheritanceTag inheritanceTag = tag as InheritanceTag; 32 | if (inheritanceTag == null) 33 | return null; 34 | 35 | string imageName; 36 | switch (inheritanceTag.Glyph) 37 | { 38 | case InheritanceGlyph.HasImplementations: 39 | imageName = "has-implementations"; 40 | break; 41 | 42 | case InheritanceGlyph.Implements: 43 | imageName = "implements"; 44 | break; 45 | 46 | case InheritanceGlyph.ImplementsAndHasImplementations: 47 | imageName = "override-is-overridden-combined"; 48 | break; 49 | 50 | case InheritanceGlyph.ImplementsAndOverridden: 51 | imageName = "override-is-overridden-combined"; 52 | break; 53 | 54 | case InheritanceGlyph.Overridden: 55 | imageName = "is-overridden"; 56 | break; 57 | 58 | case InheritanceGlyph.Overrides: 59 | imageName = "overrides"; 60 | break; 61 | 62 | case InheritanceGlyph.OverridesAndOverridden: 63 | imageName = "override-is-overridden-combined"; 64 | break; 65 | 66 | default: 67 | return null; 68 | } 69 | 70 | BitmapSource source = new BitmapImage(new Uri("pack://application:,,,/Tvl.VisualStudio.InheritanceMargin;component/Resources/" + imageName + ".png")); 71 | Image image = new Image() 72 | { 73 | Source = source 74 | }; 75 | image.CommandBindings.Add(new CommandBinding(InheritanceMarginPackage.InheritanceTargetsList, inheritanceTag.HandleExecutedInheritanceTargetsList, inheritanceTag.HandleCanExecuteInheritanceTargetsList)); 76 | 77 | inheritanceTag.MarginGlyph = image; 78 | 79 | return image; 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin/InheritanceGlyphFactoryProvider.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved. 2 | // Licensed under the MIT License. See LICENSE.txt in the project root for license information. 3 | 4 | namespace Tvl.VisualStudio.InheritanceMargin 5 | { 6 | using System; 7 | using System.ComponentModel.Composition; 8 | using Microsoft.VisualStudio.Text.Editor; 9 | using Microsoft.VisualStudio.Text.Tagging; 10 | using Microsoft.VisualStudio.Utilities; 11 | using ErrorHandler = Microsoft.VisualStudio.ErrorHandler; 12 | using IVsPackage = Microsoft.VisualStudio.Shell.Interop.IVsPackage; 13 | using IVsShell = Microsoft.VisualStudio.Shell.Interop.IVsShell; 14 | using SVsServiceProvider = Microsoft.VisualStudio.Shell.SVsServiceProvider; 15 | using SVsShell = Microsoft.VisualStudio.Shell.Interop.SVsShell; 16 | 17 | [Name("InheritanceGlyphFactory")] 18 | [Export(typeof(IGlyphFactoryProvider))] 19 | [ContentType("text")] 20 | [TagType(typeof(InheritanceTag))] 21 | [Order] 22 | internal class InheritanceGlyphFactoryProvider : IGlyphFactoryProvider 23 | { 24 | private static bool _packageLoaded; 25 | 26 | [Import] 27 | private SVsServiceProvider ServiceProvider 28 | { 29 | get; 30 | set; 31 | } 32 | 33 | /// 34 | public IGlyphFactory GetGlyphFactory(IWpfTextView view, IWpfTextViewMargin margin) 35 | { 36 | if (view == null || margin == null) 37 | return null; 38 | 39 | if (!_packageLoaded) 40 | { 41 | IVsShell shell = (IVsShell)ServiceProvider.GetService(typeof(SVsShell)); 42 | Guid guid = typeof(InheritanceMarginPackage).GUID; 43 | IVsPackage package; 44 | ErrorHandler.ThrowOnFailure(shell.LoadPackage(ref guid, out package)); 45 | _packageLoaded = true; 46 | } 47 | 48 | return new InheritanceGlyphFactory(this, view, margin); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin/InheritanceGlyphMouseHandler.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved. 2 | // Licensed under the MIT License. See LICENSE.txt in the project root for license information. 3 | 4 | namespace Tvl.VisualStudio.InheritanceMargin 5 | { 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Linq; 9 | using System.Windows; 10 | using System.Windows.Controls; 11 | using System.Windows.Controls.Primitives; 12 | using System.Windows.Input; 13 | using System.Windows.Threading; 14 | using Microsoft.VisualStudio.Shell; 15 | using Microsoft.VisualStudio.Text; 16 | using Microsoft.VisualStudio.Text.Editor; 17 | using Microsoft.VisualStudio.Text.Formatting; 18 | using Microsoft.VisualStudio.Text.Tagging; 19 | 20 | internal class InheritanceGlyphMouseHandler : MouseProcessorBase 21 | { 22 | private readonly InheritanceGlyphMouseHandlerProvider _provider; 23 | private readonly IWpfTextViewHost _textViewHost; 24 | private readonly IWpfTextViewMargin _margin; 25 | private readonly ITagAggregator _glyphTagAggregator; 26 | private readonly Popup _popup; 27 | 28 | private Point _clickLocation; 29 | private bool _lastLeftButtonWasDoubleClick; 30 | private DispatcherTimer _mouseHoverTimer; 31 | private ITextViewLine _lastHoverPosition; 32 | private ITextViewLine _currentlyHoveringLine; 33 | 34 | public InheritanceGlyphMouseHandler(InheritanceGlyphMouseHandlerProvider provider, IWpfTextViewHost textViewHost, IWpfTextViewMargin margin) 35 | { 36 | if (provider == null) 37 | throw new ArgumentNullException("provider"); 38 | if (textViewHost == null) 39 | throw new ArgumentNullException("textViewHost"); 40 | if (margin == null) 41 | throw new ArgumentNullException("margin"); 42 | 43 | _provider = provider; 44 | _textViewHost = textViewHost; 45 | _margin = margin; 46 | _glyphTagAggregator = provider.ViewTagAggregatorFactoryService.CreateTagAggregator(textViewHost.TextView); 47 | _popup = new Popup() 48 | { 49 | IsOpen = false, 50 | Visibility = Visibility.Hidden 51 | }; 52 | 53 | _lastLeftButtonWasDoubleClick = true; 54 | _textViewHost.Closed += (sender, e) => _glyphTagAggregator.Dispose(); 55 | } 56 | 57 | /// 58 | public override void PostprocessMouseEnter(MouseEventArgs e) 59 | { 60 | EnableToolTips(); 61 | } 62 | 63 | /// 64 | public override void PostprocessMouseLeave(MouseEventArgs e) 65 | { 66 | DisableToolTips(); 67 | } 68 | 69 | /// 70 | public override void PostprocessMouseRightButtonUp(MouseButtonEventArgs e) 71 | { 72 | Point mouseLocationInTextView = GetMouseLocationInTextView(e); 73 | ITextViewLine textViewLine = GetTextViewLine(mouseLocationInTextView.Y); 74 | if (textViewLine != null) 75 | { 76 | var tags = GetInheritanceGlyphTagsStartingOnLine(textViewLine); 77 | var firstTag = tags.FirstOrDefault(); 78 | if (firstTag != null) 79 | { 80 | FrameworkElement glyphElement = firstTag.MarginGlyph; 81 | if (glyphElement != null) 82 | { 83 | Action action = () => firstTag.ShowContextMenu(e); 84 | glyphElement.Dispatcher.BeginInvoke(DispatcherPriority.Normal, action); 85 | } 86 | } 87 | } 88 | } 89 | 90 | /// 91 | public override void PostprocessMouseLeftButtonDown(MouseButtonEventArgs e) 92 | { 93 | _clickLocation = GetMouseLocationInTextView(e); 94 | _lastLeftButtonWasDoubleClick = e.ClickCount == 2; 95 | if (!_lastLeftButtonWasDoubleClick) 96 | HandleDragStart(_clickLocation); 97 | } 98 | 99 | /// 100 | public override void PostprocessMouseLeftButtonUp(MouseButtonEventArgs e) 101 | { 102 | Point mouseLocationInTextView = GetMouseLocationInTextView(e); 103 | if (HandleDragEnd(mouseLocationInTextView)) 104 | { 105 | e.Handled = true; 106 | } 107 | else if (!_lastLeftButtonWasDoubleClick) 108 | { 109 | if (GetTextViewLine(mouseLocationInTextView.Y) != GetTextViewLine(_clickLocation.Y)) 110 | e.Handled = false; 111 | else 112 | e.Handled = HandleMarkerClick(e); 113 | } 114 | } 115 | 116 | /// 117 | public override void PreprocessMouseMove(MouseEventArgs e) 118 | { 119 | Point mouseLocationInTextView = GetMouseLocationInTextView(e); 120 | if (!HandleDragOver(mouseLocationInTextView)) 121 | { 122 | ITextViewLine textViewLine = GetTextViewLine(mouseLocationInTextView.Y); 123 | if (_mouseHoverTimer != null) 124 | { 125 | if (textViewLine != _currentlyHoveringLine) 126 | { 127 | _currentlyHoveringLine = null; 128 | HideToolTip(); 129 | } 130 | 131 | _mouseHoverTimer.Start(); 132 | } 133 | } 134 | } 135 | 136 | private IEnumerable GetInheritanceGlyphTagsStartingOnLine(ITextViewLine textViewLine) 137 | { 138 | ITextBuffer visualBuffer = _textViewHost.TextView.TextViewModel.VisualBuffer; 139 | ITextBuffer textBuffer = _textViewHost.TextView.TextBuffer; 140 | foreach (IMappingTagSpan iteratorVariable2 in _glyphTagAggregator.GetTags(textViewLine.ExtentAsMappingSpan)) 141 | { 142 | InheritanceTag tag = iteratorVariable2.Tag as InheritanceTag; 143 | if (tag != null) 144 | { 145 | SnapshotPoint? point = iteratorVariable2.Span.Start.GetPoint(visualBuffer, PositionAffinity.Predecessor); 146 | SnapshotPoint? iteratorVariable5 = iteratorVariable2.Span.Start.GetPoint(textBuffer, PositionAffinity.Predecessor); 147 | if (point.HasValue && iteratorVariable5.HasValue && iteratorVariable5.Value >= textViewLine.Start && iteratorVariable5.Value <= textViewLine.End) 148 | yield return tag; 149 | } 150 | } 151 | } 152 | 153 | private Point GetMouseLocationInTextView(MouseEventArgs e) 154 | { 155 | IWpfTextView textView = _textViewHost.TextView; 156 | Point position = e.GetPosition(textView.VisualElement); 157 | position.Y += textView.ViewportTop; 158 | position.X += textView.ViewportLeft; 159 | return position; 160 | } 161 | 162 | private ITextViewLine GetTextViewLine(double y) 163 | { 164 | IWpfTextView textView = _textViewHost.TextView; 165 | ITextViewLine textViewLineContainingYCoordinate = textView.TextViewLines.GetTextViewLineContainingYCoordinate(y); 166 | if (textViewLineContainingYCoordinate == null) 167 | textViewLineContainingYCoordinate = (y <= textView.TextViewLines[0].Top) ? textView.TextViewLines.FirstVisibleLine : textView.TextViewLines.LastVisibleLine; 168 | 169 | return textViewLineContainingYCoordinate; 170 | } 171 | 172 | private void EnableToolTips() 173 | { 174 | if (_mouseHoverTimer == null) 175 | _mouseHoverTimer = new DispatcherTimer(TimeSpan.FromMilliseconds(150), DispatcherPriority.Normal, HandleHoverTimer, _margin.VisualElement.Dispatcher); 176 | 177 | _mouseHoverTimer.Start(); 178 | } 179 | 180 | private void DisableToolTips() 181 | { 182 | if (_mouseHoverTimer != null) 183 | _mouseHoverTimer.Stop(); 184 | 185 | HideToolTip(); 186 | _lastHoverPosition = null; 187 | } 188 | 189 | private void HideToolTip() 190 | { 191 | _popup.Child = null; 192 | _popup.IsOpen = false; 193 | _popup.Visibility = Visibility.Hidden; 194 | } 195 | 196 | private bool HandleMarkerClick(MouseButtonEventArgs e) 197 | { 198 | return false; 199 | } 200 | 201 | private void HandleDragStart(Point clickLocation) 202 | { 203 | } 204 | 205 | private bool HandleDragEnd(Point mouseLocationInTextView) 206 | { 207 | return false; 208 | } 209 | 210 | private bool HandleDragOver(Point mouseLocationInTextView) 211 | { 212 | return false; 213 | } 214 | 215 | private void HandleHoverTimer(object sender, EventArgs e) 216 | { 217 | if (!_textViewHost.IsClosed && Mouse.LeftButton != MouseButtonState.Pressed) 218 | HoverAtPoint(Mouse.GetPosition(_margin.VisualElement)); 219 | } 220 | 221 | private void HoverAtPoint(Point point) 222 | { 223 | if (_mouseHoverTimer != null && _mouseHoverTimer.IsEnabled && _margin.Enabled) 224 | { 225 | ITextViewLine textViewLineContainingYCoordinate = _textViewHost.TextView.TextViewLines.GetTextViewLineContainingYCoordinate(point.Y + _textViewHost.TextView.ViewportTop); 226 | if (textViewLineContainingYCoordinate != _lastHoverPosition) 227 | { 228 | _lastHoverPosition = textViewLineContainingYCoordinate; 229 | if (textViewLineContainingYCoordinate != null) 230 | { 231 | string str = null; 232 | foreach (InheritanceTag tag in GetInheritanceGlyphTagsStartingOnLine(textViewLineContainingYCoordinate)) 233 | { 234 | if (!string.IsNullOrEmpty(tag.ToolTip)) 235 | str = tag.ToolTip; 236 | } 237 | 238 | if (!string.IsNullOrEmpty(str)) 239 | { 240 | _popup.Child = null; 241 | TextBlock block = new TextBlock 242 | { 243 | Text = str, 244 | Name = "InheritanceGlyphToolTip" 245 | }; 246 | 247 | Border border = new Border 248 | { 249 | Padding = new Thickness(1.0), 250 | BorderThickness = new Thickness(1.0), 251 | Child = block 252 | }; 253 | 254 | block.SetResourceReference(TextBlock.ForegroundProperty, VsBrushes.ScreenTipTextKey); 255 | border.SetResourceReference(Border.BorderBrushProperty, VsBrushes.ScreenTipBorderKey); 256 | border.SetResourceReference(Border.BackgroundProperty, VsBrushes.ScreenTipBackgroundKey); 257 | _popup.Child = border; 258 | _popup.Placement = PlacementMode.Relative; 259 | _popup.PlacementTarget = _margin.VisualElement; 260 | _popup.HorizontalOffset = 0.0; 261 | _popup.VerticalOffset = textViewLineContainingYCoordinate.Bottom - _textViewHost.TextView.ViewportTop; 262 | _popup.IsOpen = true; 263 | _popup.Visibility = Visibility.Visible; 264 | _currentlyHoveringLine = textViewLineContainingYCoordinate; 265 | } 266 | } 267 | } 268 | } 269 | } 270 | } 271 | } 272 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin/InheritanceGlyphMouseHandlerProvider.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved. 2 | // Licensed under the MIT License. See LICENSE.txt in the project root for license information. 3 | 4 | namespace Tvl.VisualStudio.InheritanceMargin 5 | { 6 | using System.ComponentModel.Composition; 7 | using Microsoft.VisualStudio.Text.Editor; 8 | using Microsoft.VisualStudio.Text.Tagging; 9 | using Microsoft.VisualStudio.Utilities; 10 | 11 | [ContentType("text")] 12 | [Name("InheritanceMarkerMouseHandler")] 13 | [Export(typeof(IGlyphMouseProcessorProvider))] 14 | [Order] 15 | internal class InheritanceGlyphMouseHandlerProvider : IGlyphMouseProcessorProvider 16 | { 17 | [Import] 18 | public IViewTagAggregatorFactoryService ViewTagAggregatorFactoryService 19 | { 20 | get; 21 | private set; 22 | } 23 | 24 | /// 25 | public IMouseProcessor GetAssociatedMouseProcessor(IWpfTextViewHost wpfTextViewHost, IWpfTextViewMargin margin) 26 | { 27 | return new InheritanceGlyphMouseHandler(this, wpfTextViewHost, margin); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin/InheritanceMargin.vsct: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | Inheritance2 8 | Inheritance 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin/InheritanceMarginConstants.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved. 2 | // Licensed under the MIT License. See LICENSE.txt in the project root for license information. 3 | 4 | namespace Tvl.VisualStudio.InheritanceMargin 5 | { 6 | using Guid = System.Guid; 7 | 8 | internal static class InheritanceMarginConstants 9 | { 10 | public const string GuidInheritanceMarginPackageString = "B03A0D8A-A6E0-4983-B545-F73D2531D534"; 11 | 12 | public const string GuidInheritanceMarginCommandSetString = "102A7E39-1CD8-4F49-816E-245D813D884E"; 13 | public static readonly Guid GuidInheritanceMarginCommandSet = new Guid("{" + GuidInheritanceMarginCommandSetString + "}"); 14 | 15 | public static readonly int MenuInheritanceTargets = 0x0100; 16 | public static readonly int GroupInheritanceTargets = 0x0101; 17 | public static readonly int CmdidInheritanceTargetsList = 0x0200; 18 | public static readonly int CmdidInheritanceTargetsListEnd = 0x02FF; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin/InheritanceMarginPackage.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved. 2 | // Licensed under the MIT License. See LICENSE.txt in the project root for license information. 3 | 4 | namespace Tvl.VisualStudio.InheritanceMargin 5 | { 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Reflection; 9 | using System.Runtime.InteropServices; 10 | using System.Windows.Input; 11 | using Microsoft.VisualStudio.Shell; 12 | using CommandId = Tvl.VisualStudio.InheritanceMargin.CommandTranslation.CommandId; 13 | using IOleCommandTarget = Microsoft.VisualStudio.OLE.Interop.IOleCommandTarget; 14 | using OLECMD = Microsoft.VisualStudio.OLE.Interop.OLECMD; 15 | using OleConstants = Microsoft.VisualStudio.OLE.Interop.Constants; 16 | using UICONTEXT = Microsoft.VisualStudio.VSConstants.UICONTEXT; 17 | 18 | [Guid(InheritanceMarginConstants.GuidInheritanceMarginPackageString)] 19 | [PackageRegistration(UseManagedResourcesOnly = true)] 20 | [ProvideMenuResource(1000, 1)] 21 | internal class InheritanceMarginPackage : Package, IOleCommandTarget 22 | { 23 | private static InheritanceMarginPackage _instance; 24 | 25 | private readonly Dictionary _definedCommandTable = 26 | new Dictionary(CommandId.DictionaryEqualityComparer); 27 | 28 | public InheritanceMarginPackage() 29 | { 30 | _instance = this; 31 | } 32 | 33 | public static InheritanceMarginPackage Instance 34 | { 35 | get 36 | { 37 | return _instance; 38 | } 39 | } 40 | 41 | public static RoutedCommand InheritanceTargetsList 42 | { 43 | get; 44 | private set; 45 | } 46 | 47 | public SVsServiceProvider ServiceProvider 48 | { 49 | get 50 | { 51 | return new VsServiceProviderWrapper(this); 52 | } 53 | } 54 | 55 | public RoutedCommand FindCommand(Guid commandGroup, uint id) 56 | { 57 | return FindCommand(new CommandId(commandGroup, (int)id)); 58 | } 59 | 60 | private RoutedCommand FindCommand(CommandId commandId) 61 | { 62 | RoutedCommand result; 63 | if (_definedCommandTable.TryGetValue(commandId, out result)) 64 | return result; 65 | 66 | return null; 67 | } 68 | 69 | /// 70 | protected override void Initialize() 71 | { 72 | base.Initialize(); 73 | DefineRoutableCommands(); 74 | } 75 | 76 | private void DefineRoutableCommands() 77 | { 78 | DefineRoutableCommand("InheritanceTargetsList", InheritanceMarginConstants.GuidInheritanceMarginCommandSet, InheritanceMarginConstants.CmdidInheritanceTargetsList, InheritanceMarginConstants.CmdidInheritanceTargetsListEnd); 79 | } 80 | 81 | private void DefineRoutableCommand(string propertyName, Guid guid, int startId, int endId) 82 | { 83 | DefineRoutableCommand(typeof(InheritanceMarginPackage), propertyName, guid, startId, endId); 84 | } 85 | 86 | private void DefineRoutableCommand(Type owningType, string propertyName, Guid guid, int startId, int endId) 87 | { 88 | PropertyInfo property = owningType.GetProperty(propertyName, BindingFlags.Public | BindingFlags.Static); 89 | DefineRoutableCommand(property, guid, startId, endId); 90 | } 91 | 92 | private void DefineRoutableCommand(PropertyInfo property, Guid guid, int startId, int endId) 93 | { 94 | RoutedCommand command = new RoutedCommand(property.Name, property.DeclaringType); 95 | property.SetValue(this, command, new object[0]); 96 | DefineRoutableCommand(command, guid, startId, endId); 97 | } 98 | 99 | private void DefineRoutableCommand(RoutedCommand command, Guid guid, int startId, int endId) 100 | { 101 | _definedCommandTable.Add(new CommandId(guid, startId, endId), command); 102 | } 103 | 104 | /// 105 | int IOleCommandTarget.Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) 106 | { 107 | IOleCommandTarget service = (IOleCommandTarget)GetService(typeof(IOleCommandTarget)); 108 | if (service != null) 109 | return service.Exec(ref pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut); 110 | 111 | return (int)OleConstants.MSOCMDERR_E_NOTSUPPORTED; 112 | } 113 | 114 | /// 115 | int IOleCommandTarget.QueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText) 116 | { 117 | IOleCommandTarget service = (IOleCommandTarget)GetService(typeof(IOleCommandTarget)); 118 | if (service != null) 119 | return service.QueryStatus(ref pguidCmdGroup, cCmds, prgCmds, pCmdText); 120 | 121 | return (int)OleConstants.MSOCMDERR_E_NOTSUPPORTED; 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin/InheritanceTag.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved. 2 | // Licensed under the MIT License. See LICENSE.txt in the project root for license information. 3 | 4 | namespace Tvl.VisualStudio.InheritanceMargin 5 | { 6 | using System.Collections.Generic; 7 | using System.Collections.ObjectModel; 8 | 9 | using CanExecuteRoutedEventArgs = System.Windows.Input.CanExecuteRoutedEventArgs; 10 | using CommandRouter = Tvl.VisualStudio.InheritanceMargin.CommandTranslation.CommandRouter; 11 | using CommandTargetParameters = Tvl.VisualStudio.InheritanceMargin.CommandTranslation.CommandTargetParameters; 12 | using ExecutedRoutedEventArgs = System.Windows.Input.ExecutedRoutedEventArgs; 13 | using FrameworkElement = System.Windows.FrameworkElement; 14 | using MouseEventArgs = System.Windows.Input.MouseEventArgs; 15 | 16 | internal class InheritanceTag : IInheritanceTag 17 | { 18 | private readonly InheritanceGlyph _glyph; 19 | private readonly string _tooltip; 20 | private readonly List _targets; 21 | 22 | private FrameworkElement _marginGlyph; 23 | 24 | public InheritanceTag(InheritanceGlyph glyph, string tooltip, List members) 25 | { 26 | _glyph = glyph; 27 | _tooltip = tooltip; 28 | _targets = members; 29 | } 30 | 31 | public InheritanceGlyph Glyph 32 | { 33 | get 34 | { 35 | return _glyph; 36 | } 37 | } 38 | 39 | public string ToolTip 40 | { 41 | get 42 | { 43 | return _tooltip; 44 | } 45 | } 46 | 47 | public FrameworkElement MarginGlyph 48 | { 49 | get 50 | { 51 | return _marginGlyph; 52 | } 53 | 54 | internal set 55 | { 56 | _marginGlyph = value; 57 | } 58 | } 59 | 60 | public ReadOnlyCollection Targets 61 | { 62 | get 63 | { 64 | return _targets.AsReadOnly(); 65 | } 66 | } 67 | 68 | public void ShowContextMenu(MouseEventArgs e) 69 | { 70 | CommandRouter.DisplayContextMenu(InheritanceMarginConstants.GuidInheritanceMarginCommandSet, InheritanceMarginConstants.MenuInheritanceTargets, _marginGlyph); 71 | } 72 | 73 | public void HandleExecutedInheritanceTargetsList(object sender, ExecutedRoutedEventArgs e) 74 | { 75 | CommandTargetParameters parameter = e.Parameter as CommandTargetParameters; 76 | if (parameter != null) 77 | { 78 | int index = parameter.Id - InheritanceMarginConstants.CmdidInheritanceTargetsList; 79 | Targets[index].NavigateTo(); 80 | } 81 | } 82 | 83 | public void HandleCanExecuteInheritanceTargetsList(object sender, CanExecuteRoutedEventArgs e) 84 | { 85 | CommandTargetParameters parameter = e.Parameter as CommandTargetParameters; 86 | if (parameter != null) 87 | { 88 | int index = parameter.Id - InheritanceMarginConstants.CmdidInheritanceTargetsList; 89 | if (index < Targets.Count) 90 | { 91 | e.CanExecute = true; 92 | parameter.Enabled = true; 93 | parameter.Visible = true; 94 | parameter.Pressed = false; 95 | parameter.Text = Targets[index].DisplayName; 96 | } 97 | else 98 | { 99 | e.CanExecute = false; 100 | parameter.Enabled = false; 101 | parameter.Visible = false; 102 | } 103 | } 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin/InheritanceTagFactory.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved. 2 | // Licensed under the MIT License. See LICENSE.txt in the project root for license information. 3 | 4 | namespace Tvl.VisualStudio.InheritanceMargin 5 | { 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | 9 | internal class InheritanceTagFactory : IInheritanceTagFactory 10 | { 11 | /// 12 | public IInheritanceTag CreateTag(InheritanceGlyph glyph, string tooltip, IEnumerable targets) 13 | { 14 | return new InheritanceTag(glyph, tooltip, targets.ToList()); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved. 2 | // Licensed under the MIT License. See LICENSE.txt in the project root for license information. 3 | 4 | using System; 5 | using System.Reflection; 6 | using System.Resources; 7 | using System.Runtime.InteropServices; 8 | using Tvl.VisualStudio.InheritanceMargin; 9 | 10 | [assembly: AssemblyDescription("")] 11 | [assembly: AssemblyTrademark("")] 12 | [assembly: AssemblyCulture("")] 13 | [assembly: NeutralResourcesLanguage("en-US")] 14 | [assembly: CLSCompliant(false)] 15 | 16 | [assembly: ProvideBindingPath] 17 | [assembly: Guid("5B624A23-7F60-4086-87DF-1823E62418A7")] 18 | 19 | // Setting ComVisible to false makes the types in this assembly not visible 20 | // to COM components. If you need to access a type in this assembly from 21 | // COM, set the ComVisible attribute to true on that type. 22 | [assembly: ComVisible(false)] 23 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Visual Studio Extension": { 4 | "commandName": "Executable", 5 | "executablePath": "$(DevEnvDir)devenv.exe", 6 | "commandLineArgs": "/rootSuffix $(VSSDKTargetPlatformRegRootSuffix)" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin/ProvideBindingPathAttribute.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved. 2 | // Licensed under the MIT License. See LICENSE.txt in the project root for license information. 3 | 4 | namespace Tvl.VisualStudio.InheritanceMargin 5 | { 6 | using System; 7 | using System.Reflection; 8 | using System.Runtime.InteropServices; 9 | using Microsoft.VisualStudio.Shell; 10 | 11 | /// 12 | /// This attribute registers a path that should be probed for candidate assemblies at assembly load time. 13 | /// 14 | /// For example: 15 | /// [...\VisualStudio\10.0\BindingPaths\{5C48C732-5C7F-40f0-87A7-05C4F15BC8C3}] 16 | /// "$PackageFolder$"="" 17 | /// 18 | /// This would register the "PackageFolder" (i.e. the location of the pkgdef file) as a directory to be probed 19 | /// for assemblies to load. 20 | /// 21 | [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = false)] 22 | internal sealed class ProvideBindingPathAttribute : RegistrationAttribute 23 | { 24 | private static string GetPathToKey(RegistrationContext context) 25 | { 26 | Guid componentGuid = GetAssemblyGuid(context.CodeBase); 27 | return string.Concat(@"BindingPaths\", componentGuid.ToString("B").ToUpperInvariant()); 28 | } 29 | 30 | private static Guid GetAssemblyGuid(string codeBase) 31 | { 32 | string assemblyFile = new Uri(codeBase).LocalPath; 33 | Assembly assembly = Assembly.LoadFrom(codeBase); 34 | object[] attributesData = assembly.GetCustomAttributes(typeof(GuidAttribute), false); 35 | if (attributesData.Length == 0) 36 | throw new ArgumentException("The specified assembly did not contain a [Guid] attribute."); 37 | 38 | return new Guid(((GuidAttribute)attributesData[0]).Value); 39 | } 40 | 41 | /// 42 | public override void Register(RegistrationContext context) 43 | { 44 | if (context == null) 45 | throw new ArgumentNullException("context"); 46 | 47 | using (Key childKey = context.CreateKey(GetPathToKey(context))) 48 | { 49 | childKey.SetValue(context.ComponentPath, string.Empty); 50 | } 51 | } 52 | 53 | /// 54 | public override void Unregister(RegistrationContext context) 55 | { 56 | if (context == null) 57 | throw new ArgumentNullException("context"); 58 | 59 | context.RemoveKey(GetPathToKey(context)); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin/Resources/has-implementations.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tunnelvisionlabs/InheritanceMargin/7c3ebf3d71d0185d8b6f74a4b4c1c99f3f9217e6/Tvl.VisualStudio.InheritanceMargin/Resources/has-implementations.png -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin/Resources/implements.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tunnelvisionlabs/InheritanceMargin/7c3ebf3d71d0185d8b6f74a4b4c1c99f3f9217e6/Tvl.VisualStudio.InheritanceMargin/Resources/implements.png -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin/Resources/is-overridden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tunnelvisionlabs/InheritanceMargin/7c3ebf3d71d0185d8b6f74a4b4c1c99f3f9217e6/Tvl.VisualStudio.InheritanceMargin/Resources/is-overridden.png -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin/Resources/override-is-overridden-combined.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tunnelvisionlabs/InheritanceMargin/7c3ebf3d71d0185d8b6f74a4b4c1c99f3f9217e6/Tvl.VisualStudio.InheritanceMargin/Resources/override-is-overridden-combined.png -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin/Resources/override-is-overridden-combined2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tunnelvisionlabs/InheritanceMargin/7c3ebf3d71d0185d8b6f74a4b4c1c99f3f9217e6/Tvl.VisualStudio.InheritanceMargin/Resources/override-is-overridden-combined2.png -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin/Resources/overrides.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tunnelvisionlabs/InheritanceMargin/7c3ebf3d71d0185d8b6f74a4b4c1c99f3f9217e6/Tvl.VisualStudio.InheritanceMargin/Resources/overrides.png -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin/RoslynUtilities.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved. 2 | // Licensed under the MIT License. See LICENSE.txt in the project root for license information. 3 | 4 | namespace Tvl.VisualStudio.InheritanceMargin 5 | { 6 | using System; 7 | using Microsoft.VisualStudio.Shell.Interop; 8 | 9 | // Stolen from Microsoft.RestrictedUsage.CSharp.Utilities in Microsoft.VisualStudio.CSharp.Services.Language.dll 10 | internal static class RoslynUtilities 11 | { 12 | private static bool? _roslynInstalled; 13 | 14 | public static bool IsRoslynInstalled(IServiceProvider serviceProvider) 15 | { 16 | if (_roslynInstalled.HasValue) 17 | return _roslynInstalled.Value; 18 | 19 | _roslynInstalled = false; 20 | if (serviceProvider == null) 21 | return false; 22 | 23 | IVsShell vsShell = serviceProvider.GetService(typeof(SVsShell)) as IVsShell; 24 | if (vsShell == null) 25 | return false; 26 | 27 | Guid guid = new Guid("6cf2e545-6109-4730-8883-cf43d7aec3e1"); 28 | int isInstalled; 29 | if (vsShell.IsPackageInstalled(ref guid, out isInstalled) == 0 && isInstalled != 0) 30 | _roslynInstalled = true; 31 | 32 | return _roslynInstalled.Value; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin/Tvl.VisualStudio.InheritanceMargin.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | net45 8 | net46;$(AssetTargetFallback) 9 | 10 | 11 | 12 | true 13 | true 14 | true 15 | false 16 | false 17 | true 18 | false 19 | 20 | 21 | 22 | 23 | False 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 1000 35 | Designer 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 3.2.0 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | $(BuildVersionSimple) 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 11.0 105 | 106 | 107 | 108 | 109 | 110 | 18.0 111 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin/VSIXImage_large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tunnelvisionlabs/InheritanceMargin/7c3ebf3d71d0185d8b6f74a4b4c1c99f3f9217e6/Tvl.VisualStudio.InheritanceMargin/VSIXImage_large.png -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin/VSIXImage_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tunnelvisionlabs/InheritanceMargin/7c3ebf3d71d0185d8b6f74a4b4c1c99f3f9217e6/Tvl.VisualStudio.InheritanceMargin/VSIXImage_small.png -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin/VSPackage.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | text/microsoft-resx 91 | 92 | 93 | 1.3 94 | 95 | 96 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 97 | 98 | 99 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 100 | 101 | -------------------------------------------------------------------------------- /Tvl.VisualStudio.InheritanceMargin/source.extension.vsixmanifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Inheritance Margin 6 | Show inheritance information in the glyph margin. 7 | https://github.com/tunnelvisionlabs/InheritanceMargin 8 | LICENSE.txt 9 | 10 | 11 | https://github.com/tunnelvisionlabs/InheritanceMargin/releases/tag/3.3.1 12 | VSIXImage_small.png 13 | VSIXImage_large.png 14 | inheritance, margin, c#, editor 15 | 16 | 17 | 18 | 19 | 20 | 21 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 1.0.{build} 2 | os: Visual Studio 2017 3 | configuration: Release 4 | platform: Any CPU 5 | init: 6 | - ps: git config --global core.autocrlf true 7 | before_build: 8 | - nuget restore 9 | skip_tags: true 10 | build: 11 | verbosity: minimal 12 | artifacts: 13 | - path: 'Tvl.VisualStudio.InheritanceMargin\bin\Release\net45\Tvl.VisualStudio.InheritanceMargin.vsix' 14 | # preserve "packages" directory in the root of build folder but will reset it if packages.config is modified 15 | cache: 16 | - packages -> **\packages.config 17 | -------------------------------------------------------------------------------- /global.json: -------------------------------------------------------------------------------- 1 | { 2 | "sdk": { 3 | "version": "2.1.401" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /stylecop.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json", 3 | "settings": { 4 | "orderingRules": { 5 | // Ignore accessibility when evaluating element order 6 | "elementOrder": [ 7 | "kind", 8 | "constant", 9 | "static", 10 | "readonly" 11 | ] 12 | }, 13 | "documentationRules": { 14 | "companyName": "Tunnel Vision Laboratories, LLC", 15 | "copyrightText": "Copyright (c) {companyName}. All Rights Reserved.\nLicensed under the MIT License. See LICENSE.txt in the project root for license information.", 16 | "xmlHeader": false, 17 | "fileNamingConvention": "metadata", 18 | "documentInternalElements": false 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /version.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/AArnott/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", 3 | "version": "3.6", 4 | "publicReleaseRefSpec": [ 5 | "^refs/heads/master$" 6 | ], 7 | "cloudBuild": { 8 | "buildNumber": { 9 | "enabled": true 10 | } 11 | } 12 | } 13 | --------------------------------------------------------------------------------