Skip to content

Commit

Permalink
Initial
Browse files Browse the repository at this point in the history
  • Loading branch information
alejandro committed Jan 6, 2023
1 parent 602eb53 commit 58e5cc9
Show file tree
Hide file tree
Showing 17 changed files with 842 additions and 0 deletions.
18 changes: 18 additions & 0 deletions Commands/MyToolWindowCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
namespace NavigateToHandlerPubSub
{
[Command(PackageIds.ShowHandlersCommand)]
internal sealed class MyToolWindowCommand : BaseCommand<MyToolWindowCommand>
{
protected override async Task ExecuteAsync(OleMenuCmdEventArgs e)
{
await MyToolWindow.ShowAsync();

await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
ThreadHelper.JoinableTaskFactory.RunAsync(async () =>
{
ToolWindowMessenger messenger = await Package.GetServiceAsync<ToolWindowMessenger, ToolWindowMessenger>();
messenger.Send("Refresh Handlers Files");
}).FireAndForget();
}
}
}
124 changes: 124 additions & 0 deletions Logic/FindHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
using Microsoft.Build.Framework.XamlTypes;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.Text;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading.Tasks;

namespace NavigateToHandlerPubSub.Logic
{
public class FindHandler
{
public async Task<List<IdentifiedHandler>> FindHandlersAsync(Microsoft.CodeAnalysis.Solution solution, Document workingDocument, int linePosition, string projectName)
{
var syntaxRoot = await workingDocument.GetSyntaxRootAsync();
var syntaxNode = syntaxRoot?.FindNode(new TextSpan(linePosition, 0), true, true);

// Get type information

var semanticModel = await workingDocument.GetSemanticModelAsync();
await VS.StatusBar.ShowProgressAsync("Get document model", 2, 3);

var symbol = GetTypeInfo(semanticModel, syntaxNode);

var handlers = await GetEventHandlerReferencesAsync(symbol, solution, projectName);
await VS.StatusBar.ShowProgressAsync("Getting references", 3, 3);

return handlers;
}

private ITypeSymbol GetTypeInfo(SemanticModel semanticModel, SyntaxNode syntaxNode)
{
if (syntaxNode is VariableDeclaratorSyntax variableDeclarator)
{
return semanticModel.GetTypeInfo(((VariableDeclarationSyntax)variableDeclarator.Parent).Type).Type;
}
if (syntaxNode is TypeDeclarationSyntax typeDeclarationSyntax)
{
return semanticModel.GetDeclaredSymbol(typeDeclarationSyntax);
}
if (syntaxNode is IdentifierNameSyntax identifierName)
{
var accessSymbol = semanticModel.GetSymbolInfo(identifierName.Parent);
IMethodSymbol methodSymbol = (IMethodSymbol)accessSymbol.Symbol;
if (methodSymbol == null) return null;

var returnType = (INamedTypeSymbol)methodSymbol.ReceiverType;
return returnType;
}

return semanticModel.GetTypeInfo(syntaxNode).Type;
}

private async Task<List<IdentifiedHandler>> GetEventHandlerReferencesAsync(ITypeSymbol symbol, Microsoft.CodeAnalysis.Solution solution, string projectName)
{
if (symbol == null)
return default;

List<IdentifiedHandler> handlers = new();

IEnumerable<ReferencedSymbol> references = default;
ImmutableArray<ITypeSymbol> arguments = default;

if (symbol is INamedTypeSymbol named)
{
arguments = named.TypeArguments;

if (arguments.Any())
{
symbol = arguments.First();
}
}
references = await SymbolFinder.FindReferencesAsync(symbol, solution);

foreach (var reference in references)
{
var locations = string.IsNullOrWhiteSpace(projectName) ?
reference.Locations
: reference.Locations.Where(l => l.Document.Project.AssemblyName == projectName);

foreach (var location in locations)
{
var tree = await location.Document.GetSyntaxTreeAsync();
var root = await tree.GetRootAsync();
var allMethods = root.DescendantNodes().OfType<MethodDeclarationSyntax>();
var publicMethods = default(IEnumerable<MethodDeclarationSyntax>);
publicMethods = allMethods.Where(publicMethod =>
publicMethod.Modifiers.Any(modifier => modifier.Text.Equals("public")) &&
publicMethod.ToFullString().Contains("HandleAsync") &&
publicMethod.ParameterList.Parameters.Any(parameter => parameter.ToFullString().Contains(symbol.Name)));

if (!publicMethods.Any())
continue;

if (arguments != default && arguments.Count() > 1)
{
var argumentName = arguments.Last().ToString();
var argumentParsed = argumentName.Split('.');

if (argumentParsed.Count() > 1)
argumentName = argumentParsed.Last();
publicMethods = publicMethods.Where(publicMethod => publicMethod.ReturnType.ToFullString().Contains(argumentName));

if (!publicMethods.Any())
continue;
}

if (!handlers.Any(x => x.SourceFile == location.Document.FilePath))
handlers.Add(new IdentifiedHandler
{
FileName = location.Document.Name,
SourceFile = location.Document.FilePath,
LineNumber = publicMethods.First().SpanStart
});
}
}

return handlers;
}
}
}
67 changes: 67 additions & 0 deletions Logic/IdentifiedHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
using System.ComponentModel;

