diff --git a/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.CodeFixes/CodeFixResources.Designer.cs b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.CodeFixes/CodeFixResources.Designer.cs
new file mode 100644
index 0000000..659c9ec
--- /dev/null
+++ b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.CodeFixes/CodeFixResources.Designer.cs
@@ -0,0 +1,83 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.0
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+using System;
+using System.Reflection;
+
+namespace Misaki.HighPerformance.Analyzer
+{
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class CodeFixResources
+ {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal CodeFixResources()
+ {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager
+ {
+ get
+ {
+ if (object.ReferenceEquals(resourceMan, null))
+ {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Misaki.HighPerformance.Analyzer.CodeFixResources", typeof(CodeFixResources).GetTypeInfo().Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture
+ {
+ get
+ {
+ return resourceCulture;
+ }
+ set
+ {
+ resourceCulture = value;
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Make uppercase.
+ ///
+ internal static string CodeFixTitle
+ {
+ get
+ {
+ return ResourceManager.GetString("CodeFixTitle", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.CodeFixes/CodeFixResources.resx b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.CodeFixes/CodeFixResources.resx
new file mode 100644
index 0000000..97abe68
--- /dev/null
+++ b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.CodeFixes/CodeFixResources.resx
@@ -0,0 +1,124 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ Make uppercase
+ The title of the code fix.
+
+
\ No newline at end of file
diff --git a/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.CodeFixes/Misaki.HighPerformance.Analyzer.CodeFixes.csproj b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.CodeFixes/Misaki.HighPerformance.Analyzer.CodeFixes.csproj
new file mode 100644
index 0000000..85d894b
--- /dev/null
+++ b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.CodeFixes/Misaki.HighPerformance.Analyzer.CodeFixes.csproj
@@ -0,0 +1,22 @@
+
+
+
+ netstandard2.0
+ false
+ Misaki.HighPerformance.Analyzer
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.CodeFixes/StructCopyCodeFixProvider.cs b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.CodeFixes/StructCopyCodeFixProvider.cs
new file mode 100644
index 0000000..4d9b6c3
--- /dev/null
+++ b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.CodeFixes/StructCopyCodeFixProvider.cs
@@ -0,0 +1,91 @@
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CodeActions;
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Formatting;
+using System.Collections.Immutable;
+using System.Composition;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Misaki.HighPerformance.Analyzer
+{
+ [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(StructCopyCodeFixProvider)), Shared]
+ public class StructCopyCodeFixProvider : CodeFixProvider
+ {
+ public sealed override ImmutableArray FixableDiagnosticIds
+ {
+ get
+ {
+ return ImmutableArray.Create(StructCopyCodeAnalyzer.DIAGNOSTIC_ID);
+ }
+ }
+
+ public sealed override FixAllProvider GetFixAllProvider()
+ {
+ // See https://github.com/dotnet/roslyn/blob/main/docs/analyzers/FixAllProvider.md for more information on Fix All Providers
+ return WellKnownFixAllProviders.BatchFixer;
+ }
+
+ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
+ {
+ var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
+ var diagnostic = context.Diagnostics.First();
+ var diagnosticSpan = diagnostic.Location.SourceSpan;
+
+ // Find the expression identified by the diagnostic.
+ // This will be the Right-Hand Side (RHS) of the assignment or declaration
+ var expressionSyntax = root.FindToken(diagnosticSpan.Start).Parent.AncestorsAndSelf()
+ .OfType()
+ .First();
+
+ // Register a code action that will invoke the fix.
+ context.RegisterCodeFix(
+ CodeAction.Create(
+ title: "Share",
+ createChangedDocument: c => TransferOwnershipAsync(context.Document, expressionSyntax, c),
+ equivalenceKey: nameof(StructCopyCodeFixProvider)),
+ diagnostic);
+ }
+
+ private async Task TransferOwnershipAsync(Document document, ExpressionSyntax expressionToFix, CancellationToken cancellationToken)
+ {
+ // 1. Get the semantic model to figure out exactly what type we are dealing with
+ var semanticModel = await document.GetSemanticModelAsync(cancellationToken);
+ var typeSymbol = semanticModel.GetTypeInfo(expressionToFix).Type;
+
+ // 2. Generate the type name string (e.g., "UniquePtr")
+ // We use ToMinimalDisplayString so Roslyn handles namespaces/using directives automatically.
+ var typeName = typeSymbol.ToMinimalDisplayString(semanticModel, expressionToFix.SpanStart);
+ var typeSyntax = SyntaxFactory.ParseTypeName(typeName);
+
+ // 3. Create the "Share()" invocation: expression.Share()
+ var detachMethod = SyntaxFactory.MemberAccessExpression(
+ SyntaxKind.SimpleMemberAccessExpression,
+ expressionToFix, // The 'a' in 'b = a'
+ SyntaxFactory.IdentifierName("Share")
+ );
+
+ var detachInvocation = SyntaxFactory.InvocationExpression(detachMethod);
+
+ // 4. Create the "new UniquePtr(...)" expression
+ var newObjectCreation = SyntaxFactory.ObjectCreationExpression(typeSyntax)
+ .WithArgumentList(
+ SyntaxFactory.ArgumentList(
+ SyntaxFactory.SingletonSeparatedList(
+ SyntaxFactory.Argument(detachInvocation)
+ )
+ )
+ )
+ .WithAdditionalAnnotations(Formatter.Annotation); // Auto-format whitespace
+
+ // 5. Replace the old node with the new node in the Syntax Tree
+ var root = await document.GetSyntaxRootAsync(cancellationToken);
+ var newRoot = root.ReplaceNode(expressionToFix, newObjectCreation);
+
+ return document.WithSyntaxRoot(newRoot);
+ }
+ }
+}
diff --git a/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Package/Misaki.HighPerformance.Analyzer.Package.csproj b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Package/Misaki.HighPerformance.Analyzer.Package.csproj
new file mode 100644
index 0000000..c290a5d
--- /dev/null
+++ b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Package/Misaki.HighPerformance.Analyzer.Package.csproj
@@ -0,0 +1,40 @@
+
+
+
+ netstandard2.0
+ False
+ True
+ True
+ 1.0.0
+
+
+
+ Misaki.HighPerformance.Analyzer
+ $(AssemblyVersion)
+ Misaki
+ False
+ Misaki.HighPerformance.Analyzer
+ Misaki.HighPerformance.Analyzer, analyzers
+ True
+ True
+
+ $(TargetsForTfmSpecificContentInPackage);_AddAnalyzersToOutput
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Package/tools/install.ps1 b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Package/tools/install.ps1
new file mode 100644
index 0000000..53136a2
--- /dev/null
+++ b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Package/tools/install.ps1
@@ -0,0 +1,275 @@
+param($installPath, $toolsPath, $package, $project)
+
+if($project.Object.SupportsPackageDependencyResolution)
+{
+ if($project.Object.SupportsPackageDependencyResolution())
+ {
+ # Do not install analyzers via install.ps1, instead let the project system handle it.
+ return
+ }
+}
+
+$analyzersPaths = Join-Path (Join-Path (Split-Path -Path $toolsPath -Parent) "analyzers") * -Resolve
+
+foreach($analyzersPath in $analyzersPaths)
+{
+ if (Test-Path $analyzersPath)
+ {
+ # Install the language agnostic analyzers.
+ foreach ($analyzerFilePath in Get-ChildItem -Path "$analyzersPath\*.dll" -Exclude *.resources.dll)
+ {
+ if($project.Object.AnalyzerReferences)
+ {
+ $project.Object.AnalyzerReferences.Add($analyzerFilePath.FullName)
+ }
+ }
+ }
+}
+
+# $project.Type gives the language name like (C# or VB.NET)
+$languageFolder = ""
+if($project.Type -eq "C#")
+{
+ $languageFolder = "cs"
+}
+if($project.Type -eq "VB.NET")
+{
+ $languageFolder = "vb"
+}
+if($languageFolder -eq "")
+{
+ return
+}
+
+foreach($analyzersPath in $analyzersPaths)
+{
+ # Install language specific analyzers.
+ $languageAnalyzersPath = join-path $analyzersPath $languageFolder
+ if (Test-Path $languageAnalyzersPath)
+ {
+ foreach ($analyzerFilePath in Get-ChildItem -Path "$languageAnalyzersPath\*.dll" -Exclude *.resources.dll)
+ {
+ if($project.Object.AnalyzerReferences)
+ {
+ $project.Object.AnalyzerReferences.Add($analyzerFilePath.FullName)
+ }
+ }
+ }
+}
+# SIG # Begin signature block
+# MIIoKgYJKoZIhvcNAQcCoIIoGzCCKBcCAQExDzANBglghkgBZQMEAgEFADB5Bgor
+# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
+# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCA/i+qRUHsWzI0s
+# FVk99zLgt/HOEQ33uvkFsWtHTHZgf6CCDXYwggX0MIID3KADAgECAhMzAAADTrU8
+# esGEb+srAAAAAANOMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD
+# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
+# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
+# bmcgUENBIDIwMTEwHhcNMjMwMzE2MTg0MzI5WhcNMjQwMzE0MTg0MzI5WjB0MQsw
+# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
+# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy
+# b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
+# AQDdCKiNI6IBFWuvJUmf6WdOJqZmIwYs5G7AJD5UbcL6tsC+EBPDbr36pFGo1bsU
+# p53nRyFYnncoMg8FK0d8jLlw0lgexDDr7gicf2zOBFWqfv/nSLwzJFNP5W03DF/1
+# 1oZ12rSFqGlm+O46cRjTDFBpMRCZZGddZlRBjivby0eI1VgTD1TvAdfBYQe82fhm
+# WQkYR/lWmAK+vW/1+bO7jHaxXTNCxLIBW07F8PBjUcwFxxyfbe2mHB4h1L4U0Ofa
+# +HX/aREQ7SqYZz59sXM2ySOfvYyIjnqSO80NGBaz5DvzIG88J0+BNhOu2jl6Dfcq
+# jYQs1H/PMSQIK6E7lXDXSpXzAgMBAAGjggFzMIIBbzAfBgNVHSUEGDAWBgorBgEE
+# AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUnMc7Zn/ukKBsBiWkwdNfsN5pdwAw
+# RQYDVR0RBD4wPKQ6MDgxHjAcBgNVBAsTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEW
+# MBQGA1UEBRMNMjMwMDEyKzUwMDUxNjAfBgNVHSMEGDAWgBRIbmTlUAXTgqoXNzci
+# tW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8vd3d3Lm1pY3Jvc29mdC5j
+# b20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3JsMGEG
+# CCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDovL3d3dy5taWNyb3NvZnQu
+# Y29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3J0
+# MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIBAD21v9pHoLdBSNlFAjmk
+# mx4XxOZAPsVxxXbDyQv1+kGDe9XpgBnT1lXnx7JDpFMKBwAyIwdInmvhK9pGBa31
+# TyeL3p7R2s0L8SABPPRJHAEk4NHpBXxHjm4TKjezAbSqqbgsy10Y7KApy+9UrKa2
+# kGmsuASsk95PVm5vem7OmTs42vm0BJUU+JPQLg8Y/sdj3TtSfLYYZAaJwTAIgi7d
+# hzn5hatLo7Dhz+4T+MrFd+6LUa2U3zr97QwzDthx+RP9/RZnur4inzSQsG5DCVIM
+# pA1l2NWEA3KAca0tI2l6hQNYsaKL1kefdfHCrPxEry8onJjyGGv9YKoLv6AOO7Oh
+# JEmbQlz/xksYG2N/JSOJ+QqYpGTEuYFYVWain7He6jgb41JbpOGKDdE/b+V2q/gX
+# UgFe2gdwTpCDsvh8SMRoq1/BNXcr7iTAU38Vgr83iVtPYmFhZOVM0ULp/kKTVoir
+# IpP2KCxT4OekOctt8grYnhJ16QMjmMv5o53hjNFXOxigkQWYzUO+6w50g0FAeFa8
+# 5ugCCB6lXEk21FFB1FdIHpjSQf+LP/W2OV/HfhC3uTPgKbRtXo83TZYEudooyZ/A
+# Vu08sibZ3MkGOJORLERNwKm2G7oqdOv4Qj8Z0JrGgMzj46NFKAxkLSpE5oHQYP1H
+# tPx1lPfD7iNSbJsP6LiUHXH1MIIHejCCBWKgAwIBAgIKYQ6Q0gAAAAAAAzANBgkq
+# hkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x
+# EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv
+# bjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5
+# IDIwMTEwHhcNMTEwNzA4MjA1OTA5WhcNMjYwNzA4MjEwOTA5WjB+MQswCQYDVQQG
+# EwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwG
+# A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSgwJgYDVQQDEx9NaWNyb3NvZnQg
+# Q29kZSBTaWduaW5nIFBDQSAyMDExMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
+# CgKCAgEAq/D6chAcLq3YbqqCEE00uvK2WCGfQhsqa+laUKq4BjgaBEm6f8MMHt03
+# a8YS2AvwOMKZBrDIOdUBFDFC04kNeWSHfpRgJGyvnkmc6Whe0t+bU7IKLMOv2akr
+# rnoJr9eWWcpgGgXpZnboMlImEi/nqwhQz7NEt13YxC4Ddato88tt8zpcoRb0Rrrg
+# OGSsbmQ1eKagYw8t00CT+OPeBw3VXHmlSSnnDb6gE3e+lD3v++MrWhAfTVYoonpy
+# 4BI6t0le2O3tQ5GD2Xuye4Yb2T6xjF3oiU+EGvKhL1nkkDstrjNYxbc+/jLTswM9
+# sbKvkjh+0p2ALPVOVpEhNSXDOW5kf1O6nA+tGSOEy/S6A4aN91/w0FK/jJSHvMAh
+# dCVfGCi2zCcoOCWYOUo2z3yxkq4cI6epZuxhH2rhKEmdX4jiJV3TIUs+UsS1Vz8k
+# A/DRelsv1SPjcF0PUUZ3s/gA4bysAoJf28AVs70b1FVL5zmhD+kjSbwYuER8ReTB
+# w3J64HLnJN+/RpnF78IcV9uDjexNSTCnq47f7Fufr/zdsGbiwZeBe+3W7UvnSSmn
+# Eyimp31ngOaKYnhfsi+E11ecXL93KCjx7W3DKI8sj0A3T8HhhUSJxAlMxdSlQy90
+# lfdu+HggWCwTXWCVmj5PM4TasIgX3p5O9JawvEagbJjS4NaIjAsCAwEAAaOCAe0w
+# ggHpMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBRIbmTlUAXTgqoXNzcitW2o
+# ynUClTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMCAYYwDwYD
+# VR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBRyLToCMZBDuRQFTuHqp8cx0SOJNDBa
+# BgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2Ny
+# bC9wcm9kdWN0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3JsMF4GCCsG
+# AQUFBwEBBFIwUDBOBggrBgEFBQcwAoZCaHR0cDovL3d3dy5taWNyb3NvZnQuY29t
+# L3BraS9jZXJ0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3J0MIGfBgNV
+# HSAEgZcwgZQwgZEGCSsGAQQBgjcuAzCBgzA/BggrBgEFBQcCARYzaHR0cDovL3d3
+# dy5taWNyb3NvZnQuY29tL3BraW9wcy9kb2NzL3ByaW1hcnljcHMuaHRtMEAGCCsG
+# AQUFBwICMDQeMiAdAEwAZQBnAGEAbABfAHAAbwBsAGkAYwB5AF8AcwB0AGEAdABl
+# AG0AZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4ICAQBn8oalmOBUeRou09h0ZyKb
+# C5YR4WOSmUKWfdJ5DJDBZV8uLD74w3LRbYP+vj/oCso7v0epo/Np22O/IjWll11l
+# hJB9i0ZQVdgMknzSGksc8zxCi1LQsP1r4z4HLimb5j0bpdS1HXeUOeLpZMlEPXh6
+# I/MTfaaQdION9MsmAkYqwooQu6SpBQyb7Wj6aC6VoCo/KmtYSWMfCWluWpiW5IP0
+# wI/zRive/DvQvTXvbiWu5a8n7dDd8w6vmSiXmE0OPQvyCInWH8MyGOLwxS3OW560
+# STkKxgrCxq2u5bLZ2xWIUUVYODJxJxp/sfQn+N4sOiBpmLJZiWhub6e3dMNABQam
+# ASooPoI/E01mC8CzTfXhj38cbxV9Rad25UAqZaPDXVJihsMdYzaXht/a8/jyFqGa
+# J+HNpZfQ7l1jQeNbB5yHPgZ3BtEGsXUfFL5hYbXw3MYbBL7fQccOKO7eZS/sl/ah
+# XJbYANahRr1Z85elCUtIEJmAH9AAKcWxm6U/RXceNcbSoqKfenoi+kiVH6v7RyOA
+# 9Z74v2u3S5fi63V4GuzqN5l5GEv/1rMjaHXmr/r8i+sLgOppO6/8MO0ETI7f33Vt
+# Y5E90Z1WTk+/gFcioXgRMiF670EKsT/7qMykXcGhiJtXcVZOSEXAQsmbdlsKgEhr
+# /Xmfwb1tbWrJUnMTDXpQzTGCGgowghoGAgEBMIGVMH4xCzAJBgNVBAYTAlVTMRMw
+# EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN
+# aWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNp
+# Z25pbmcgUENBIDIwMTECEzMAAANOtTx6wYRv6ysAAAAAA04wDQYJYIZIAWUDBAIB
+# BQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEO
+# MAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIEY4Ow3COroWH11sAEOoStJj
+# 1u4sq9rcx0dAx0gyZLHCMEIGCisGAQQBgjcCAQwxNDAyoBSAEgBNAGkAYwByAG8A
+# cwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20wDQYJKoZIhvcNAQEB
+# BQAEggEAFlSLlk17KQp2AwLbr5e4T5zyE44MGZOdNejIip+Mg8co8qho16qdNSvg
+# AhvoJYxPJJr70DSCU9BIUoWY7hXoi9S4P08YlAid7BUT5OciIgHlrb8I900LaE+S
+# 83rSvfVU1CZCjiSwcgng5DD2VPRo0Lu4G9p2Ky14dyOPwtPvrpsib5s9kewZLdiy
+# /KxEDLKX8P+cHat1xH7RaZLDNxweRS6GSomjE2vjOlQHNSW879XR8bSoAt/m4uR1
+# WyrAxTGZb4miEYX+I5HsrWvbZLw9NSCJ/crbbap3LIobfQtK5binjY7v4MQp/5Oq
+# y4S/4FAfwhWDXfaQfq6YTeOjHRVQbKGCF5QwgheQBgorBgEEAYI3AwMBMYIXgDCC
+# F3wGCSqGSIb3DQEHAqCCF20wghdpAgEDMQ8wDQYJYIZIAWUDBAIBBQAwggFSBgsq
+# hkiG9w0BCRABBKCCAUEEggE9MIIBOQIBAQYKKwYBBAGEWQoDATAxMA0GCWCGSAFl
+# AwQCAQUABCCV3irbWIoYz2Llfx9YQhUNtcP6GOrL7+YTUXQ4y5qzWAIGZNTJrsAW
+# GBMyMDIzMDgzMTAwMTI1OC45ODNaMASAAgH0oIHRpIHOMIHLMQswCQYDVQQGEwJV
+# UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE
+# ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSUwIwYDVQQLExxNaWNyb3NvZnQgQW1l
+# cmljYSBPcGVyYXRpb25zMScwJQYDVQQLEx5uU2hpZWxkIFRTUyBFU046OTIwMC0w
+# NUUwLUQ5NDcxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2Wg
+# ghHqMIIHIDCCBQigAwIBAgITMwAAAc9SNr5xS81IygABAAABzzANBgkqhkiG9w0B
+# AQsFADB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE
+# BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYD
+# VQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDAeFw0yMzA1MjUxOTEy
+# MTFaFw0yNDAyMDExOTEyMTFaMIHLMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2Fz
+# aGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENv
+# cnBvcmF0aW9uMSUwIwYDVQQLExxNaWNyb3NvZnQgQW1lcmljYSBPcGVyYXRpb25z
+# MScwJQYDVQQLEx5uU2hpZWxkIFRTUyBFU046OTIwMC0wNUUwLUQ5NDcxJTAjBgNV
+# BAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2UwggIiMA0GCSqGSIb3DQEB
+# AQUAA4ICDwAwggIKAoICAQC4Pct+15TYyrUje553lzBQodgmd5Bz7WuH8SdHpAoW
+# z+01TrHExBSuaMKnxvVMsyYtas5h6aopUGAS5WKVLZAvUtH62TKmAE0JK+i1hafi
+# CSXLZPcRexxeRkOqeZefLBzXp0nudMOXUUab333Ss8LkoK4l3LYxm1Ebsr3b2OTo
+# 2ebsAoNJ4kSxmVuPM7C+RDhGtVKR/EmHsQ9GcwGmluu54bqiVFd0oAFBbw4txTU1
+# mruIGWP/i+sgiNqvdV/wah/QcrKiGlpWiOr9a5aGrJaPSQD2xgEDdPbrSflYxsRM
+# dZCJI8vzvOv6BluPcPPGGVLEaU7OszdYjK5f4Z5Su/lPK1eST5PC4RFsVcOiS4L0
+# sI4IFZywIdDJHoKgdqWRp6Q5vEDk8kvZz6HWFnYLOlHuqMEYvQLr6OgooYU9z0A5
+# cMLHEIHYV1xiaBzx2ERiRY9MUPWohh+TpZWEUZlUm/q9anXVRN0ujejm6OsUVFDs
+# sIMszRNCqEotJGwtHHm5xrCKuJkFr8GfwNelFl+XDoHXrQYL9zY7Np+frsTXQpKR
+# NnmI1ashcn5EC+wxUt/EZIskWzewEft0/+/0g3+8YtMkUdaQE5+8e7C8UMiXOHkM
+# K25jNNQqLCedlJwFIf9ir9SpMc72NR+1j6Uebiz/ZPV74do3jdVvq7DiPFlTb92U
+# KwIDAQABo4IBSTCCAUUwHQYDVR0OBBYEFDaeKPtp0eTSVdG+gZc5BDkabTg4MB8G
+# A1UdIwQYMBaAFJ+nFV0AXmJdg/Tl0mWnG1M1GelyMF8GA1UdHwRYMFYwVKBSoFCG
+# Tmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY3Jvc29mdCUy
+# MFRpbWUtU3RhbXAlMjBQQ0ElMjAyMDEwKDEpLmNybDBsBggrBgEFBQcBAQRgMF4w
+# XAYIKwYBBQUHMAKGUGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY2Vy
+# dHMvTWljcm9zb2Z0JTIwVGltZS1TdGFtcCUyMFBDQSUyMDIwMTAoMSkuY3J0MAwG
+# A1UdEwEB/wQCMAAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwDgYDVR0PAQH/BAQD
+# AgeAMA0GCSqGSIb3DQEBCwUAA4ICAQBQgm4pnA0xkd/9uKXJMzdMYyxUfUm/ZusU
+# Ba32MEZXQuMGp20pSuX2VW9/tpTMo5bkaJdBVoUyd2DbDsNb1kjr/36ntT0jvL3A
+# oWStAFhZBypmpPbx+BPK49ZlejlM4d5epX668tRRGfFip9Til9yKRfXBrXnM/q64
+# IinN7zXEQ3FFQhdJMzt8ibXClO7eFA+1HiwZPWysYWPb/ZOFobPEMvXie+GmEbTK
+# bhE5tze6RrA9aejjP+v1ouFoD5bMj5Qg+wfZXqe+hfYKpMd8QOnQyez+Nlj1ityn
+# OZWfwHVR7dVwV0yLSlPT+yHIO8g+3fWiAwpoO17bDcntSZ7YOBljXrIgad4W4gX+
+# 4tp1eBsc6XWIITPBNzxQDZZRxD4rXzOB6XRlEVJdYZQ8gbXOirg/dNvS2GxcR50Q
+# dOXDAumdEHaGNHb6y2InJadCPp2iT5QLC4MnzR+YZno1b8mWpCdOdRs9g21QbbrI
+# 06iLk9KD61nx7K5ReSucuS5Z9nbkIBaLUxDesFhr1wmd1ynf0HQ51Swryh7YI7TX
+# T0jr81mbvvI9xtoqjFvIhNBsICdCfTR91ylJTH8WtUlpDhEgSqWt3gzNLPTSvXAx
+# XTpIM583sZdd+/2YGADMeWmt8PuMce6GsIcLCOF2NiYZ10SXHZS5HRrLrChuzedD
+# RisWpIu5uTCCB3EwggVZoAMCAQICEzMAAAAVxedrngKbSZkAAAAAABUwDQYJKoZI
+# hvcNAQELBQAwgYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAw
+# DgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24x
+# MjAwBgNVBAMTKU1pY3Jvc29mdCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAy
+# MDEwMB4XDTIxMDkzMDE4MjIyNVoXDTMwMDkzMDE4MzIyNVowfDELMAkGA1UEBhMC
+# VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV
+# BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRp
+# bWUtU3RhbXAgUENBIDIwMTAwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
+# AQDk4aZM57RyIQt5osvXJHm9DtWC0/3unAcH0qlsTnXIyjVX9gF/bErg4r25Phdg
+# M/9cT8dm95VTcVrifkpa/rg2Z4VGIwy1jRPPdzLAEBjoYH1qUoNEt6aORmsHFPPF
+# dvWGUNzBRMhxXFExN6AKOG6N7dcP2CZTfDlhAnrEqv1yaa8dq6z2Nr41JmTamDu6
+# GnszrYBbfowQHJ1S/rboYiXcag/PXfT+jlPP1uyFVk3v3byNpOORj7I5LFGc6XBp
+# Dco2LXCOMcg1KL3jtIckw+DJj361VI/c+gVVmG1oO5pGve2krnopN6zL64NF50Zu
+# yjLVwIYwXE8s4mKyzbnijYjklqwBSru+cakXW2dg3viSkR4dPf0gz3N9QZpGdc3E
+# XzTdEonW/aUgfX782Z5F37ZyL9t9X4C626p+Nuw2TPYrbqgSUei/BQOj0XOmTTd0
+# lBw0gg/wEPK3Rxjtp+iZfD9M269ewvPV2HM9Q07BMzlMjgK8QmguEOqEUUbi0b1q
+# GFphAXPKZ6Je1yh2AuIzGHLXpyDwwvoSCtdjbwzJNmSLW6CmgyFdXzB0kZSU2LlQ
+# +QuJYfM2BjUYhEfb3BvR/bLUHMVr9lxSUV0S2yW6r1AFemzFER1y7435UsSFF5PA
+# PBXbGjfHCBUYP3irRbb1Hode2o+eFnJpxq57t7c+auIurQIDAQABo4IB3TCCAdkw
+# EgYJKwYBBAGCNxUBBAUCAwEAATAjBgkrBgEEAYI3FQIEFgQUKqdS/mTEmr6CkTxG
+# NSnPEP8vBO4wHQYDVR0OBBYEFJ+nFV0AXmJdg/Tl0mWnG1M1GelyMFwGA1UdIARV
+# MFMwUQYMKwYBBAGCN0yDfQEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly93d3cubWlj
+# cm9zb2Z0LmNvbS9wa2lvcHMvRG9jcy9SZXBvc2l0b3J5Lmh0bTATBgNVHSUEDDAK
+# BggrBgEFBQcDCDAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMC
+# AYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBTV9lbLj+iiXGJo0T2UkFvX
+# zpoYxDBWBgNVHR8ETzBNMEugSaBHhkVodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20v
+# cGtpL2NybC9wcm9kdWN0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0yMy5jcmwwWgYI
+# KwYBBQUHAQEETjBMMEoGCCsGAQUFBzAChj5odHRwOi8vd3d3Lm1pY3Jvc29mdC5j
+# b20vcGtpL2NlcnRzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNydDANBgkqhkiG
+# 9w0BAQsFAAOCAgEAnVV9/Cqt4SwfZwExJFvhnnJL/Klv6lwUtj5OR2R4sQaTlz0x
+# M7U518JxNj/aZGx80HU5bbsPMeTCj/ts0aGUGCLu6WZnOlNN3Zi6th542DYunKmC
+# VgADsAW+iehp4LoJ7nvfam++Kctu2D9IdQHZGN5tggz1bSNU5HhTdSRXud2f8449
+# xvNo32X2pFaq95W2KFUn0CS9QKC/GbYSEhFdPSfgQJY4rPf5KYnDvBewVIVCs/wM
+# nosZiefwC2qBwoEZQhlSdYo2wh3DYXMuLGt7bj8sCXgU6ZGyqVvfSaN0DLzskYDS
+# PeZKPmY7T7uG+jIa2Zb0j/aRAfbOxnT99kxybxCrdTDFNLB62FD+CljdQDzHVG2d
+# Y3RILLFORy3BFARxv2T5JL5zbcqOCb2zAVdJVGTZc9d/HltEAY5aGZFrDZ+kKNxn
+# GSgkujhLmm77IVRrakURR6nxt67I6IleT53S0Ex2tVdUCbFpAUR+fKFhbHP+Crvs
+# QWY9af3LwUFJfn6Tvsv4O+S3Fb+0zj6lMVGEvL8CwYKiexcdFYmNcP7ntdAoGokL
+# jzbaukz5m/8K6TT4JDVnK+ANuOaMmdbhIurwJ0I9JZTmdHRbatGePu1+oDEzfbzL
+# 6Xu/OHBE0ZDxyKs6ijoIYn/ZcGNTTY3ugm2lBRDBcQZqELQdVTNYs6FwZvKhggNN
+# MIICNQIBATCB+aGB0aSBzjCByzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hp
+# bmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jw
+# b3JhdGlvbjElMCMGA1UECxMcTWljcm9zb2Z0IEFtZXJpY2EgT3BlcmF0aW9uczEn
+# MCUGA1UECxMeblNoaWVsZCBUU1MgRVNOOjkyMDAtMDVFMC1EOTQ3MSUwIwYDVQQD
+# ExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNloiMKAQEwBwYFKw4DAhoDFQDq
+# 8xzVXwLguauAQj1rrJ4/TyEMm6CBgzCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYD
+# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
+# b3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1w
+# IFBDQSAyMDEwMA0GCSqGSIb3DQEBCwUAAgUA6JpNsjAiGA8yMDIzMDgzMDIzMjIy
+# NloYDzIwMjMwODMxMjMyMjI2WjB0MDoGCisGAQQBhFkKBAExLDAqMAoCBQDomk2y
+# AgEAMAcCAQACAi7oMAcCAQACAhLnMAoCBQDom58yAgEAMDYGCisGAQQBhFkKBAIx
+# KDAmMAwGCisGAQQBhFkKAwKgCjAIAgEAAgMHoSChCjAIAgEAAgMBhqAwDQYJKoZI
+# hvcNAQELBQADggEBADE16CHIs3WeXYKQG9djja+StAB7gsNJxV9p+CETL3847UL3
+# +DIeoj6p5g0FkS8PJK2xc+UbcNx6XJO+WUXEbU9GL4mrOCQjYOM+i3r8FEU+l3Gh
+# 6ZG/9ygsIYRXEfDKK4lsbrrUkFQs9nDISHT3f8JZEJJXSsGmwcHWlNC0LC8bv0Jp
+# e2Bw2+SNc6SlGD8Vv45r4WFPHhfSioCz4HSsF1He3/2Wku7OH85FKvugBlsca7+F
+# bpGsDSL4LO9bv60DxuD+8xBZuyTB8s64ifCGlOXCNpK5VaHND48PhoJbuD0COwlM
+# Rn5NlT6T4hhtkPOqNscMlzYHmTOKc5NhWK8PyrIxggQNMIIECQIBATCBkzB8MQsw
+# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
+# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNy
+# b3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAITMwAAAc9SNr5xS81IygABAAABzzAN
+# BglghkgBZQMEAgEFAKCCAUowGgYJKoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEEMC8G
+# CSqGSIb3DQEJBDEiBCAjGiC3/PscCMBvPZjpZqbYcL2WRZ+Ecf74oiIPQKkjSzCB
+# +gYLKoZIhvcNAQkQAi8xgeowgecwgeQwgb0EILPpsLqeNS4NuYXE2VJlMuvQeWVA
+# 80ZDFhpOPjSzhPa/MIGYMIGApH4wfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldh
+# c2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBD
+# b3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIw
+# MTACEzMAAAHPUja+cUvNSMoAAQAAAc8wIgQgWdbLA3Co0zf3nE5086HU0tdn0vK7
+# yXyU9aAFpszvWFIwDQYJKoZIhvcNAQELBQAEggIANrHN06oaP0N1lUSxxoJteJgI
+# fQjN82xV5VSE0cwNCBy05fg1VydPERF59+MIwIlJHhikSo3YOj5tt3AohC78U46P
+# 2IdrLHKlA3rjiLUGwQvGUKJUSsEH4uueA1mmh9jwUBJhY3NjTcMQaQqp/oxZTaya
+# l7NqbubBIZvsDD126SUr8jtVWtZZzw8pnWCFb4Rijii4fY1UiQzfQLFwqQuid6tE
+# I0AaY3IoTlp7U9K2wfAPWcP1G7n3qv+990GEiQlGJlCfIJSSJQodzL2QZF5HCn/K
+# SfgkRPn3y/Aax8683mWCT8zricYzO3MZ9j0T7tAcqOiWb7PFCsk5Va44lq4Gv0u+
+# +60FYCAA/Qn6eMuNkqIpBeIK0+NYUcMSwPdY/riKXdgkVLwChEJC5WWznD/Iqsil
+# Jj9XYailhXzYx7Pa2MLays62LPwCnUxRQBTD9/rL3XQMj69iA4lisb51dKAtrqAU
+# 53aRXFn+twYYFTAUQ/oNK14nZEQE5H53xAfhphMokJOu+CnQQKeCMeYlex6Q4zfw
+# TQxP/xXZ+QW2cSZTwh1d5iE0XMhKCZxhxIOF/rRA+75L5GUz60reRZPeH/7USYZL
+# VPc0+kxIdSbNFJAhAp0u59wSMQdBofor3+HfDfmxmoSjfCSH4TvOkNIulX1PPJPX
+# UB7H4n7XHWJPkUU0cUw=
+# SIG # End signature block
diff --git a/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Package/tools/uninstall.ps1 b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Package/tools/uninstall.ps1
new file mode 100644
index 0000000..1f6b6d4
--- /dev/null
+++ b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Package/tools/uninstall.ps1
@@ -0,0 +1,282 @@
+param($installPath, $toolsPath, $package, $project)
+
+if($project.Object.SupportsPackageDependencyResolution)
+{
+ if($project.Object.SupportsPackageDependencyResolution())
+ {
+ # Do not uninstall analyzers via uninstall.ps1, instead let the project system handle it.
+ return
+ }
+}
+
+$analyzersPaths = Join-Path (Join-Path (Split-Path -Path $toolsPath -Parent) "analyzers") * -Resolve
+
+foreach($analyzersPath in $analyzersPaths)
+{
+ # Uninstall the language agnostic analyzers.
+ if (Test-Path $analyzersPath)
+ {
+ foreach ($analyzerFilePath in Get-ChildItem -Path "$analyzersPath\*.dll" -Exclude *.resources.dll)
+ {
+ if($project.Object.AnalyzerReferences)
+ {
+ $project.Object.AnalyzerReferences.Remove($analyzerFilePath.FullName)
+ }
+ }
+ }
+}
+
+# $project.Type gives the language name like (C# or VB.NET)
+$languageFolder = ""
+if($project.Type -eq "C#")
+{
+ $languageFolder = "cs"
+}
+if($project.Type -eq "VB.NET")
+{
+ $languageFolder = "vb"
+}
+if($languageFolder -eq "")
+{
+ return
+}
+
+foreach($analyzersPath in $analyzersPaths)
+{
+ # Uninstall language specific analyzers.
+ $languageAnalyzersPath = join-path $analyzersPath $languageFolder
+ if (Test-Path $languageAnalyzersPath)
+ {
+ foreach ($analyzerFilePath in Get-ChildItem -Path "$languageAnalyzersPath\*.dll" -Exclude *.resources.dll)
+ {
+ if($project.Object.AnalyzerReferences)
+ {
+ try
+ {
+ $project.Object.AnalyzerReferences.Remove($analyzerFilePath.FullName)
+ }
+ catch
+ {
+
+ }
+ }
+ }
+ }
+}
+# SIG # Begin signature block
+# MIIoLQYJKoZIhvcNAQcCoIIoHjCCKBoCAQExDzANBglghkgBZQMEAgEFADB5Bgor
+# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
+# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDC68wb97fg0QGL
+# yXrxJhYfmibzcOh8caqC0uZprfczDaCCDXYwggX0MIID3KADAgECAhMzAAADTrU8
+# esGEb+srAAAAAANOMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD
+# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
+# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
+# bmcgUENBIDIwMTEwHhcNMjMwMzE2MTg0MzI5WhcNMjQwMzE0MTg0MzI5WjB0MQsw
+# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
+# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy
+# b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
+# AQDdCKiNI6IBFWuvJUmf6WdOJqZmIwYs5G7AJD5UbcL6tsC+EBPDbr36pFGo1bsU
+# p53nRyFYnncoMg8FK0d8jLlw0lgexDDr7gicf2zOBFWqfv/nSLwzJFNP5W03DF/1
+# 1oZ12rSFqGlm+O46cRjTDFBpMRCZZGddZlRBjivby0eI1VgTD1TvAdfBYQe82fhm
+# WQkYR/lWmAK+vW/1+bO7jHaxXTNCxLIBW07F8PBjUcwFxxyfbe2mHB4h1L4U0Ofa
+# +HX/aREQ7SqYZz59sXM2ySOfvYyIjnqSO80NGBaz5DvzIG88J0+BNhOu2jl6Dfcq
+# jYQs1H/PMSQIK6E7lXDXSpXzAgMBAAGjggFzMIIBbzAfBgNVHSUEGDAWBgorBgEE
+# AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUnMc7Zn/ukKBsBiWkwdNfsN5pdwAw
+# RQYDVR0RBD4wPKQ6MDgxHjAcBgNVBAsTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEW
+# MBQGA1UEBRMNMjMwMDEyKzUwMDUxNjAfBgNVHSMEGDAWgBRIbmTlUAXTgqoXNzci
+# tW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8vd3d3Lm1pY3Jvc29mdC5j
+# b20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3JsMGEG
+# CCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDovL3d3dy5taWNyb3NvZnQu
+# Y29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3J0
+# MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIBAD21v9pHoLdBSNlFAjmk
+# mx4XxOZAPsVxxXbDyQv1+kGDe9XpgBnT1lXnx7JDpFMKBwAyIwdInmvhK9pGBa31
+# TyeL3p7R2s0L8SABPPRJHAEk4NHpBXxHjm4TKjezAbSqqbgsy10Y7KApy+9UrKa2
+# kGmsuASsk95PVm5vem7OmTs42vm0BJUU+JPQLg8Y/sdj3TtSfLYYZAaJwTAIgi7d
+# hzn5hatLo7Dhz+4T+MrFd+6LUa2U3zr97QwzDthx+RP9/RZnur4inzSQsG5DCVIM
+# pA1l2NWEA3KAca0tI2l6hQNYsaKL1kefdfHCrPxEry8onJjyGGv9YKoLv6AOO7Oh
+# JEmbQlz/xksYG2N/JSOJ+QqYpGTEuYFYVWain7He6jgb41JbpOGKDdE/b+V2q/gX
+# UgFe2gdwTpCDsvh8SMRoq1/BNXcr7iTAU38Vgr83iVtPYmFhZOVM0ULp/kKTVoir
+# IpP2KCxT4OekOctt8grYnhJ16QMjmMv5o53hjNFXOxigkQWYzUO+6w50g0FAeFa8
+# 5ugCCB6lXEk21FFB1FdIHpjSQf+LP/W2OV/HfhC3uTPgKbRtXo83TZYEudooyZ/A
+# Vu08sibZ3MkGOJORLERNwKm2G7oqdOv4Qj8Z0JrGgMzj46NFKAxkLSpE5oHQYP1H
+# tPx1lPfD7iNSbJsP6LiUHXH1MIIHejCCBWKgAwIBAgIKYQ6Q0gAAAAAAAzANBgkq
+# hkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x
+# EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv
+# bjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5
+# IDIwMTEwHhcNMTEwNzA4MjA1OTA5WhcNMjYwNzA4MjEwOTA5WjB+MQswCQYDVQQG
+# EwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwG
+# A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSgwJgYDVQQDEx9NaWNyb3NvZnQg
+# Q29kZSBTaWduaW5nIFBDQSAyMDExMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
+# CgKCAgEAq/D6chAcLq3YbqqCEE00uvK2WCGfQhsqa+laUKq4BjgaBEm6f8MMHt03
+# a8YS2AvwOMKZBrDIOdUBFDFC04kNeWSHfpRgJGyvnkmc6Whe0t+bU7IKLMOv2akr
+# rnoJr9eWWcpgGgXpZnboMlImEi/nqwhQz7NEt13YxC4Ddato88tt8zpcoRb0Rrrg
+# OGSsbmQ1eKagYw8t00CT+OPeBw3VXHmlSSnnDb6gE3e+lD3v++MrWhAfTVYoonpy
+# 4BI6t0le2O3tQ5GD2Xuye4Yb2T6xjF3oiU+EGvKhL1nkkDstrjNYxbc+/jLTswM9
+# sbKvkjh+0p2ALPVOVpEhNSXDOW5kf1O6nA+tGSOEy/S6A4aN91/w0FK/jJSHvMAh
+# dCVfGCi2zCcoOCWYOUo2z3yxkq4cI6epZuxhH2rhKEmdX4jiJV3TIUs+UsS1Vz8k
+# A/DRelsv1SPjcF0PUUZ3s/gA4bysAoJf28AVs70b1FVL5zmhD+kjSbwYuER8ReTB
+# w3J64HLnJN+/RpnF78IcV9uDjexNSTCnq47f7Fufr/zdsGbiwZeBe+3W7UvnSSmn
+# Eyimp31ngOaKYnhfsi+E11ecXL93KCjx7W3DKI8sj0A3T8HhhUSJxAlMxdSlQy90
+# lfdu+HggWCwTXWCVmj5PM4TasIgX3p5O9JawvEagbJjS4NaIjAsCAwEAAaOCAe0w
+# ggHpMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBRIbmTlUAXTgqoXNzcitW2o
+# ynUClTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMCAYYwDwYD
+# VR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBRyLToCMZBDuRQFTuHqp8cx0SOJNDBa
+# BgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2Ny
+# bC9wcm9kdWN0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3JsMF4GCCsG
+# AQUFBwEBBFIwUDBOBggrBgEFBQcwAoZCaHR0cDovL3d3dy5taWNyb3NvZnQuY29t
+# L3BraS9jZXJ0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3J0MIGfBgNV
+# HSAEgZcwgZQwgZEGCSsGAQQBgjcuAzCBgzA/BggrBgEFBQcCARYzaHR0cDovL3d3
+# dy5taWNyb3NvZnQuY29tL3BraW9wcy9kb2NzL3ByaW1hcnljcHMuaHRtMEAGCCsG
+# AQUFBwICMDQeMiAdAEwAZQBnAGEAbABfAHAAbwBsAGkAYwB5AF8AcwB0AGEAdABl
+# AG0AZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4ICAQBn8oalmOBUeRou09h0ZyKb
+# C5YR4WOSmUKWfdJ5DJDBZV8uLD74w3LRbYP+vj/oCso7v0epo/Np22O/IjWll11l
+# hJB9i0ZQVdgMknzSGksc8zxCi1LQsP1r4z4HLimb5j0bpdS1HXeUOeLpZMlEPXh6
+# I/MTfaaQdION9MsmAkYqwooQu6SpBQyb7Wj6aC6VoCo/KmtYSWMfCWluWpiW5IP0
+# wI/zRive/DvQvTXvbiWu5a8n7dDd8w6vmSiXmE0OPQvyCInWH8MyGOLwxS3OW560
+# STkKxgrCxq2u5bLZ2xWIUUVYODJxJxp/sfQn+N4sOiBpmLJZiWhub6e3dMNABQam
+# ASooPoI/E01mC8CzTfXhj38cbxV9Rad25UAqZaPDXVJihsMdYzaXht/a8/jyFqGa
+# J+HNpZfQ7l1jQeNbB5yHPgZ3BtEGsXUfFL5hYbXw3MYbBL7fQccOKO7eZS/sl/ah
+# XJbYANahRr1Z85elCUtIEJmAH9AAKcWxm6U/RXceNcbSoqKfenoi+kiVH6v7RyOA
+# 9Z74v2u3S5fi63V4GuzqN5l5GEv/1rMjaHXmr/r8i+sLgOppO6/8MO0ETI7f33Vt
+# Y5E90Z1WTk+/gFcioXgRMiF670EKsT/7qMykXcGhiJtXcVZOSEXAQsmbdlsKgEhr
+# /Xmfwb1tbWrJUnMTDXpQzTGCGg0wghoJAgEBMIGVMH4xCzAJBgNVBAYTAlVTMRMw
+# EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN
+# aWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNp
+# Z25pbmcgUENBIDIwMTECEzMAAANOtTx6wYRv6ysAAAAAA04wDQYJYIZIAWUDBAIB
+# BQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEO
+# MAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIBdcqRcs5QL71hlQnl3M636V
+# 5iTZvb6co3MHeMuIr36qMEIGCisGAQQBgjcCAQwxNDAyoBSAEgBNAGkAYwByAG8A
+# cwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20wDQYJKoZIhvcNAQEB
+# BQAEggEARbhO/zqm6SWBf6DSJ3P1r82VjSyMGXaLtMfTOq/bqHOXPOqC25R1v5uO
+# zu4ri+UOS8dU6EfW6C9Xf/Z1Ue/oxrvxn5j8mPvsmcs5OyDO0hW0Wv6pYEy5Z5up
+# mfcqvfUfl3+ir29lgPuz0f1mLpz0XxqhjqElEi5RfZD1k1YVg65f0qHroP2txql5
+# TfC77DXJ8verzVm1wqXBHTAERQD94TJobahYTCmyaudMjLUVFakv2lTMv0YTnrQR
+# So006ZQg3i1jcVCJt/bRDGKh3xUo1IHgoh3NjMEkxT3iWt8rnX8Us6T6Zg8B2OxC
+# 0EnuIu/eYYUlYTLQxO9eks7w1kVcUqGCF5cwgheTBgorBgEEAYI3AwMBMYIXgzCC
+# F38GCSqGSIb3DQEHAqCCF3AwghdsAgEDMQ8wDQYJYIZIAWUDBAIBBQAwggFSBgsq
+# hkiG9w0BCRABBKCCAUEEggE9MIIBOQIBAQYKKwYBBAGEWQoDATAxMA0GCWCGSAFl
+# AwQCAQUABCBQ1HvJFFsT0ICl6oEZlSNN8DlUeQobBHt/oTUGN6iKBgIGZNTKS0Bc
+# GBMyMDIzMDgzMTAwMTI1OC4zODVaMASAAgH0oIHRpIHOMIHLMQswCQYDVQQGEwJV
+# UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE
+# ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSUwIwYDVQQLExxNaWNyb3NvZnQgQW1l
+# cmljYSBPcGVyYXRpb25zMScwJQYDVQQLEx5uU2hpZWxkIFRTUyBFU046N0YwMC0w
+# NUUwLUQ5NDcxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2Wg
+# ghHtMIIHIDCCBQigAwIBAgITMwAAAdWpAs/Fp8npWgABAAAB1TANBgkqhkiG9w0B
+# AQsFADB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE
+# BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYD
+# VQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDAeFw0yMzA1MjUxOTEy
+# MzBaFw0yNDAyMDExOTEyMzBaMIHLMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2Fz
+# aGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENv
+# cnBvcmF0aW9uMSUwIwYDVQQLExxNaWNyb3NvZnQgQW1lcmljYSBPcGVyYXRpb25z
+# MScwJQYDVQQLEx5uU2hpZWxkIFRTUyBFU046N0YwMC0wNUUwLUQ5NDcxJTAjBgNV
+# BAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2UwggIiMA0GCSqGSIb3DQEB
+# AQUAA4ICDwAwggIKAoICAQDFfak57Oph9vuxtloABiLc6enT+yKH619b+OhGdkyh
+# gNzkX80KUGI/jEqOVMV4Sqt/UPFFidx2t7v2SETj2tAzuVKtDfq2HBpu80vZ0vyQ
+# DydVt4MDL4tJSKqgYofCxDIBrWzJJjgBolKdOJx1ut2TyOc+UOm7e92tVPHpjdg+
+# Omf31TLUf/oouyAOJ/Inn2ih3ASP0QYm+AFQjhYDNDu8uzMdwHF5QdwsscNa9PVS
+# GedLdDLo9jL6DoPF4NYo06lvvEQuSJ9ImwZfBGLy/8hpE7RD4ewvJKmM1+t6eQuE
+# sTXjrGM2WjkW18SgUZ8n+VpL2uk6AhDkCa355I531p0Jkqpoon7dHuLUdZSQO40q
+# mVIQ6qQCanvImTqmNgE/rPJ0rgr0hMPI/uR1T/iaL0mEq4bqak+3sa8I+FAYOI/P
+# C7V+zEek+sdyWtaX+ndbGlv/RJb5mQaGn8NunbkfvHD1Qt5D0rmtMOekYMq7QjYq
+# E3FEP/wAY4TDuJxstjsa2HXi2yUDEg4MJL6/JvsQXToOZ+IxR6KT5t5fB5FpZYBp
+# VLMma3pm5z6VXvkXrYs33NXJqVWLwiswa7NUFV87Es2sou9Idw3yAZmHIYWgOQ+D
+# IY1nY3aG5DODiwN1rJyEb+mbWDagrdVxcncr6UKKO49eoNTXEW+scUf6GwXG0KEy
+# mQIDAQABo4IBSTCCAUUwHQYDVR0OBBYEFK/QXKNO35bBMOz3R5giX7Ala2OaMB8G
+# A1UdIwQYMBaAFJ+nFV0AXmJdg/Tl0mWnG1M1GelyMF8GA1UdHwRYMFYwVKBSoFCG
+# Tmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY3Jvc29mdCUy
+# MFRpbWUtU3RhbXAlMjBQQ0ElMjAyMDEwKDEpLmNybDBsBggrBgEFBQcBAQRgMF4w
+# XAYIKwYBBQUHMAKGUGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY2Vy
+# dHMvTWljcm9zb2Z0JTIwVGltZS1TdGFtcCUyMFBDQSUyMDIwMTAoMSkuY3J0MAwG
+# A1UdEwEB/wQCMAAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwDgYDVR0PAQH/BAQD
+# AgeAMA0GCSqGSIb3DQEBCwUAA4ICAQBmRddqvQuyjRpx0HGxvOqffFrbgFAg0j82
+# v0v7R+/8a70S2V4t7yKYKSsQGI6pvt1A8JGmuZyjmIXmw23AkI5bZkxvSgws8rrB
+# tJw9vakEckcWFQb7JG6b618x0s9Q3DL0dRq46QZRnm7U6234lecvjstAow30dP0T
+# nIacPWKpPc3QgB+WDnglN2fdT1ruQ6WIVBenmpjpG9ypRANKUx5NRcpdJAQW2FqE
+# HTS3Ntb+0tCqIkNHJ5aFsF6ehRovWZp0MYIz9bpJHix0VrjdLVMOpe7wv62t90E3
+# UrE2KmVwpQ5wsMD6YUscoCsSRQZrA5AbwTOCZJpeG2z3vDo/huvPK8TeTJ2Ltu/I
+# tXgxIlIOQp/tbHAiN8Xptw/JmIZg9edQ/FiDaIIwG5YHsfm2u7TwOFyd6OqLw18Z
+# 5j/IvDPzlkwWJxk6RHJF5dS4s3fnyLw3DHBe5Dav6KYB4n8x/cEmD/R44/8gS5Pf
+# uG1srjLdyyGtyh0KiRDSmjw+fa7i1VPoemidDWNZ7ksNadMad4ZoDvgkqOV4A6a+
+# N8HIc/P6g0irrezLWUgbKXSN8iH9RP+WJFx5fBHE4AFxrbAUQ2Zn5jDmHAI3wYcQ
+# DnnEYP51A75WFwPsvBrfrb1+6a1fuTEH1AYdOOMy8fX8xKo0E0Ys+7bxIvFPsUpS
+# zfFjBolmhzCCB3EwggVZoAMCAQICEzMAAAAVxedrngKbSZkAAAAAABUwDQYJKoZI
+# hvcNAQELBQAwgYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAw
+# DgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24x
+# MjAwBgNVBAMTKU1pY3Jvc29mdCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAy
+# MDEwMB4XDTIxMDkzMDE4MjIyNVoXDTMwMDkzMDE4MzIyNVowfDELMAkGA1UEBhMC
+# VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV
+# BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRp
+# bWUtU3RhbXAgUENBIDIwMTAwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
+# AQDk4aZM57RyIQt5osvXJHm9DtWC0/3unAcH0qlsTnXIyjVX9gF/bErg4r25Phdg
+# M/9cT8dm95VTcVrifkpa/rg2Z4VGIwy1jRPPdzLAEBjoYH1qUoNEt6aORmsHFPPF
+# dvWGUNzBRMhxXFExN6AKOG6N7dcP2CZTfDlhAnrEqv1yaa8dq6z2Nr41JmTamDu6
+# GnszrYBbfowQHJ1S/rboYiXcag/PXfT+jlPP1uyFVk3v3byNpOORj7I5LFGc6XBp
+# Dco2LXCOMcg1KL3jtIckw+DJj361VI/c+gVVmG1oO5pGve2krnopN6zL64NF50Zu
+# yjLVwIYwXE8s4mKyzbnijYjklqwBSru+cakXW2dg3viSkR4dPf0gz3N9QZpGdc3E
+# XzTdEonW/aUgfX782Z5F37ZyL9t9X4C626p+Nuw2TPYrbqgSUei/BQOj0XOmTTd0
+# lBw0gg/wEPK3Rxjtp+iZfD9M269ewvPV2HM9Q07BMzlMjgK8QmguEOqEUUbi0b1q
+# GFphAXPKZ6Je1yh2AuIzGHLXpyDwwvoSCtdjbwzJNmSLW6CmgyFdXzB0kZSU2LlQ
+# +QuJYfM2BjUYhEfb3BvR/bLUHMVr9lxSUV0S2yW6r1AFemzFER1y7435UsSFF5PA
+# PBXbGjfHCBUYP3irRbb1Hode2o+eFnJpxq57t7c+auIurQIDAQABo4IB3TCCAdkw
+# EgYJKwYBBAGCNxUBBAUCAwEAATAjBgkrBgEEAYI3FQIEFgQUKqdS/mTEmr6CkTxG
+# NSnPEP8vBO4wHQYDVR0OBBYEFJ+nFV0AXmJdg/Tl0mWnG1M1GelyMFwGA1UdIARV
+# MFMwUQYMKwYBBAGCN0yDfQEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly93d3cubWlj
+# cm9zb2Z0LmNvbS9wa2lvcHMvRG9jcy9SZXBvc2l0b3J5Lmh0bTATBgNVHSUEDDAK
+# BggrBgEFBQcDCDAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMC
+# AYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBTV9lbLj+iiXGJo0T2UkFvX
+# zpoYxDBWBgNVHR8ETzBNMEugSaBHhkVodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20v
+# cGtpL2NybC9wcm9kdWN0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0yMy5jcmwwWgYI
+# KwYBBQUHAQEETjBMMEoGCCsGAQUFBzAChj5odHRwOi8vd3d3Lm1pY3Jvc29mdC5j
+# b20vcGtpL2NlcnRzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNydDANBgkqhkiG
+# 9w0BAQsFAAOCAgEAnVV9/Cqt4SwfZwExJFvhnnJL/Klv6lwUtj5OR2R4sQaTlz0x
+# M7U518JxNj/aZGx80HU5bbsPMeTCj/ts0aGUGCLu6WZnOlNN3Zi6th542DYunKmC
+# VgADsAW+iehp4LoJ7nvfam++Kctu2D9IdQHZGN5tggz1bSNU5HhTdSRXud2f8449
+# xvNo32X2pFaq95W2KFUn0CS9QKC/GbYSEhFdPSfgQJY4rPf5KYnDvBewVIVCs/wM
+# nosZiefwC2qBwoEZQhlSdYo2wh3DYXMuLGt7bj8sCXgU6ZGyqVvfSaN0DLzskYDS
+# PeZKPmY7T7uG+jIa2Zb0j/aRAfbOxnT99kxybxCrdTDFNLB62FD+CljdQDzHVG2d
+# Y3RILLFORy3BFARxv2T5JL5zbcqOCb2zAVdJVGTZc9d/HltEAY5aGZFrDZ+kKNxn
+# GSgkujhLmm77IVRrakURR6nxt67I6IleT53S0Ex2tVdUCbFpAUR+fKFhbHP+Crvs
+# QWY9af3LwUFJfn6Tvsv4O+S3Fb+0zj6lMVGEvL8CwYKiexcdFYmNcP7ntdAoGokL
+# jzbaukz5m/8K6TT4JDVnK+ANuOaMmdbhIurwJ0I9JZTmdHRbatGePu1+oDEzfbzL
+# 6Xu/OHBE0ZDxyKs6ijoIYn/ZcGNTTY3ugm2lBRDBcQZqELQdVTNYs6FwZvKhggNQ
+# MIICOAIBATCB+aGB0aSBzjCByzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hp
+# bmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jw
+# b3JhdGlvbjElMCMGA1UECxMcTWljcm9zb2Z0IEFtZXJpY2EgT3BlcmF0aW9uczEn
+# MCUGA1UECxMeblNoaWVsZCBUU1MgRVNOOjdGMDAtMDVFMC1EOTQ3MSUwIwYDVQQD
+# ExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNloiMKAQEwBwYFKw4DAhoDFQBO
+# Ei+S/ZVFe6w1Id31m6Kge26lNKCBgzCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYD
+# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
+# b3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1w
+# IFBDQSAyMDEwMA0GCSqGSIb3DQEBCwUAAgUA6JpN3jAiGA8yMDIzMDgzMDIzMjMx
+# MFoYDzIwMjMwODMxMjMyMzEwWjB3MD0GCisGAQQBhFkKBAExLzAtMAoCBQDomk3e
+# AgEAMAoCAQACAiLLAgH/MAcCAQACAhLTMAoCBQDom59eAgEAMDYGCisGAQQBhFkK
+# BAIxKDAmMAwGCisGAQQBhFkKAwKgCjAIAgEAAgMHoSChCjAIAgEAAgMBhqAwDQYJ
+# KoZIhvcNAQELBQADggEBAC/zAZ9IEqD3nHBUWwxFTfnDSRErnCJ6XGxH5jOVtR0t
+# 9pi7yCpApLpA2D12g1lcv4ugnwGpsbwmFjrcF4WlHemRa77qv409xNhNKrnh3H+U
+# X2hvy9Utp9LiJiqS7lOW5VN1Uv+LbnA+FWt//4J+YLv44D/dliUGjYX623X7KiEX
+# dbdXPR/Sn+W2YVQ19O8liKaFDnDnIAz+WLCfL6EaoGu4Te/Mr65Khy3YWTwQfXxr
+# gR/JMDzLzWossnGszYCN8S8d9X6mfzWuYv4JHLEiThW++WbMLeT2hhKPomcbvqU4
+# wPb/ylDrTrWuAr/fVndECXVjCIzYJiFwOWn/ZfN9FpQxggQNMIIECQIBATCBkzB8
+# MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVk
+# bW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1N
+# aWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAITMwAAAdWpAs/Fp8npWgABAAAB
+# 1TANBglghkgBZQMEAgEFAKCCAUowGgYJKoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEE
+# MC8GCSqGSIb3DQEJBDEiBCAHS+EjBkJ/YPugQQv1D7eXVQOI4DWPIYpUxpssheDN
+# lTCB+gYLKoZIhvcNAQkQAi8xgeowgecwgeQwgb0EINm/I4YM166JMM7EKIcYvlcb
+# r2CHjKC0LUOmpZIbBsH/MIGYMIGApH4wfDELMAkGA1UEBhMCVVMxEzARBgNVBAgT
+# Cldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29m
+# dCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENB
+# IDIwMTACEzMAAAHVqQLPxafJ6VoAAQAAAdUwIgQgBVj4mNvMkXn0xEeEe3i6urr/
+# L5Eh2p4uPk3zOcR/jHIwDQYJKoZIhvcNAQELBQAEggIAiKbnM5VQAwi5gWDevpEJ
+# oHiZRrb0HApEUkca54Oye2+5tyRfWo3ruZvLZueHWsbEzYXclOscHVPjyR1t6s+p
+# W13utx4mDab1BaJCBq1q9IH1HDfCf/kSMb0H02UDNBumrt1s5/oaiiY75S3kigpt
+# XHCKV/AKbi+4vORYdBwJhWvy4kug+zZHWAp7+K4rVeAaMbWOitriFPQaSdZlOkNT
+# VKMbYUtX6VEnhyfr5O390TxPJCdkDznT6rAf5FlQEkim7wb2gb/Osi73KF0dtnRd
+# 0ePNT4GxulYTrAhHsZmyuinh/FIyqJDtW3C+2eVt/lx6GJfAtDA/gVCe9mAL4bYv
+# 7vjocHeLvWJ8bc0PYMCRZXMsU2zkJqVJ7pZWq+z5hGQAHemrQj9hUZBXCEFVZ8dd
+# jEZbIsg2nwZOFakhvdAvvGlTXPbRMOCHblToXAKA8ksRbLob8CDL6Cstoy5VL3al
+# fOAWLj3FYITlvGvAYCtJzHrHdqyphL805Co1syR6YDopR8tDrxgWzJKAby5fIolP
+# 7SfunXsCa0n3xx80aaxR0apljIXZWBSMGZdJmVzASQFxlexNsU1PmaLmmpn0fih/
+# 567e+kyzFG1wiw5btwttSW9hKgCX+yze1B4IK4yquTQSfPikrCpbBaFZ0OlWmOnL
+# r0eKAKY3WDyxYgNyeg6KeCc=
+# SIG # End signature block
diff --git a/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Test/Misaki.HighPerformance.Analyzer.Test.csproj b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Test/Misaki.HighPerformance.Analyzer.Test.csproj
new file mode 100644
index 0000000..d624aea
--- /dev/null
+++ b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Test/Misaki.HighPerformance.Analyzer.Test.csproj
@@ -0,0 +1,28 @@
+
+
+
+ netcoreapp3.1
+
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Test/MisakiHighPerformanceAnalyzerUnitTests.cs b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Test/MisakiHighPerformanceAnalyzerUnitTests.cs
new file mode 100644
index 0000000..a5caafa
--- /dev/null
+++ b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Test/MisakiHighPerformanceAnalyzerUnitTests.cs
@@ -0,0 +1,59 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System.Threading.Tasks;
+using VerifyCS = Misaki.HighPerformance.Analyzer.Test.CSharpCodeFixVerifier<
+ Misaki.HighPerformance.Analyzer.MisakiHighPerformanceAnalyzerAnalyzer,
+ Misaki.HighPerformance.Analyzer.MisakiHighPerformanceAnalyzerCodeFixProvider>;
+
+namespace Misaki.HighPerformance.Analyzer.Test
+{
+ [TestClass]
+ public class MisakiHighPerformanceAnalyzerUnitTest
+ {
+ //No diagnostics expected to show up
+ [TestMethod]
+ public async Task TestMethod1()
+ {
+ var test = @"";
+
+ await VerifyCS.VerifyAnalyzerAsync(test);
+ }
+
+ //Diagnostic and CodeFix both triggered and checked for
+ [TestMethod]
+ public async Task TestMethod2()
+ {
+ var test = @"
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using System.Threading.Tasks;
+ using System.Diagnostics;
+
+ namespace ConsoleApplication1
+ {
+ class {|#0:TypeName|}
+ {
+ }
+ }";
+
+ var fixtest = @"
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using System.Threading.Tasks;
+ using System.Diagnostics;
+
+ namespace ConsoleApplication1
+ {
+ class TYPENAME
+ {
+ }
+ }";
+
+ var expected = VerifyCS.Diagnostic("MisakiHighPerformanceAnalyzer").WithLocation(0).WithArguments("TypeName");
+ await VerifyCS.VerifyCodeFixAsync(test, expected, fixtest);
+ }
+ }
+}
diff --git a/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Test/Verifiers/CSharpAnalyzerVerifier`1+Test.cs b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Test/Verifiers/CSharpAnalyzerVerifier`1+Test.cs
new file mode 100644
index 0000000..6324ee9
--- /dev/null
+++ b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Test/Verifiers/CSharpAnalyzerVerifier`1+Test.cs
@@ -0,0 +1,26 @@
+using Microsoft.CodeAnalysis.CSharp.Testing;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.CodeAnalysis.Testing.Verifiers;
+
+namespace Misaki.HighPerformance.Analyzer.Test
+{
+ public static partial class CSharpAnalyzerVerifier
+ where TAnalyzer : DiagnosticAnalyzer, new()
+ {
+ public class Test : CSharpAnalyzerTest
+ {
+ public Test()
+ {
+ SolutionTransforms.Add((solution, projectId) =>
+ {
+ var compilationOptions = solution.GetProject(projectId).CompilationOptions;
+ compilationOptions = compilationOptions.WithSpecificDiagnosticOptions(
+ compilationOptions.SpecificDiagnosticOptions.SetItems(CSharpVerifierHelper.NullableWarnings));
+ solution = solution.WithProjectCompilationOptions(projectId, compilationOptions);
+
+ return solution;
+ });
+ }
+ }
+ }
+}
diff --git a/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Test/Verifiers/CSharpAnalyzerVerifier`1.cs b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Test/Verifiers/CSharpAnalyzerVerifier`1.cs
new file mode 100644
index 0000000..789f32d
--- /dev/null
+++ b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Test/Verifiers/CSharpAnalyzerVerifier`1.cs
@@ -0,0 +1,38 @@
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp.Testing;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.CodeAnalysis.Testing;
+using Microsoft.CodeAnalysis.Testing.Verifiers;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Misaki.HighPerformance.Analyzer.Test
+{
+ public static partial class CSharpAnalyzerVerifier
+ where TAnalyzer : DiagnosticAnalyzer, new()
+ {
+ ///
+ public static DiagnosticResult Diagnostic()
+ => CSharpAnalyzerVerifier.Diagnostic();
+
+ ///
+ public static DiagnosticResult Diagnostic(string diagnosticId)
+ => CSharpAnalyzerVerifier.Diagnostic(diagnosticId);
+
+ ///
+ public static DiagnosticResult Diagnostic(DiagnosticDescriptor descriptor)
+ => CSharpAnalyzerVerifier.Diagnostic(descriptor);
+
+ ///
+ public static async Task VerifyAnalyzerAsync(string source, params DiagnosticResult[] expected)
+ {
+ var test = new Test
+ {
+ TestCode = source,
+ };
+
+ test.ExpectedDiagnostics.AddRange(expected);
+ await test.RunAsync(CancellationToken.None);
+ }
+ }
+}
diff --git a/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Test/Verifiers/CSharpCodeFixVerifier`2+Test.cs b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Test/Verifiers/CSharpCodeFixVerifier`2+Test.cs
new file mode 100644
index 0000000..bafdf89
--- /dev/null
+++ b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Test/Verifiers/CSharpCodeFixVerifier`2+Test.cs
@@ -0,0 +1,28 @@
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.CSharp.Testing;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.CodeAnalysis.Testing.Verifiers;
+
+namespace Misaki.HighPerformance.Analyzer.Test
+{
+ public static partial class CSharpCodeFixVerifier
+ where TAnalyzer : DiagnosticAnalyzer, new()
+ where TCodeFix : CodeFixProvider, new()
+ {
+ public class Test : CSharpCodeFixTest
+ {
+ public Test()
+ {
+ SolutionTransforms.Add((solution, projectId) =>
+ {
+ var compilationOptions = solution.GetProject(projectId).CompilationOptions;
+ compilationOptions = compilationOptions.WithSpecificDiagnosticOptions(
+ compilationOptions.SpecificDiagnosticOptions.SetItems(CSharpVerifierHelper.NullableWarnings));
+ solution = solution.WithProjectCompilationOptions(projectId, compilationOptions);
+
+ return solution;
+ });
+ }
+ }
+ }
+}
diff --git a/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Test/Verifiers/CSharpCodeFixVerifier`2.cs b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Test/Verifiers/CSharpCodeFixVerifier`2.cs
new file mode 100644
index 0000000..11eac30
--- /dev/null
+++ b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Test/Verifiers/CSharpCodeFixVerifier`2.cs
@@ -0,0 +1,61 @@
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.CSharp.Testing;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.CodeAnalysis.Testing;
+using Microsoft.CodeAnalysis.Testing.Verifiers;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Misaki.HighPerformance.Analyzer.Test
+{
+ public static partial class CSharpCodeFixVerifier
+ where TAnalyzer : DiagnosticAnalyzer, new()
+ where TCodeFix : CodeFixProvider, new()
+ {
+ ///
+ public static DiagnosticResult Diagnostic()
+ => CSharpCodeFixVerifier.Diagnostic();
+
+ ///
+ public static DiagnosticResult Diagnostic(string diagnosticId)
+ => CSharpCodeFixVerifier.Diagnostic(diagnosticId);
+
+ ///
+ public static DiagnosticResult Diagnostic(DiagnosticDescriptor descriptor)
+ => CSharpCodeFixVerifier.Diagnostic(descriptor);
+
+ ///
+ public static async Task VerifyAnalyzerAsync(string source, params DiagnosticResult[] expected)
+ {
+ var test = new Test
+ {
+ TestCode = source,
+ };
+
+ test.ExpectedDiagnostics.AddRange(expected);
+ await test.RunAsync(CancellationToken.None);
+ }
+
+ ///
+ public static async Task VerifyCodeFixAsync(string source, string fixedSource)
+ => await VerifyCodeFixAsync(source, DiagnosticResult.EmptyDiagnosticResults, fixedSource);
+
+ ///
+ public static async Task VerifyCodeFixAsync(string source, DiagnosticResult expected, string fixedSource)
+ => await VerifyCodeFixAsync(source, new[] { expected }, fixedSource);
+
+ ///
+ public static async Task VerifyCodeFixAsync(string source, DiagnosticResult[] expected, string fixedSource)
+ {
+ var test = new Test
+ {
+ TestCode = source,
+ FixedCode = fixedSource,
+ };
+
+ test.ExpectedDiagnostics.AddRange(expected);
+ await test.RunAsync(CancellationToken.None);
+ }
+ }
+}
diff --git a/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Test/Verifiers/CSharpCodeRefactoringVerifier`1+Test.cs b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Test/Verifiers/CSharpCodeRefactoringVerifier`1+Test.cs
new file mode 100644
index 0000000..cbddead
--- /dev/null
+++ b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Test/Verifiers/CSharpCodeRefactoringVerifier`1+Test.cs
@@ -0,0 +1,26 @@
+using Microsoft.CodeAnalysis.CodeRefactorings;
+using Microsoft.CodeAnalysis.CSharp.Testing;
+using Microsoft.CodeAnalysis.Testing.Verifiers;
+
+namespace Misaki.HighPerformance.Analyzer.Test
+{
+ public static partial class CSharpCodeRefactoringVerifier
+ where TCodeRefactoring : CodeRefactoringProvider, new()
+ {
+ public class Test : CSharpCodeRefactoringTest
+ {
+ public Test()
+ {
+ SolutionTransforms.Add((solution, projectId) =>
+ {
+ var compilationOptions = solution.GetProject(projectId).CompilationOptions;
+ compilationOptions = compilationOptions.WithSpecificDiagnosticOptions(
+ compilationOptions.SpecificDiagnosticOptions.SetItems(CSharpVerifierHelper.NullableWarnings));
+ solution = solution.WithProjectCompilationOptions(projectId, compilationOptions);
+
+ return solution;
+ });
+ }
+ }
+ }
+}
diff --git a/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Test/Verifiers/CSharpCodeRefactoringVerifier`1.cs b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Test/Verifiers/CSharpCodeRefactoringVerifier`1.cs
new file mode 100644
index 0000000..7bc2e98
--- /dev/null
+++ b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Test/Verifiers/CSharpCodeRefactoringVerifier`1.cs
@@ -0,0 +1,36 @@
+using Microsoft.CodeAnalysis.CodeRefactorings;
+using Microsoft.CodeAnalysis.Testing;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Misaki.HighPerformance.Analyzer.Test
+{
+ public static partial class CSharpCodeRefactoringVerifier
+ where TCodeRefactoring : CodeRefactoringProvider, new()
+ {
+ ///
+ public static async Task VerifyRefactoringAsync(string source, string fixedSource)
+ {
+ await VerifyRefactoringAsync(source, DiagnosticResult.EmptyDiagnosticResults, fixedSource);
+ }
+
+ ///
+ public static async Task VerifyRefactoringAsync(string source, DiagnosticResult expected, string fixedSource)
+ {
+ await VerifyRefactoringAsync(source, new[] { expected }, fixedSource);
+ }
+
+ ///
+ public static async Task VerifyRefactoringAsync(string source, DiagnosticResult[] expected, string fixedSource)
+ {
+ var test = new Test
+ {
+ TestCode = source,
+ FixedCode = fixedSource,
+ };
+
+ test.ExpectedDiagnostics.AddRange(expected);
+ await test.RunAsync(CancellationToken.None);
+ }
+ }
+}
diff --git a/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Test/Verifiers/CSharpVerifierHelper.cs b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Test/Verifiers/CSharpVerifierHelper.cs
new file mode 100644
index 0000000..9adf359
--- /dev/null
+++ b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Test/Verifiers/CSharpVerifierHelper.cs
@@ -0,0 +1,33 @@
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using System;
+using System.Collections.Immutable;
+
+namespace Misaki.HighPerformance.Analyzer.Test
+{
+ internal static class CSharpVerifierHelper
+ {
+ ///
+ /// By default, the compiler reports diagnostics for nullable reference types at
+ /// , and the analyzer test framework defaults to only validating
+ /// diagnostics at . This map contains all compiler diagnostic IDs
+ /// related to nullability mapped to , which is then used to enable all
+ /// of these warnings for default validation during analyzer and code fix tests.
+ ///
+ internal static ImmutableDictionary NullableWarnings { get; } = GetNullableWarningsFromCompiler();
+
+ private static ImmutableDictionary GetNullableWarningsFromCompiler()
+ {
+ string[] args = { "/warnaserror:nullable" };
+ var commandLineArguments = CSharpCommandLineParser.Default.Parse(args, baseDirectory: Environment.CurrentDirectory, sdkDirectory: Environment.CurrentDirectory);
+ var nullableWarnings = commandLineArguments.CompilationOptions.SpecificDiagnosticOptions;
+
+ // Workaround for https://github.com/dotnet/roslyn/issues/41610
+ nullableWarnings = nullableWarnings
+ .SetItem("CS8632", ReportDiagnostic.Error)
+ .SetItem("CS8669", ReportDiagnostic.Error);
+
+ return nullableWarnings;
+ }
+ }
+}
diff --git a/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Test/Verifiers/VisualBasicAnalyzerVerifier`1+Test.cs b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Test/Verifiers/VisualBasicAnalyzerVerifier`1+Test.cs
new file mode 100644
index 0000000..2898cc7
--- /dev/null
+++ b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Test/Verifiers/VisualBasicAnalyzerVerifier`1+Test.cs
@@ -0,0 +1,17 @@
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.CodeAnalysis.Testing.Verifiers;
+using Microsoft.CodeAnalysis.VisualBasic.Testing;
+
+namespace Misaki.HighPerformance.Analyzer.Test
+{
+ public static partial class VisualBasicAnalyzerVerifier
+ where TAnalyzer : DiagnosticAnalyzer, new()
+ {
+ public class Test : VisualBasicAnalyzerTest
+ {
+ public Test()
+ {
+ }
+ }
+ }
+}
diff --git a/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Test/Verifiers/VisualBasicAnalyzerVerifier`1.cs b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Test/Verifiers/VisualBasicAnalyzerVerifier`1.cs
new file mode 100644
index 0000000..ca6439c
--- /dev/null
+++ b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Test/Verifiers/VisualBasicAnalyzerVerifier`1.cs
@@ -0,0 +1,38 @@
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.CodeAnalysis.Testing;
+using Microsoft.CodeAnalysis.Testing.Verifiers;
+using Microsoft.CodeAnalysis.VisualBasic.Testing;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Misaki.HighPerformance.Analyzer.Test
+{
+ public static partial class VisualBasicAnalyzerVerifier
+ where TAnalyzer : DiagnosticAnalyzer, new()
+ {
+ ///
+ public static DiagnosticResult Diagnostic()
+ => VisualBasicAnalyzerVerifier.Diagnostic();
+
+ ///
+ public static DiagnosticResult Diagnostic(string diagnosticId)
+ => VisualBasicAnalyzerVerifier.Diagnostic(diagnosticId);
+
+ ///
+ public static DiagnosticResult Diagnostic(DiagnosticDescriptor descriptor)
+ => VisualBasicAnalyzerVerifier.Diagnostic(descriptor);
+
+ ///
+ public static async Task VerifyAnalyzerAsync(string source, params DiagnosticResult[] expected)
+ {
+ var test = new Test
+ {
+ TestCode = source,
+ };
+
+ test.ExpectedDiagnostics.AddRange(expected);
+ await test.RunAsync(CancellationToken.None);
+ }
+ }
+}
diff --git a/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Test/Verifiers/VisualBasicCodeFixVerifier`2+Test.cs b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Test/Verifiers/VisualBasicCodeFixVerifier`2+Test.cs
new file mode 100644
index 0000000..7fc4682
--- /dev/null
+++ b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Test/Verifiers/VisualBasicCodeFixVerifier`2+Test.cs
@@ -0,0 +1,16 @@
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.CodeAnalysis.Testing.Verifiers;
+using Microsoft.CodeAnalysis.VisualBasic.Testing;
+
+namespace Misaki.HighPerformance.Analyzer.Test
+{
+ public static partial class VisualBasicCodeFixVerifier
+ where TAnalyzer : DiagnosticAnalyzer, new()
+ where TCodeFix : CodeFixProvider, new()
+ {
+ public class Test : VisualBasicCodeFixTest
+ {
+ }
+ }
+}
diff --git a/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Test/Verifiers/VisualBasicCodeFixVerifier`2.cs b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Test/Verifiers/VisualBasicCodeFixVerifier`2.cs
new file mode 100644
index 0000000..05735c3
--- /dev/null
+++ b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Test/Verifiers/VisualBasicCodeFixVerifier`2.cs
@@ -0,0 +1,61 @@
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.CodeAnalysis.Testing;
+using Microsoft.CodeAnalysis.Testing.Verifiers;
+using Microsoft.CodeAnalysis.VisualBasic.Testing;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Misaki.HighPerformance.Analyzer.Test
+{
+ public static partial class VisualBasicCodeFixVerifier
+ where TAnalyzer : DiagnosticAnalyzer, new()
+ where TCodeFix : CodeFixProvider, new()
+ {
+ ///
+ public static DiagnosticResult Diagnostic()
+ => VisualBasicCodeFixVerifier.Diagnostic();
+
+ ///
+ public static DiagnosticResult Diagnostic(string diagnosticId)
+ => VisualBasicCodeFixVerifier.Diagnostic(diagnosticId);
+
+ ///
+ public static DiagnosticResult Diagnostic(DiagnosticDescriptor descriptor)
+ => VisualBasicCodeFixVerifier.Diagnostic(descriptor);
+
+ ///
+ public static async Task VerifyAnalyzerAsync(string source, params DiagnosticResult[] expected)
+ {
+ var test = new Test
+ {
+ TestCode = source,
+ };
+
+ test.ExpectedDiagnostics.AddRange(expected);
+ await test.RunAsync(CancellationToken.None);
+ }
+
+ ///
+ public static async Task VerifyCodeFixAsync(string source, string fixedSource)
+ => await VerifyCodeFixAsync(source, DiagnosticResult.EmptyDiagnosticResults, fixedSource);
+
+ ///
+ public static async Task VerifyCodeFixAsync(string source, DiagnosticResult expected, string fixedSource)
+ => await VerifyCodeFixAsync(source, new[] { expected }, fixedSource);
+
+ ///
+ public static async Task VerifyCodeFixAsync(string source, DiagnosticResult[] expected, string fixedSource)
+ {
+ var test = new Test
+ {
+ TestCode = source,
+ FixedCode = fixedSource,
+ };
+
+ test.ExpectedDiagnostics.AddRange(expected);
+ await test.RunAsync(CancellationToken.None);
+ }
+ }
+}
diff --git a/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Test/Verifiers/VisualBasicCodeRefactoringVerifier`1+Test.cs b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Test/Verifiers/VisualBasicCodeRefactoringVerifier`1+Test.cs
new file mode 100644
index 0000000..29ebd34
--- /dev/null
+++ b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Test/Verifiers/VisualBasicCodeRefactoringVerifier`1+Test.cs
@@ -0,0 +1,14 @@
+using Microsoft.CodeAnalysis.CodeRefactorings;
+using Microsoft.CodeAnalysis.Testing.Verifiers;
+using Microsoft.CodeAnalysis.VisualBasic.Testing;
+
+namespace Misaki.HighPerformance.Analyzer.Test
+{
+ public static partial class VisualBasicCodeRefactoringVerifier
+ where TCodeRefactoring : CodeRefactoringProvider, new()
+ {
+ public class Test : VisualBasicCodeRefactoringTest
+ {
+ }
+ }
+}
diff --git a/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Test/Verifiers/VisualBasicCodeRefactoringVerifier`1.cs b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Test/Verifiers/VisualBasicCodeRefactoringVerifier`1.cs
new file mode 100644
index 0000000..5743d0f
--- /dev/null
+++ b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Test/Verifiers/VisualBasicCodeRefactoringVerifier`1.cs
@@ -0,0 +1,36 @@
+using Microsoft.CodeAnalysis.CodeRefactorings;
+using Microsoft.CodeAnalysis.Testing;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Misaki.HighPerformance.Analyzer.Test
+{
+ public static partial class VisualBasicCodeRefactoringVerifier
+ where TCodeRefactoring : CodeRefactoringProvider, new()
+ {
+ ///
+ public static async Task VerifyRefactoringAsync(string source, string fixedSource)
+ {
+ await VerifyRefactoringAsync(source, DiagnosticResult.EmptyDiagnosticResults, fixedSource);
+ }
+
+ ///
+ public static async Task VerifyRefactoringAsync(string source, DiagnosticResult expected, string fixedSource)
+ {
+ await VerifyRefactoringAsync(source, new[] { expected }, fixedSource);
+ }
+
+ ///
+ public static async Task VerifyRefactoringAsync(string source, DiagnosticResult[] expected, string fixedSource)
+ {
+ var test = new Test
+ {
+ TestCode = source,
+ FixedCode = fixedSource,
+ };
+
+ test.ExpectedDiagnostics.AddRange(expected);
+ await test.RunAsync(CancellationToken.None);
+ }
+ }
+}
diff --git a/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Vsix/Misaki.HighPerformance.Analyzer.Vsix.csproj b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Vsix/Misaki.HighPerformance.Analyzer.Vsix.csproj
new file mode 100644
index 0000000..cbd1570
--- /dev/null
+++ b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Vsix/Misaki.HighPerformance.Analyzer.Vsix.csproj
@@ -0,0 +1,48 @@
+
+
+
+
+
+ net472
+ Misaki.HighPerformance.Analyzer.Vsix
+ Misaki.HighPerformance.Analyzer.Vsix
+
+
+
+ false
+ false
+ false
+ false
+ false
+ false
+ Roslyn
+
+
+
+
+
+
+
+ Program
+ $(DevEnvDir)devenv.exe
+ /rootsuffix $(VSSDKTargetPlatformRegRootSuffix)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Vsix/source.extension.vsixmanifest b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Vsix/source.extension.vsixmanifest
new file mode 100644
index 0000000..53fa37e
--- /dev/null
+++ b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.Vsix/source.extension.vsixmanifest
@@ -0,0 +1,24 @@
+
+
+
+
+ Misaki.HighPerformance.Analyzer
+ This is a sample diagnostic extension for the .NET Compiler Platform ("Roslyn").
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.csproj b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.csproj
new file mode 100644
index 0000000..7176c81
--- /dev/null
+++ b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer.csproj
@@ -0,0 +1,21 @@
+
+
+
+ netstandard2.0
+ false
+
+
+ *$(MSBuildProjectFile)*
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer/Resources.Designer.cs b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer/Resources.Designer.cs
new file mode 100644
index 0000000..1a5ffea
--- /dev/null
+++ b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer/Resources.Designer.cs
@@ -0,0 +1,105 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.0
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+using System;
+using System.Reflection;
+
+namespace Misaki.HighPerformance.Analyzer
+{
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources
+ {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources()
+ {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager
+ {
+ get
+ {
+ if (object.ReferenceEquals(resourceMan, null))
+ {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Misaki.HighPerformance.Analyzer.Resources", typeof(Resources).GetTypeInfo().Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture
+ {
+ get
+ {
+ return resourceCulture;
+ }
+ set
+ {
+ resourceCulture = value;
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Type names should be all uppercase..
+ ///
+ internal static string AnalyzerDescription
+ {
+ get
+ {
+ return ResourceManager.GetString("AnalyzerDescription", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Type name '{0}' contains lowercase letters.
+ ///
+ internal static string AnalyzerMessageFormat
+ {
+ get
+ {
+ return ResourceManager.GetString("AnalyzerMessageFormat", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Type name contains lowercase letters.
+ ///
+ internal static string AnalyzerTitle
+ {
+ get
+ {
+ return ResourceManager.GetString("AnalyzerTitle", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer/Resources.resx b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer/Resources.resx
new file mode 100644
index 0000000..410edcc
--- /dev/null
+++ b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer/Resources.resx
@@ -0,0 +1,132 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ Type names should be all uppercase.
+ An optional longer localizable description of the diagnostic.
+
+
+ Type name '{0}' contains lowercase letters
+ The format-able message the diagnostic displays.
+
+
+ Type name contains lowercase letters
+ The title of the diagnostic.
+
+
\ No newline at end of file
diff --git a/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer/StructCopyCodeAnalyzer.cs b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer/StructCopyCodeAnalyzer.cs
new file mode 100644
index 0000000..1d40a29
--- /dev/null
+++ b/Misaki.HighPerformance.Analyzer/Misaki.HighPerformance.Analyzer/StructCopyCodeAnalyzer.cs
@@ -0,0 +1,123 @@
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Diagnostics;
+using System.Collections.Immutable;
+using System.Linq;
+
+namespace Misaki.HighPerformance.Analyzer
+{
+ [DiagnosticAnalyzer(LanguageNames.CSharp)]
+ public class StructCopyCodeAnalyzer : DiagnosticAnalyzer
+ {
+ public const string DIAGNOSTIC_ID = "MHP001";
+ private const string _TITLE = "Struct marked as NonCopyable was copied";
+ private const string _MESSAGE_FORMAT = "The struct '{0}' is designed for unique ownership and cannot be copied. Use .Detach(), .Get(), .Share() or pass by reference.";
+ private const string _CATEGORY = "Safety";
+
+ private static readonly DiagnosticDescriptor s_rule = new DiagnosticDescriptor(
+ DIAGNOSTIC_ID, _TITLE, _MESSAGE_FORMAT, _CATEGORY, DiagnosticSeverity.Error, isEnabledByDefault: true);
+
+ public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(s_rule);
+
+ public override void Initialize(AnalysisContext context)
+ {
+ context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
+ context.EnableConcurrentExecution();
+
+ // We want to catch:
+ // 1. var a = b; (Variable Declaration)
+ // 2. a = b; (Assignment Expression)
+ context.RegisterSyntaxNodeAction(AnalyzeAssignment, SyntaxKind.SimpleAssignmentExpression);
+ context.RegisterSyntaxNodeAction(AnalyzeDeclaration, SyntaxKind.VariableDeclarator);
+ }
+
+ private void AnalyzeAssignment(SyntaxNodeAnalysisContext context)
+ {
+ var assignment = (AssignmentExpressionSyntax)context.Node;
+ var rightHandSide = assignment.Right;
+
+ AnalyzePossibleCopy(context, assignment.Left, rightHandSide);
+ }
+
+ private void AnalyzeDeclaration(SyntaxNodeAnalysisContext context)
+ {
+ var declarator = (VariableDeclaratorSyntax)context.Node;
+
+ // Handle: var a = b;
+ if (declarator.Initializer == null)
+ {
+ return;
+ }
+
+ var variableType = context.SemanticModel.GetTypeInfo(declarator.Initializer.Value).Type;
+ if (variableType == null)
+ {
+ return;
+ }
+
+ // Check if this is a NonCopyable type
+ if (!IsNonCopyable(variableType))
+ {
+ return;
+ }
+
+ AnalyzePossibleCopy(context, declarator, declarator.Initializer.Value);
+ }
+
+ private void AnalyzePossibleCopy(SyntaxNodeAnalysisContext context, SyntaxNode targetNode, ExpressionSyntax rightHandSide)
+ {
+ // 1. Get type of the RHS
+ var typeInfo = context.SemanticModel.GetTypeInfo(rightHandSide);
+ var type = typeInfo.Type;
+
+ if (type == null || !IsNonCopyable(type))
+ {
+ return;
+ }
+
+ // 2. Determine if the RHS is a "Storage Location" (Variable, Field, Parameter)
+ // If it is, this is a copy operation.
+ // If the RHS is a Method Call (Factory) or 'new' keyword, we allow it (Creation/Transfer).
+
+ var isCopy = false;
+
+ switch (rightHandSide)
+ {
+ case AssignmentExpressionSyntax _: // e.g. = a = b;
+ case IdentifierNameSyntax _: // e.g. = myVar;
+ case MemberAccessExpressionSyntax _: // e.g. = obj.myField;
+ case ElementAccessExpressionSyntax _: // e.g. = arr[0];
+ isCopy = true;
+ break;
+ // We explicitly allow InvocationExpression (methods) and ObjectCreationExpression (new)
+ // because those typically represent creating a new owner, not copying an existing one.
+ }
+
+ if (isCopy)
+ {
+ // 3. Double check that we are not just referencing a constant or static readonly
+ var symbol = context.SemanticModel.GetSymbolInfo(rightHandSide).Symbol;
+
+ // If it's a local, parameter, field, or property, it's a copy of an existing value.
+ if (symbol != null && (
+ symbol.Kind == SymbolKind.Local ||
+ symbol.Kind == SymbolKind.Parameter ||
+ symbol.Kind == SymbolKind.Field ||
+ symbol.Kind == SymbolKind.Property))
+ {
+ var diagnostic = Diagnostic.Create(s_rule, rightHandSide.GetLocation(), type.Name);
+ context.ReportDiagnostic(diagnostic);
+ }
+ }
+ }
+
+ private bool IsNonCopyable(ITypeSymbol type)
+ {
+ // Check for [NonCopyable] attribute on the struct
+ return type.GetAttributes().Any(ad =>
+ ad.AttributeClass != null &&
+ ad.AttributeClass.Name == "NonCopyableAttribute");
+ }
+ }
+}
diff --git a/Misaki.HighPerformance.LowLevel/Attributes.cs b/Misaki.HighPerformance.LowLevel/Attributes.cs
new file mode 100644
index 0000000..d23e946
--- /dev/null
+++ b/Misaki.HighPerformance.LowLevel/Attributes.cs
@@ -0,0 +1,6 @@
+namespace Misaki.HighPerformance.LowLevel;
+
+[AttributeUsage(AttributeTargets.Struct)]
+public class NonCopyableAttribute : Attribute
+{
+}
\ No newline at end of file
diff --git a/Misaki.HighPerformance.LowLevel/Ptr.cs b/Misaki.HighPerformance.LowLevel/Ptr.cs
new file mode 100644
index 0000000..bbe2707
--- /dev/null
+++ b/Misaki.HighPerformance.LowLevel/Ptr.cs
@@ -0,0 +1,176 @@
+using System.Runtime.CompilerServices;
+
+namespace Misaki.HighPerformance.LowLevel;
+
+///
+/// Represents a strongly-typed, read-only pointer to an unmanaged value of type .
+///
+///
+/// When a pointer is wrapped in this struct, it indicates that the code does not intend to manage the lifetime of the data being pointed to.
+///
+/// The unmanaged type to which the pointer refers.
+public readonly unsafe struct SharedPtr : IEquatable>
+ where T : unmanaged
+{
+ private readonly T* _value;
+
+ public SharedPtr(T* value)
+ {
+ _value = value;
+ }
+
+ public T* Get()
+ {
+ return _value;
+ }
+
+ public bool Equals(SharedPtr other)
+ {
+ return _value == other._value;
+ }
+
+ public override bool Equals(object? obj)
+ {
+ return obj is SharedPtr ptr && Equals(ptr);
+ }
+
+ public override int GetHashCode()
+ {
+ return ((nint)_value).GetHashCode();
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator T*(SharedPtr ptr)
+ {
+ return ptr._value;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator SharedPtr(T* value)
+ {
+ return new SharedPtr(value);
+ }
+
+ public static bool operator ==(SharedPtr left, SharedPtr right)
+ {
+ return left.Equals(right);
+ }
+
+ public static bool operator !=(SharedPtr left, SharedPtr right)
+ {
+ return !(left == right);
+ }
+}
+
+///
+/// Provides exclusive ownership and management of an unmanaged pointer to a value of type .
+/// Ensures that the pointer is not shared and can be safely transferred or detached.
+///
+///
+/// UniquePtr is designed to encapsulate a raw pointer, enforcing unique ownership semantics similar to C++'s std::unique_ptr.
+///
+/// The unmanaged type of the value to which the pointer refers.
+[NonCopyable]
+public unsafe struct UniquePtr : IEquatable>
+ where T : unmanaged
+{
+ private T* _value;
+
+ public UniquePtr(T* value)
+ {
+ _value = value;
+ }
+
+ public readonly T* Get()
+ {
+ return _value;
+ }
+
+ public readonly SharedPtr Share()
+ {
+ return new SharedPtr(_value);
+ }
+
+ public T* Detach()
+ {
+ var temp = _value;
+ _value = null;
+ return temp;
+ }
+
+ public readonly bool Equals(UniquePtr other)
+ {
+ return _value == other._value;
+ }
+
+ public override readonly bool Equals(object? obj)
+ {
+ return obj is SharedPtr ptr && Equals(ptr);
+ }
+
+ public override readonly int GetHashCode()
+ {
+ return ((nint)_value).GetHashCode();
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator T*(UniquePtr ptr)
+ {
+ return ptr._value;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator UniquePtr(T* value)
+ {
+ return new UniquePtr(value);
+ }
+
+ public static bool operator ==(UniquePtr left, UniquePtr right)
+ {
+ return left.Equals(right);
+ }
+
+ public static bool operator !=(UniquePtr left, UniquePtr right)
+ {
+ return !(left == right);
+ }
+}
+
+public ref struct Ref
+{
+ private ref T _value;
+
+ public Ref(ref T value)
+ {
+ _value = ref value;
+ }
+
+ public ref T Get()
+ {
+ return ref _value;
+ }
+
+ [Obsolete("Equals() on Ref will always throw an exception. Use the equality operator instead.")]
+#pragma warning disable CS0809 // Obsolete member overrides non-obsolete member
+ public override bool Equals(object? obj)
+ {
+ throw new NotSupportedException();
+ }
+
+ [Obsolete("GetHashCode() on Ref will always throw an exception.")]
+ public override int GetHashCode()
+#pragma warning restore CS0809 // Obsolete member overrides non-obsolete member
+ {
+ throw new NotSupportedException();
+ }
+
+ public static bool operator ==(Ref left, Ref right)
+ {
+ return Unsafe.AreSame(ref left._value, ref right._value);
+ }
+
+ public static bool operator !=(Ref left, Ref right)
+ {
+ return !(left == right);
+ }
+}
diff --git a/Misaki.HighPerformance.LowLevel/Utilities/UnsafeUtility.cs b/Misaki.HighPerformance.LowLevel/Utilities/UnsafeUtility.cs
index 283c675..954232b 100644
--- a/Misaki.HighPerformance.LowLevel/Utilities/UnsafeUtility.cs
+++ b/Misaki.HighPerformance.LowLevel/Utilities/UnsafeUtility.cs
@@ -1,4 +1,4 @@
-using Misaki.HighPerformance.LowLevel.Collections;
+using Misaki.HighPerformance.LowLevel.Collections;
using System.Runtime.CompilerServices;
namespace Misaki.HighPerformance.LowLevel.Utilities;
@@ -39,7 +39,7 @@ public static unsafe class UnsafeUtility
/// Indicates the position of the element to be accessed within the array.
/// Returns a pointer to the element located at the specified index.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static T* ReadArrayElementUnsafe(void* ptr, int index)
+ public static T* ReadArrayElementUnsafe(void* ptr, nint index)
where T : unmanaged
{
return (T*)((byte*)ptr + index * sizeof(T));
@@ -53,10 +53,10 @@ public static unsafe class UnsafeUtility
/// Indicates the position of the element to be accessed within the array.
/// Returns a pointer to the element located at the specified index.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static T* ReadArrayElementUnsafe(void* ptr, uint index)
+ public static T* ReadArrayElementUnsafe(void* ptr, nuint index)
where T : unmanaged
{
- return (T*)((byte*)ptr + index * sizeof(T));
+ return (T*)((byte*)ptr + index * (nuint)sizeof(T));
}
///
@@ -67,7 +67,7 @@ public static unsafe class UnsafeUtility
/// Indicates the position of the element to be accessed in the array.
/// A reference to the specified element in the unmanaged array.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static ref T ReadArrayElementRef(void* ptr, int index)
+ public static ref T ReadArrayElementRef(void* ptr, nint index)
where T : unmanaged
{
return ref AsRef(ReadArrayElementUnsafe(ptr, index));
@@ -81,7 +81,7 @@ public static unsafe class UnsafeUtility
/// Indicates the position of the element to be accessed in the array.
/// A reference to the specified element in the unmanaged array.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static ref T ReadArrayElementRef(void* ptr, uint index)
+ public static ref T ReadArrayElementRef(void* ptr, nuint index)
where T : unmanaged
{
return ref AsRef(ReadArrayElementUnsafe(ptr, index));
@@ -95,7 +95,7 @@ public static unsafe class UnsafeUtility
/// Indicates the position of the element to be accessed within the array.
/// The element located at the specified index in the array.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static T ReadArrayElement(void* ptr, int index)
+ public static T ReadArrayElement(void* ptr, nint index)
where T : unmanaged
{
return *ReadArrayElementUnsafe(ptr, index);
@@ -109,7 +109,7 @@ public static unsafe class UnsafeUtility
/// Indicates the position of the element to be accessed within the array.
/// The element located at the specified index in the array.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static T ReadArrayElement(void* ptr, uint index)
+ public static T ReadArrayElement(void* ptr, nuint index)
where T : unmanaged
{
return *ReadArrayElementUnsafe(ptr, index);
@@ -123,7 +123,7 @@ public static unsafe class UnsafeUtility
/// Indicates the position in the array where the value should be stored.
/// Represents the value to be written to the specified index of the array.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void WriteArrayElement(void* ptr, int index, T value)
+ public static void WriteArrayElement(void* ptr, nint index, T value)
where T : unmanaged
{
*ReadArrayElementUnsafe(ptr, index) = value;
@@ -137,26 +137,12 @@ public static unsafe class UnsafeUtility
/// Indicates the position in the array where the value should be stored.
/// Represents the value to be written to the specified index of the array.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void WriteArrayElement(void* ptr, uint index, T value)
+ public static void WriteArrayElement(void* ptr, nuint index, T value)
where T : unmanaged
{
*ReadArrayElementUnsafe(ptr, index) = value;
}
- ///
- /// Converts an UnsafeArray of one unmanaged type to another unmanaged type without copying the elements.
- ///
- /// Represents the type of elements in the input array.
- /// Represents the type of elements in the output array.
- /// The input array containing elements of the specified input type.
- /// An UnsafeArray containing elements of the specified output type.
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static UnsafeArray CastArray(UnsafeArray array)
- where TIn : unmanaged where TOut : unmanaged
- {
- return new UnsafeArray((TOut*)array.GetUnsafePtr(), array.Count * sizeof(TIn) / sizeof(TOut));
- }
-
///
/// Returns a pointer to the first element of the specified span. This method enables direct, unsafe access to the underlying data of the span.
///
diff --git a/Misaki.HighPerformance.Test/Misaki.HighPerformance.Test.csproj b/Misaki.HighPerformance.Test/Misaki.HighPerformance.Test.csproj
index 669b9df..3f8aeb5 100644
--- a/Misaki.HighPerformance.Test/Misaki.HighPerformance.Test.csproj
+++ b/Misaki.HighPerformance.Test/Misaki.HighPerformance.Test.csproj
@@ -24,6 +24,8 @@
+
+
diff --git a/Misaki.HighPerformance.Test/Program.cs b/Misaki.HighPerformance.Test/Program.cs
index 73c2f0b..dc279df 100644
--- a/Misaki.HighPerformance.Test/Program.cs
+++ b/Misaki.HighPerformance.Test/Program.cs
@@ -18,6 +18,8 @@
//Console.WriteLine($"Count should be {threadCount * 990}, actual: {map.Count}");
+using Misaki.HighPerformance.LowLevel;
+
BenchmarkDotNet.Running.BenchmarkRunner.Run();
//using Misaki.HighPerformance.LowLevel.Buffer;
@@ -51,3 +53,15 @@ BenchmarkDotNet.Running.BenchmarkRunner.Run();
+unsafe
+{
+ var b = a.Share();
+ b.Get()->Value = 42;
+}
+
+internal struct MyStruct
+{
+ public int Value;
+}
\ No newline at end of file
diff --git a/Misaki.HighPerformance.sln b/Misaki.HighPerformance.sln
index 28cda71..971c3bb 100644
--- a/Misaki.HighPerformance.sln
+++ b/Misaki.HighPerformance.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 17
-VisualStudioVersion = 17.14.35821.62
+# Visual Studio Version 18
+VisualStudioVersion = 18.3.11218.70 d18.3
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Misaki.HighPerformance", "Misaki.HighPerformance\Misaki.HighPerformance.csproj", "{275B2E80-9B2A-4567-A157-F147A6B28A0F}"
EndProject
@@ -17,6 +17,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Misaki.HighPerformance.Math
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Misaki.HighPerformance.Mathematics.CodeGen", "Misaki.HighPerformance.Mathematics.CodeGen\Misaki.HighPerformance.Mathematics.CodeGen.csproj", "{405082D2-B7D5-480F-A3D8-B140E5E2D5AA}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Misaki.HighPerformance.Analyzer", "Misaki.HighPerformance.Analyzer\Misaki.HighPerformance.Analyzer\Misaki.HighPerformance.Analyzer.csproj", "{9809478A-9877-4DF8-BE22-03DAB495BE75}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Misaki.HighPerformance.Analyzer.CodeFixes", "Misaki.HighPerformance.Analyzer\Misaki.HighPerformance.Analyzer.CodeFixes\Misaki.HighPerformance.Analyzer.CodeFixes.csproj", "{8E36FFCE-A772-428C-BF73-276A41661E23}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Misaki.HighPerformance.Analyzer.Package", "Misaki.HighPerformance.Analyzer\Misaki.HighPerformance.Analyzer.Package\Misaki.HighPerformance.Analyzer.Package.csproj", "{446213EF-4E44-4EEF-970A-536F0AFC7AEB}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Analyzer", "Analyzer", "{457CB43B-38FA-4221-BCC2-BE866D0A2A06}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -51,10 +59,27 @@ Global
{405082D2-B7D5-480F-A3D8-B140E5E2D5AA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{405082D2-B7D5-480F-A3D8-B140E5E2D5AA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{405082D2-B7D5-480F-A3D8-B140E5E2D5AA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {9809478A-9877-4DF8-BE22-03DAB495BE75}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {9809478A-9877-4DF8-BE22-03DAB495BE75}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {9809478A-9877-4DF8-BE22-03DAB495BE75}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {9809478A-9877-4DF8-BE22-03DAB495BE75}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8E36FFCE-A772-428C-BF73-276A41661E23}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8E36FFCE-A772-428C-BF73-276A41661E23}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8E36FFCE-A772-428C-BF73-276A41661E23}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8E36FFCE-A772-428C-BF73-276A41661E23}.Release|Any CPU.Build.0 = Release|Any CPU
+ {446213EF-4E44-4EEF-970A-536F0AFC7AEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {446213EF-4E44-4EEF-970A-536F0AFC7AEB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {446213EF-4E44-4EEF-970A-536F0AFC7AEB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {446213EF-4E44-4EEF-970A-536F0AFC7AEB}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {9809478A-9877-4DF8-BE22-03DAB495BE75} = {457CB43B-38FA-4221-BCC2-BE866D0A2A06}
+ {8E36FFCE-A772-428C-BF73-276A41661E23} = {457CB43B-38FA-4221-BCC2-BE866D0A2A06}
+ {446213EF-4E44-4EEF-970A-536F0AFC7AEB} = {457CB43B-38FA-4221-BCC2-BE866D0A2A06}
+ EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {51A97B1D-DB4D-45BC-8D2E-347710C1AA37}
EndGlobalSection