├── images
├── icon.png
├── screenshot.gif
└── screenshot.png
├── src
├── Resources
│ ├── Reload.png
│ ├── DisasmWindowCommand.png
│ └── AsmSyntax.xshd
├── BenchmarkDotNet.Disassembler.x64
│ ├── BenchmarkDotNet.Disassembler.x64.csproj
│ ├── DataContracts.cs
│ ├── ClrSourceExtensions.cs
│ └── Program.cs
├── DisasmoPackage.cs
├── Properties
│ ├── AssemblyInfo.cs
│ ├── Settings.settings
│ └── Settings.Designer.cs
├── Analyzers
│ ├── Base
│ │ ├── CommonSuggestedActionsSourceProvider.cs
│ │ ├── CommonSuggestedActionsSource.cs
│ │ └── BaseSuggestedAction.cs
│ ├── DisasmMethodOrClassAction.cs
│ ├── BenchmarkSuggestedAction.cs
│ └── ObjectLayoutSuggestedAction.cs
├── source.extension.vsixmanifest
├── app.config
├── Utils
│ ├── ProcessUtils.cs
│ ├── Bdn
│ │ ├── BdnDisassembler.cs
│ │ └── BdnDisassemblyPrettifier.cs
│ ├── IdeUtils.cs
│ └── ComPlusDisassemblyPrettifier.cs
├── Views
│ ├── DisasmWindowControl.xaml.cs
│ └── DisasmWindowControl.xaml
├── DisasmoPackage.vsct
├── ViewModels
│ ├── SettingsViewModel.cs
│ └── MainViewModel.cs
└── Disasmo.Vsix.csproj
├── LICENSE
├── Disasmo.sln
├── README.md
└── .gitignore
/images/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XenocodeRCE/Disasmo/master/images/icon.png
--------------------------------------------------------------------------------
/images/screenshot.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XenocodeRCE/Disasmo/master/images/screenshot.gif
--------------------------------------------------------------------------------
/images/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XenocodeRCE/Disasmo/master/images/screenshot.png
--------------------------------------------------------------------------------
/src/Resources/Reload.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XenocodeRCE/Disasmo/master/src/Resources/Reload.png
--------------------------------------------------------------------------------
/src/Resources/DisasmWindowCommand.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XenocodeRCE/Disasmo/master/src/Resources/DisasmWindowCommand.png
--------------------------------------------------------------------------------
/src/BenchmarkDotNet.Disassembler.x64/BenchmarkDotNet.Disassembler.x64.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net46
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/DisasmoPackage.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 | using System.Threading;
4 | using Microsoft.VisualStudio;
5 | using Microsoft.VisualStudio.Shell;
6 | using Task = System.Threading.Tasks.Task;
7 |
8 | namespace Disasmo
9 | {
10 | [PackageRegistration(UseManagedResourcesOnly = true, AllowsBackgroundLoading = true)]
11 | [Guid(DisasmoPackage.PackageGuidString)]
12 | [ProvideAutoLoad(VSConstants.UICONTEXT.SolutionExistsAndFullyLoaded_string, PackageAutoLoadFlags.BackgroundLoad)]
13 | [ProvideToolWindow(typeof(DisasmWindow))]
14 | public sealed class DisasmoPackage : AsyncPackage
15 | {
16 | public const string PackageGuidString = "6d23b8d8-92f1-4f92-947a-b9021f6ab3dc";
17 |
18 | protected override async Task InitializeAsync(CancellationToken cancellationToken, IProgress progress)
19 | {
20 | Current = this;
21 | await this.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
22 | }
23 |
24 | public static DisasmoPackage Current { get; set; }
25 | }
26 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Egor Bogatov
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 |
--------------------------------------------------------------------------------
/src/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("Disasmo")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("Disasmo")]
13 | [assembly: AssemblyCopyright("")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // Version information for an assembly consists of the following four values:
23 | //
24 | // Major Version
25 | // Minor Version
26 | // Build Number
27 | // Revision
28 | //
29 | // You can specify all the values or you can default the Build and Revision Numbers
30 | // by using the '*' as shown below:
31 | // [assembly: AssemblyVersion("1.0.*")]
32 | [assembly: AssemblyVersion("1.0.0.0")]
33 | [assembly: AssemblyFileVersion("1.0.0.0")]
34 |
--------------------------------------------------------------------------------
/src/Analyzers/Base/CommonSuggestedActionsSourceProvider.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel.Composition;
2 | using Microsoft.CodeAnalysis;
3 | using Microsoft.VisualStudio.Language.Intellisense;
4 | using Microsoft.VisualStudio.LanguageServices;
5 | using Microsoft.VisualStudio.Text;
6 | using Microsoft.VisualStudio.Text.Editor;
7 | using Microsoft.VisualStudio.Text.Operations;
8 | using Microsoft.VisualStudio.Utilities;
9 |
10 | namespace Disasmo.Analyzers
11 | {
12 | [Export(typeof(ISuggestedActionsSourceProvider))]
13 | [Name("Test Suggested Actions")]
14 | [ContentType("text")]
15 | internal class CommonSuggestedActionsSourceProvider : ISuggestedActionsSourceProvider
16 | {
17 | public Workspace Workspace { get; }
18 |
19 | [Import(typeof(ITextStructureNavigatorSelectorService))]
20 | internal ITextStructureNavigatorSelectorService NavigatorService { get; set; }
21 |
22 | [ImportingConstructor]
23 | public CommonSuggestedActionsSourceProvider([Import(typeof(VisualStudioWorkspace), AllowDefault = true)] Workspace workspace)
24 | {
25 | Workspace = workspace;
26 | }
27 |
28 | public ISuggestedActionsSource CreateSuggestedActionsSource(ITextView textView, ITextBuffer textBuffer)
29 | {
30 | if (textBuffer == null && textView == null)
31 | return null;
32 |
33 | return new CommonSuggestedActionsSource(this, textView, textBuffer);
34 | }
35 | }
36 | }
--------------------------------------------------------------------------------
/Disasmo.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.28516.95
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Disasmo.Vsix", "src\Disasmo.Vsix.csproj", "{3334577B-6E6F-4AF2-BDD3-FE03D697CCC5}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BenchmarkDotNet.Disassembler.x64", "src\BenchmarkDotNet.Disassembler.x64\BenchmarkDotNet.Disassembler.x64.csproj", "{3428BD3B-BA98-42AA-864F-7C85A95A7D05}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Release|Any CPU = Release|Any CPU
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {3334577B-6E6F-4AF2-BDD3-FE03D697CCC5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17 | {3334577B-6E6F-4AF2-BDD3-FE03D697CCC5}.Debug|Any CPU.Build.0 = Debug|Any CPU
18 | {3334577B-6E6F-4AF2-BDD3-FE03D697CCC5}.Release|Any CPU.ActiveCfg = Release|Any CPU
19 | {3334577B-6E6F-4AF2-BDD3-FE03D697CCC5}.Release|Any CPU.Build.0 = Release|Any CPU
20 | {3428BD3B-BA98-42AA-864F-7C85A95A7D05}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {3428BD3B-BA98-42AA-864F-7C85A95A7D05}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {3428BD3B-BA98-42AA-864F-7C85A95A7D05}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {3428BD3B-BA98-42AA-864F-7C85A95A7D05}.Release|Any CPU.Build.0 = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {F9249C67-05FB-4105-A619-BBE976B34BA1}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/src/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | False
10 |
11 |
12 | True
13 |
14 |
15 | False
16 |
17 |
18 | COMPlus_JitDiffableDasm=1
19 |
20 |
21 | False
22 |
23 |
24 | False
25 |
26 |
27 | True
28 |
29 |
30 | False
31 |
32 |
33 | False
34 |
35 |
36 | 1
37 |
38 |
39 |
--------------------------------------------------------------------------------
/src/Analyzers/DisasmMethodOrClassAction.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 | using Microsoft.CodeAnalysis;
5 | using Microsoft.CodeAnalysis.CSharp.Syntax;
6 | using Microsoft.CodeAnalysis.FindSymbols;
7 | using Document = Microsoft.CodeAnalysis.Document;
8 |
9 | namespace Disasmo
10 | {
11 |
12 | internal class DisasmMethodOrClassAction : BaseSuggestedAction
13 | {
14 | public DisasmMethodOrClassAction(CommonSuggestedActionsSource actionsSource) : base(actionsSource) {}
15 |
16 | public override async void Invoke(CancellationToken cancellationToken)
17 | {
18 | var window = await IdeUtils.ShowWindowAsync(cancellationToken);
19 | window?.ViewModel?.RunOperationAsync(_symbol, _codeDoc, OperationType.Disasm);
20 | }
21 |
22 | protected override async Task GetSymbol(Document document, int tokenPosition, CancellationToken cancellationToken)
23 | {
24 | SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken);
25 |
26 | var syntaxTree = await semanticModel.SyntaxTree.GetRootAsync(cancellationToken);
27 | var token = syntaxTree.FindToken(tokenPosition);
28 |
29 | if (token.Parent is MethodDeclarationSyntax m)
30 | return ModelExtensions.GetDeclaredSymbol(semanticModel, m);
31 |
32 | if (token.Parent is ClassDeclarationSyntax c)
33 | return ModelExtensions.GetDeclaredSymbol(semanticModel, c);
34 |
35 | return null;
36 | }
37 |
38 | public override string DisplayText
39 | {
40 | get
41 | {
42 | if (_symbol is IMethodSymbol)
43 | return $"Disasm '{_symbol.Name}' method";
44 | return $"Disasm '{_symbol.Name}' class";
45 | }
46 | }
47 | }
48 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Disasmo
2 | [VS2019 Add-in.](https://marketplace.visualstudio.com/items?itemName=EgorBogatov.Disasmo)
3 | Click on any method or class to see what .NET Core's JIT generates for them (ASM).
4 |
5 | 
6 |
7 |
8 | The Add-in targets .NET Core contributors so it assumes you already have CoreCLR local repo.
9 | If you don't have it, the steps to obtain and configure it are:
10 | ```bash
11 | git clone git@github.com:dotnet/coreclr.git
12 | cd coreclr
13 | build release skiptests
14 | build debug skiptests
15 | ```
16 | We have to build it twice because we need mostly release files and a debug version of `clrjit.dll`.
17 | For more details visit [viewing-jit-dumps.md](https://github.com/dotnet/coreclr/blob/master/Documentation/building/viewing-jit-dumps.md).
18 | The Add-in basically follows steps mentioned in the doc above:
19 | ```
20 | dotnet restore
21 | dotnet publish -r win-x64 -c Release
22 | set COMPlus_JitDisasm=%method%
23 | ConsoleApp123.exe
24 | ```
25 | In order to be able to disasm any method (even unused) the add-in injects a small line to the app's `Main()`:
26 | ```csharp
27 | System.Runtime.CompilerServices.RuntimeHelpers.PrepareMethod(%methodHandle%);
28 | ```
29 | **However**, you can use BenchmarkDotNet-style disassembler without any local CoreCLR,
30 | just enable it in "Settings/Use BDN disasm".
31 |
32 | ## Known Issues
33 | * Only .NET Core Console applications are supported
34 | * I only tested it for .NET Core 3.0 apps
35 | * Multi-target projects are not supported
36 | * Generic methods are not supported
37 | * **Resharper** hides Roslyn actions by default (Uncheck "Do not show Visual Studio Light Bulb").
38 |
39 | ## 3rd party dependencies
40 | * [MvvmLight](https://github.com/lbugnion/mvvmlight) (MIT)
41 | * [AvalonEdit](https://github.com/icsharpcode/AvalonEdit) (MIT)
42 | * [BenchmarkDotNet](https://github.com/dotnet/BenchmarkDotNet) (MIT)
43 | * [ObjectLayoutInspector](https://github.com/SergeyTeplyakov/ObjectLayoutInspector) (MIT)
44 |
--------------------------------------------------------------------------------
/src/Analyzers/BenchmarkSuggestedAction.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Threading;
4 | using System.Threading.Tasks;
5 | using Microsoft.CodeAnalysis;
6 | using Microsoft.CodeAnalysis.CSharp.Syntax;
7 | using Microsoft.CodeAnalysis.Text;
8 | using Microsoft.VisualStudio.Text;
9 |
10 | namespace Disasmo
11 | {
12 | internal class BenchmarkSuggestedAction : BaseSuggestedAction
13 | {
14 | public BenchmarkSuggestedAction(CommonSuggestedActionsSource actionsSource) : base(actionsSource) {}
15 |
16 | protected override async Task GetSymbol(Document document, int tokenPosition, CancellationToken cancellationToken)
17 | {
18 | SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken);
19 |
20 | var syntaxTree = await semanticModel.SyntaxTree.GetRootAsync(cancellationToken);
21 | var token = syntaxTree.FindToken(tokenPosition);
22 |
23 | if (token.Parent is MethodDeclarationSyntax method)
24 | return ModelExtensions.GetDeclaredSymbol(semanticModel, method);
25 |
26 | return null;
27 | }
28 |
29 | public override async void Invoke(CancellationToken cancellationToken)
30 | {
31 | DisasmWindow window = await IdeUtils.ShowWindowAsync(cancellationToken);
32 | SyntaxNode syntaxNode = await _symbol.DeclaringSyntaxReferences.FirstOrDefault().GetSyntaxAsync();
33 | ITrackingSpan trackingSpan = SnapshotSpan.Snapshot.CreateTrackingSpan(new Span(syntaxNode.FullSpan.Start, syntaxNode.FullSpan.Length), SpanTrackingMode.EdgeInclusive);
34 | trackingSpan.TextBuffer.Insert(syntaxNode.SpanStart, "[BenchmarkDotNet.Attributes.Benchmark]" + Environment.NewLine + "\t\t");
35 |
36 | window?.ViewModel?.RunOperationAsync(_symbol, _codeDoc, OperationType.Benchmark);
37 | }
38 |
39 | public override string DisplayText => $"Benchmark '{_symbol}' (Adds BenchmarkDotNet package)";
40 | }
41 | }
--------------------------------------------------------------------------------
/src/source.extension.vsixmanifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Disasmo
6 | VS2019 Add-in. Click on any method to see what ASM JIT will generate for it.
7 | http://github.com/EgorBo/disasmo
8 | ..\images\icon.png
9 | ..\images\screenshot.png
10 | .NET Core, disasm, asm, disassembler
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/src/app.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | False
15 |
16 |
17 | True
18 |
19 |
20 | False
21 |
22 |
23 | COMPlus_JitDiffableDasm=1
24 |
25 |
26 | False
27 |
28 |
29 | False
30 |
31 |
32 | True
33 |
34 |
35 | False
36 |
37 |
38 | False
39 |
40 |
41 | 1
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/src/Analyzers/ObjectLayoutSuggestedAction.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 | using Microsoft.CodeAnalysis;
4 | using Microsoft.CodeAnalysis.CSharp;
5 | using Microsoft.CodeAnalysis.CSharp.Syntax;
6 |
7 | namespace Disasmo
8 | {
9 | internal class ObjectLayoutSuggestedAction : BaseSuggestedAction
10 | {
11 | public ObjectLayoutSuggestedAction(CommonSuggestedActionsSource actionsSource) : base(actionsSource) {}
12 |
13 | protected override async Task GetSymbol(Document document, int tokenPosition, CancellationToken cancellationToken)
14 | {
15 | SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken);
16 |
17 | var syntaxTree = await semanticModel.SyntaxTree.GetRootAsync(cancellationToken);
18 | var token = syntaxTree.FindToken(tokenPosition);
19 |
20 | if (token.Parent is ClassDeclarationSyntax c)
21 | return ModelExtensions.GetDeclaredSymbol(semanticModel, c);
22 |
23 | var vds = token.Parent is VariableDeclarationSyntax variable ? variable : token.Parent?.Parent as VariableDeclarationSyntax;
24 | if (vds != null)
25 | {
26 | var info = semanticModel.GetSymbolInfo(vds.Type);
27 | if (string.IsNullOrWhiteSpace(info.Symbol.ToString()))
28 | return null;
29 | return info.Symbol;
30 | }
31 |
32 | if (token.Parent is ParameterSyntax parameterSyntax)
33 | {
34 | var info = semanticModel.GetSymbolInfo(parameterSyntax.Type);
35 | if (string.IsNullOrWhiteSpace(info.Symbol.ToString()))
36 | return null;
37 | return info.Symbol;
38 | }
39 |
40 | return null;
41 | }
42 |
43 | public override async void Invoke(CancellationToken cancellationToken)
44 | {
45 | var window = await IdeUtils.ShowWindowAsync(cancellationToken);
46 | window?.ViewModel?.RunOperationAsync(_symbol, _codeDoc, OperationType.ObjectLayout);
47 | }
48 |
49 | public override string DisplayText => $"Show memory layout for '{_symbol}' (Adds ObjectLayoutInspector package)";
50 | }
51 | }
--------------------------------------------------------------------------------
/src/Utils/ProcessUtils.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using Microsoft.VisualStudio.Threading;
7 |
8 | namespace Disasmo
9 | {
10 | public static class ProcessUtils
11 | {
12 | public static async Task RunProcess(string path, string args = "", Dictionary envVars = null, string workingDir = null)
13 | {
14 | var logger = new StringBuilder();
15 | var loggerForErrors = new StringBuilder();
16 | try
17 | {
18 | var processStartInfo = new ProcessStartInfo
19 | {
20 | FileName = path,
21 | UseShellExecute = false,
22 | CreateNoWindow = true,
23 | RedirectStandardError = true,
24 | RedirectStandardOutput = true,
25 | Arguments = args,
26 | };
27 |
28 | if (workingDir != null)
29 | processStartInfo.WorkingDirectory = workingDir;
30 |
31 | if (envVars != null)
32 | {
33 | foreach (var envVar in envVars)
34 | processStartInfo.EnvironmentVariables[envVar.Key] = envVar.Value;
35 | }
36 |
37 | var process = Process.Start(processStartInfo);
38 |
39 | process.ErrorDataReceived += (sender, e) =>
40 | {
41 | logger.AppendLine(e.Data);
42 | loggerForErrors.AppendLine(e.Data);
43 | };
44 | process.OutputDataReceived += (sender, e) => logger.AppendLine(e.Data);
45 | process.BeginOutputReadLine();
46 | process.BeginErrorReadLine();
47 | await process.WaitForExitAsync();
48 |
49 | return new ProcessResult { Error = loggerForErrors.ToString().Trim('\r', '\n'), Output = logger.ToString().Trim('\r', '\n') };
50 | }
51 | catch (Exception e)
52 | {
53 | return new ProcessResult { Error = $"RunProcess failed:{e.Message}.\npath={path}\nargs={args}\nworkingdir={workingDir ?? Environment.CurrentDirectory}\n{loggerForErrors}" };
54 | }
55 | }
56 | }
57 |
58 | public class ProcessResult
59 | {
60 | public string Output { get; set; }
61 | public string Error { get; set; }
62 | }
63 | }
--------------------------------------------------------------------------------
/src/Analyzers/Base/CommonSuggestedActionsSource.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 | using Disasmo.Analyzers;
7 | using Microsoft.VisualStudio.Language.Intellisense;
8 | using Microsoft.VisualStudio.Text;
9 | using Microsoft.VisualStudio.Text.Editor;
10 |
11 | namespace Disasmo
12 | {
13 | internal class CommonSuggestedActionsSource : ISuggestedActionsSource
14 | {
15 | private BaseSuggestedAction[] _baseActions;
16 |
17 | public CommonSuggestedActionsSourceProvider SourceProvider { get; }
18 |
19 | public ITextView TextView { get; }
20 | public ITextBuffer TextBuffer { get; }
21 |
22 | public CommonSuggestedActionsSource(CommonSuggestedActionsSourceProvider sourceProvider,
23 | ITextView textView, ITextBuffer textBuffer)
24 | {
25 | SourceProvider = sourceProvider;
26 | TextView = textView;
27 | TextBuffer = textBuffer;
28 | _baseActions = new BaseSuggestedAction[]
29 | {
30 | new DisasmMethodOrClassAction(this),
31 | new ObjectLayoutSuggestedAction(this),
32 | new BenchmarkSuggestedAction(this),
33 | };
34 | }
35 |
36 | public event EventHandler SuggestedActionsChanged;
37 |
38 | public void Dispose() {}
39 |
40 | public IEnumerable GetSuggestedActions(
41 | ISuggestedActionCategorySet requestedActionCategories, SnapshotSpan range,
42 | CancellationToken cancellationToken)
43 | {
44 | return _baseActions
45 | .Where(a => a.Symbol != null)
46 | .Select(a =>
47 | {
48 | a.SnapshotSpan = range;
49 | return new SuggestedActionSet(a.GetType().Name, new[] {a}, priority: SuggestedActionSetPriority.Low);
50 | });
51 | }
52 |
53 | public async Task HasSuggestedActionsAsync(ISuggestedActionCategorySet requestedActionCategories,
54 | SnapshotSpan range, CancellationToken cancellationToken)
55 | {
56 | return await await Task.WhenAny(_baseActions.Select(t =>
57 | {
58 | t.SnapshotSpan = range;
59 | return t.Validate(cancellationToken);
60 | }));
61 | }
62 |
63 | public bool TryGetTelemetryId(out Guid telemetryId)
64 | {
65 | telemetryId = Guid.Empty;
66 | return false;
67 | }
68 | }
69 | }
--------------------------------------------------------------------------------
/src/Analyzers/Base/BaseSuggestedAction.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Drawing;
4 | using System.Linq;
5 | using System.Threading;
6 | using System.Threading.Tasks;
7 | using Microsoft.CodeAnalysis;
8 | using Microsoft.CodeAnalysis.Text;
9 | using Microsoft.VisualStudio.Imaging;
10 | using Microsoft.VisualStudio.Imaging.Interop;
11 | using Microsoft.VisualStudio.Language.Intellisense;
12 | using Microsoft.VisualStudio.Shell;
13 | using Microsoft.VisualStudio.Text;
14 | using Point = System.Windows.Point;
15 | using Size = System.Windows.Size;
16 | using Task = System.Threading.Tasks.Task;
17 |
18 | namespace Disasmo
19 | {
20 | internal abstract class BaseSuggestedAction : ISuggestedAction
21 | {
22 | protected readonly CommonSuggestedActionsSource _actionsSource;
23 | protected ISymbol _symbol;
24 | protected Document _codeDoc;
25 |
26 | public BaseSuggestedAction(CommonSuggestedActionsSource actionsSource) => _actionsSource = actionsSource;
27 |
28 | public SnapshotSpan SnapshotSpan { get; set; }
29 |
30 | public async Task Validate(CancellationToken cancellationToken)
31 | {
32 | try
33 | {
34 | var document = SnapshotSpan.Snapshot.TextBuffer.GetRelatedDocuments().FirstOrDefault();
35 | _codeDoc = document;
36 | _symbol = document != null ? await GetSymbol(document, SnapshotSpan.Start, cancellationToken) : null;
37 | return _symbol != null;
38 | }
39 | catch
40 | {
41 | return false;
42 | }
43 | }
44 |
45 | public ISymbol Symbol => _symbol;
46 | protected abstract Task GetSymbol(Document document, int tokenPosition, CancellationToken cancellationToken);
47 | public abstract string DisplayText { get; }
48 | public string IconAutomationText => "Disamo";
49 | ImageMoniker ISuggestedAction.IconMoniker => KnownMonikers.CSLightswitch;
50 | public string InputGestureText => null;
51 | public bool HasActionSets => false;
52 | public Task> GetActionSetsAsync(CancellationToken cancellationToken) => null;
53 | public bool HasPreview => false;
54 | public Task