namespace NavigateToHandlerPubSub.Logic
{
public class IdentifiedHandler : INotifyPropertyChanged
{
private string fileName;
public string FileName
{
get
{
return fileName;
}
set
{
if (fileName != value)
{
fileName = value;
OnPropertyChanged("FileName");
}
}
}
private string sourceFile;
public string SourceFile
{
get
{
return sourceFile;
}
set
{
if (sourceFile != value)
{
sourceFile = value;
OnPropertyChanged("SourceFile");
}
}
}

private int lineNumber;
public int LineNumber
{
get
{
return lineNumber;
}
set
{
if (lineNumber != value)
{
lineNumber = value;
OnPropertyChanged("LineNumber");
}
}
}

public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(String info)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(info));
}
}
}
}
137 changes: 137 additions & 0 deletions NavigateToHandlerPubSub.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<SchemaVersion>2.0</SchemaVersion>
<ProjectTypeGuids>{82b43b9b-a64c-4715-b499-d71e9ca2bd60};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<ProjectGuid>{0A887131-CD6F-4B38-9305-A00ED936AB29}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>NavigateToHandlerPubSub</RootNamespace>
<AssemblyName>NavigateToHandlerPubSub</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<GeneratePkgDefFile>true</GeneratePkgDefFile>
<UseCodebase>true</UseCodebase>
<IncludeAssemblyInVSIXContainer>true</IncludeAssemblyInVSIXContainer>
<IncludeDebugSymbolsInVSIXContainer>true</IncludeDebugSymbolsInVSIXContainer>
<IncludeDebugSymbolsInLocalVSIXDeployment>false</IncludeDebugSymbolsInLocalVSIXDeployment>
<CopyBuildOutputToOutputDirectory>true</CopyBuildOutputToOutputDirectory>
<CopyOutputSymbolsToOutputDirectory>true</CopyOutputSymbolsToOutputDirectory>
<StartAction>Program</StartAction>
<StartProgram Condition="'$(DevEnvDir)' != ''">$(DevEnvDir)devenv.exe</StartProgram>
<StartArguments>/rootsuffix Exp</StartArguments>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Compile Include="Logic\FindHandler.cs" />
<Compile Include="Logic\IdentifiedHandler.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Commands\MyToolWindowCommand.cs" />
<Compile Include="NavigateToHandlerPubSubPackage.cs" />
<Compile Include="source.extension.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>source.extension.vsixmanifest</DependentUpon>
</Compile>
<Compile Include="ToolWindowMessenger.cs" />
<Compile Include="ToolWindows\SelectionContextItem.cs" />
<Compile Include="VSCommandTable.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>VSCommandTable.vsct</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<None Include="source.extension.vsixmanifest">
<SubType>Designer</SubType>
<Generator>VsixManifestGenerator</Generator>
<LastGenOutput>source.extension.cs</LastGenOutput>
</None>
<Content Include="Resources\Icon.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<IncludeInVSIX>true</IncludeInVSIX>
</Content>
</ItemGroup>
<ItemGroup>
<VSCTCompile Include="VSCommandTable.vsct">
<ResourceName>Menus.ctmenu</ResourceName>
<Generator>VsctGenerator</Generator>
<LastGenOutput>VSCommandTable.cs</LastGenOutput>
</VSCTCompile>
</ItemGroup>
<ItemGroup>
<Compile Include="ToolWindows\MyToolWindow.cs" />
<Page Include="ToolWindows\MyToolWindowControl.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Compile Include="ToolWindows\MyToolWindowControl.xaml.cs">
<DependentUpon>MyToolWindowControl.xaml</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Design" />
<Reference Include="System.Xaml" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
<Reference Include="WindowsBase" />
<Reference Include="System.ComponentModel.Composition" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Community.VisualStudio.VSCT" Version="16.0.29.6" PrivateAssets="all" />
<PackageReference Include="Community.VisualStudio.Toolkit.17" Version="17.0.486" ExcludeAssets="Runtime">
<IncludeAssets>compile; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp">
<Version>4.4.0</Version>
</PackageReference>
<PackageReference Include="Microsoft.VisualStudio.Imaging">
<Version>17.0.31723.112</Version>
</PackageReference>
<PackageReference Include="Microsoft.VisualStudio.LanguageServices">
<Version>4.4.0</Version>
</PackageReference>
<PackageReference Include="Microsoft.VisualStudio.SDK">
<Version>17.4.33103.184</Version>
</PackageReference>
<PackageReference Include="Microsoft.VisualStudio.Shell.15.0">
<Version>17.0.31723.112</Version>
</PackageReference>
<PackageReference Include="Microsoft.VSSDK.BuildTools" Version="17.4.2119">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="$(VSToolsPath)\VSSDK\Microsoft.VsSDK.targets" Condition="'$(VSToolsPath)' != ''" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
37 changes: 37 additions & 0 deletions NavigateToHandlerPubSub.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.4.33205.214
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NavigateToHandlerPubSub", "NavigateToHandlerPubSub.csproj", "{0A887131-CD6F-4B38-9305-A00ED936AB29}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|arm64 = Debug|arm64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|arm64 = Release|arm64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{0A887131-CD6F-4B38-9305-A00ED936AB29}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0A887131-CD6F-4B38-9305-A00ED936AB29}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0A887131-CD6F-4B38-9305-A00ED936AB29}.Debug|arm64.ActiveCfg = Debug|arm64
{0A887131-CD6F-4B38-9305-A00ED936AB29}.Debug|arm64.Build.0 = Debug|arm64
{0A887131-CD6F-4B38-9305-A00ED936AB29}.Debug|x86.ActiveCfg = Debug|x86
{0A887131-CD6F-4B38-9305-A00ED936AB29}.Debug|x86.Build.0 = Debug|x86
{0A887131-CD6F-4B38-9305-A00ED936AB29}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0A887131-CD6F-4B38-9305-A00ED936AB29}.Release|Any CPU.Build.0 = Release|Any CPU
{0A887131-CD6F-4B38-9305-A00ED936AB29}.Release|arm64.ActiveCfg = Release|arm64
{0A887131-CD6F-4B38-9305-A00ED936AB29}.Release|arm64.Build.0 = Release|arm64
{0A887131-CD6F-4B38-9305-A00ED936AB29}.Release|x86.ActiveCfg = Release|x86
{0A887131-CD6F-4B38-9305-A00ED936AB29}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {6CF82DC8-FBF6-4430-9622-5E02D7C8B399}
EndGlobalSection
EndGlobal
Loading

0 comments on commit 58e5cc9

Please sign in to comment.