diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 00000000..1ff0c423
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,63 @@
+###############################################################################
+# Set default behavior to automatically normalize line endings.
+###############################################################################
+* text=auto
+
+###############################################################################
+# Set default behavior for command prompt diff.
+#
+# This is need for earlier builds of msysgit that does not have it on by
+# default for csharp files.
+# Note: This is only used by command line
+###############################################################################
+#*.cs diff=csharp
+
+###############################################################################
+# Set the merge driver for project and solution files
+#
+# Merging from the command prompt will add diff markers to the files if there
+# are conflicts (Merging from VS is not affected by the settings below, in VS
+# the diff markers are never inserted). Diff markers may cause the following
+# file extensions to fail to load in VS. An alternative would be to treat
+# these files as binary and thus will always conflict and require user
+# intervention with every merge. To do so, just uncomment the entries below
+###############################################################################
+#*.sln merge=binary
+#*.csproj merge=binary
+#*.vbproj merge=binary
+#*.vcxproj merge=binary
+#*.vcproj merge=binary
+#*.dbproj merge=binary
+#*.fsproj merge=binary
+#*.lsproj merge=binary
+#*.wixproj merge=binary
+#*.modelproj merge=binary
+#*.sqlproj merge=binary
+#*.wwaproj merge=binary
+
+###############################################################################
+# behavior for image files
+#
+# image files are treated as binary by default.
+###############################################################################
+#*.jpg binary
+#*.png binary
+#*.gif binary
+
+###############################################################################
+# diff behavior for common document formats
+#
+# Convert binary document formats to text before diffing them. This feature
+# is only available from the command line. Turn it on by uncommenting the
+# entries below.
+###############################################################################
+#*.doc diff=astextplain
+#*.DOC diff=astextplain
+#*.docx diff=astextplain
+#*.DOCX diff=astextplain
+#*.dot diff=astextplain
+#*.DOT diff=astextplain
+#*.pdf diff=astextplain
+#*.PDF diff=astextplain
+#*.rtf diff=astextplain
+#*.RTF diff=astextplain
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..3a2238d6
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,245 @@
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+
+# User-specific files
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+[Xx]64/
+[Xx]86/
+[Bb]uild/
+bld/
+[Bb]in/
+[Oo]bj/
+
+# Visual Studio 2015 cache/options directory
+.vs/
+# Uncomment if you have tasks that create the project's static files in wwwroot
+#wwwroot/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+# NUNIT
+*.VisualState.xml
+TestResult.xml
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+# DNX
+project.lock.json
+artifacts/
+
+*_i.c
+*_p.c
+*_i.h
+*.ilk
+*.meta
+*.obj
+*.pch
+*.pdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*.log
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
+
+# Chutzpah Test files
+_Chutzpah*
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opendb
+*.opensdf
+*.sdf
+*.cachefile
+*.VC.db
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+*.sap
+
+# TFS 2012 Local Workspace
+$tf/
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# JustCode is a .NET coding add-in
+.JustCode
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# NCrunch
+_NCrunch_*
+.*crunch*.local.xml
+nCrunchTemp_*
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.[Pp]ublish.xml
+*.azurePubxml
+
+# TODO: Un-comment the next line if you do not want to checkin
+# your web deploy settings because they may include unencrypted
+# passwords
+#*.pubxml
+*.publishproj
+
+# NuGet Packages
+*.nupkg
+# The packages folder can be ignored because of Package Restore
+**/packages/*
+# except build/, which is used as an MSBuild target.
+!**/packages/build/
+# Uncomment if necessary however generally it will be regenerated when needed
+#!**/packages/repositories.config
+# NuGet v3's project.json files produces more ignoreable files
+*.nuget.props
+*.nuget.targets
+
+# Microsoft Azure Build Output
+csx/
+*.build.csdef
+
+# Microsoft Azure Emulator
+ecf/
+rcf/
+
+# Microsoft Azure ApplicationInsights config file
+ApplicationInsights.config
+
+# Windows Store app package directory
+AppPackages/
+BundleArtifacts/
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!*.[Cc]ache/
+
+# Others
+ClientBin/
+[Ss]tyle[Cc]op.*
+~$*
+*~
+*.dbmdl
+*.dbproj.schemaview
+*.pfx
+*.publishsettings
+node_modules/
+orleans.codegen.cs
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+
+# SQL Server files
+*.mdf
+*.ldf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+
+# Microsoft Fakes
+FakesAssemblies/
+
+# GhostDoc plugin setting file
+*.GhostDoc.xml
+
+# Node.js Tools for Visual Studio
+.ntvs_analysis.dat
+
+# Visual Studio 6 build log
+*.plg
+
+# Visual Studio 6 workspace options file
+*.opt
+
+# Visual Studio LightSwitch build output
+**/*.HTMLClient/GeneratedArtifacts
+**/*.DesktopClient/GeneratedArtifacts
+**/*.DesktopClient/ModelManifest.xml
+**/*.Server/GeneratedArtifacts
+**/*.Server/ModelManifest.xml
+_Pvt_Extensions
+
+# LightSwitch generated files
+GeneratedArtifacts/
+ModelManifest.xml
+
+# Paket dependency manager
+.paket/paket.exe
+
+# FAKE - F# Make
+.fake/
\ No newline at end of file
diff --git a/Source/AsyncGenerator/AsyncGenerator.Tests/AsyncGenerator.Tests.csproj b/Source/AsyncGenerator/AsyncGenerator.Tests/AsyncGenerator.Tests.csproj
new file mode 100644
index 00000000..0c2d9715
--- /dev/null
+++ b/Source/AsyncGenerator/AsyncGenerator.Tests/AsyncGenerator.Tests.csproj
@@ -0,0 +1,273 @@
+
+
+
+ Debug
+ AnyCPU
+ {0A3D852A-5C81-4E74-AC16-85BA2EBF3581}
+ Library
+ Properties
+ AsyncGenerator.Tests
+ AsyncGenerator.Tests
+ v4.6.1
+ 512
+ {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ 10.0
+ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
+ $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages
+ False
+ UnitTest
+
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+ ..\packages\ManagedEsent.1.9.4\lib\net40\Esent.Interop.dll
+ True
+
+
+ ..\packages\Microsoft.CodeAnalysis.Common.2.0.0\lib\netstandard1.3\Microsoft.CodeAnalysis.dll
+ True
+
+
+ ..\packages\Microsoft.CodeAnalysis.CSharp.2.0.0\lib\netstandard1.3\Microsoft.CodeAnalysis.CSharp.dll
+ True
+
+
+ ..\packages\Microsoft.CodeAnalysis.CSharp.Workspaces.2.0.0\lib\netstandard1.3\Microsoft.CodeAnalysis.CSharp.Workspaces.dll
+ True
+
+
+ ..\packages\Microsoft.CodeAnalysis.Elfie.0.10.6\lib\net46\Microsoft.CodeAnalysis.Elfie.dll
+ True
+
+
+ ..\packages\Microsoft.CodeAnalysis.Workspaces.Common.2.0.0\lib\net46\Microsoft.CodeAnalysis.Workspaces.dll
+ True
+
+
+ ..\packages\Microsoft.CodeAnalysis.Workspaces.Common.2.0.0\lib\net46\Microsoft.CodeAnalysis.Workspaces.Desktop.dll
+ True
+
+
+
+ ..\packages\Microsoft.Web.Xdt.2.1.1\lib\net40\Microsoft.Web.XmlTransform.dll
+ True
+
+
+ ..\packages\Newtonsoft.Json.6.0.4\lib\net45\Newtonsoft.Json.dll
+ True
+
+
+ ..\packages\NuGet.Common.4.0.0\lib\net45\NuGet.Common.dll
+ True
+
+
+ ..\packages\NuGet.ContentModel.4.0.0\lib\net45\NuGet.ContentModel.dll
+ True
+
+
+ ..\packages\NuGet.Core.2.14.0\lib\net40-Client\NuGet.Core.dll
+ True
+
+
+ ..\packages\NuGet.Frameworks.4.0.0\lib\net45\NuGet.Frameworks.dll
+ True
+
+
+ ..\packages\NuGet.Packaging.4.0.0\lib\net45\NuGet.Packaging.dll
+ True
+
+
+ ..\packages\NuGet.Packaging.Core.4.0.0\lib\net45\NuGet.Packaging.Core.dll
+ True
+
+
+ ..\packages\NuGet.Packaging.Core.Types.4.0.0\lib\net45\NuGet.Packaging.Core.Types.dll
+ True
+
+
+ ..\packages\NuGet.Repositories.4.0.0\lib\net45\NuGet.Repositories.dll
+ True
+
+
+ ..\packages\NuGet.RuntimeModel.4.0.0\lib\net45\NuGet.RuntimeModel.dll
+ True
+
+
+ ..\packages\NuGet.Versioning.4.0.0\lib\net45\NuGet.Versioning.dll
+ True
+
+
+ ..\packages\NUnit.3.6.1\lib\net45\nunit.framework.dll
+ True
+
+
+
+ ..\packages\System.AppContext.4.3.0\lib\net46\System.AppContext.dll
+ True
+
+
+ ..\packages\System.Collections.Immutable.1.3.1\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll
+ True
+
+
+
+ ..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.AttributedModel.dll
+ True
+
+
+ ..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.Convention.dll
+ True
+
+
+ ..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.Hosting.dll
+ True
+
+
+ ..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.Runtime.dll
+ True
+
+
+ ..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.TypedParts.dll
+ True
+
+
+ ..\packages\System.Console.4.3.0\lib\net46\System.Console.dll
+ True
+
+
+ ..\packages\System.Diagnostics.FileVersionInfo.4.3.0\lib\net46\System.Diagnostics.FileVersionInfo.dll
+ True
+
+
+ ..\packages\System.Diagnostics.StackTrace.4.3.0\lib\net46\System.Diagnostics.StackTrace.dll
+ True
+
+
+ ..\packages\System.IO.Compression.4.3.0\lib\net46\System.IO.Compression.dll
+ True
+
+
+ ..\packages\System.IO.FileSystem.4.3.0\lib\net46\System.IO.FileSystem.dll
+ True
+
+
+ ..\packages\System.IO.FileSystem.Primitives.4.3.0\lib\net46\System.IO.FileSystem.Primitives.dll
+ True
+
+
+
+ ..\packages\System.Reflection.Metadata.1.4.2\lib\portable-net45+win8\System.Reflection.Metadata.dll
+ True
+
+
+ ..\packages\System.Security.Cryptography.Algorithms.4.3.0\lib\net461\System.Security.Cryptography.Algorithms.dll
+ True
+
+
+ ..\packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll
+ True
+
+
+ ..\packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll
+ True
+
+
+ ..\packages\System.Security.Cryptography.X509Certificates.4.3.0\lib\net461\System.Security.Cryptography.X509Certificates.dll
+ True
+
+
+ ..\packages\System.Text.Encoding.CodePages.4.3.0\lib\net46\System.Text.Encoding.CodePages.dll
+ True
+
+
+ ..\packages\System.Threading.Thread.4.3.0\lib\net46\System.Threading.Thread.dll
+ True
+
+
+ ..\packages\System.ValueTuple.4.3.0\lib\netstandard1.0\System.ValueTuple.dll
+ True
+
+
+
+
+ ..\packages\System.Xml.ReaderWriter.4.3.0\lib\net46\System.Xml.ReaderWriter.dll
+ True
+
+
+ ..\packages\System.Xml.XmlDocument.4.3.0\lib\net46\System.Xml.XmlDocument.dll
+ True
+
+
+ ..\packages\System.Xml.XPath.4.3.0\lib\net46\System.Xml.XPath.dll
+ True
+
+
+ ..\packages\System.Xml.XPath.XDocument.4.3.0\lib\net46\System.Xml.XPath.XDocument.dll
+ True
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ False
+
+
+ False
+
+
+ False
+
+
+ False
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Source/AsyncGenerator/AsyncGenerator.Tests/Properties/AssemblyInfo.cs b/Source/AsyncGenerator/AsyncGenerator.Tests/Properties/AssemblyInfo.cs
new file mode 100644
index 00000000..d1627383
--- /dev/null
+++ b/Source/AsyncGenerator/AsyncGenerator.Tests/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("AsyncGenerator.Tests")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("AsyncGenerator.Tests")]
+[assembly: AssemblyCopyright("Copyright © 2017")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("0a3d852a-5c81-4e74-ac16-85ba2ebf3581")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/Source/AsyncGenerator/AsyncGenerator.Tests/UnitTest1.cs b/Source/AsyncGenerator/AsyncGenerator.Tests/UnitTest1.cs
new file mode 100644
index 00000000..5b8ad875
--- /dev/null
+++ b/Source/AsyncGenerator/AsyncGenerator.Tests/UnitTest1.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using NuGet;
+using NUnit.Framework;
+
+namespace AsyncGenerator.Tests
+{
+ public class UnitTest1
+ {
+ [Test]
+ public void TestMethod1()
+ {
+ //ID of the package to be looked up
+ string packageID = "EntityFramework";
+
+ //Connect to the official package repository
+ IPackageRepository repo = PackageRepositoryFactory.Default.CreateRepository("https://packages.nuget.org/api/v2");
+
+ //Get the list of all NuGet packages with ID 'EntityFramework'
+ var package = repo.FindPackagesById(packageID)
+ .First(o => o.IsLatestVersion);
+ //.First(o => o.Version.ToFullString() == "5.0.0");
+
+
+ //Initialize the package manager
+ var path = @"C:\Workspace\Git\AsyncGenerator\Source\AsyncGenerator\packages";
+ var packageManager = new PackageManager(repo, path);
+
+ //Download and unzip the package
+ packageManager.InstallPackage(package, false, false);
+ }
+
+ }
+}
diff --git a/Source/AsyncGenerator/AsyncGenerator.Tests/app.config b/Source/AsyncGenerator/AsyncGenerator.Tests/app.config
new file mode 100644
index 00000000..0f29e48a
--- /dev/null
+++ b/Source/AsyncGenerator/AsyncGenerator.Tests/app.config
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Source/AsyncGenerator/AsyncGenerator.Tests/packages.config b/Source/AsyncGenerator/AsyncGenerator.Tests/packages.config
new file mode 100644
index 00000000..f61cece1
--- /dev/null
+++ b/Source/AsyncGenerator/AsyncGenerator.Tests/packages.config
@@ -0,0 +1,65 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Source/AsyncGenerator/AsyncGenerator.sln b/Source/AsyncGenerator/AsyncGenerator.sln
new file mode 100644
index 00000000..68e2bdb1
--- /dev/null
+++ b/Source/AsyncGenerator/AsyncGenerator.sln
@@ -0,0 +1,28 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 14
+VisualStudioVersion = 14.0.25123.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AsyncGenerator", "AsyncGenerator\AsyncGenerator.csproj", "{9D321EA8-54AE-4741-86A8-12198551AD67}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AsyncGenerator.Tests", "AsyncGenerator.Tests\AsyncGenerator.Tests.csproj", "{0A3D852A-5C81-4E74-AC16-85BA2EBF3581}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {9D321EA8-54AE-4741-86A8-12198551AD67}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {9D321EA8-54AE-4741-86A8-12198551AD67}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {9D321EA8-54AE-4741-86A8-12198551AD67}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {9D321EA8-54AE-4741-86A8-12198551AD67}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0A3D852A-5C81-4E74-AC16-85BA2EBF3581}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0A3D852A-5C81-4E74-AC16-85BA2EBF3581}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0A3D852A-5C81-4E74-AC16-85BA2EBF3581}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0A3D852A-5C81-4E74-AC16-85BA2EBF3581}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/Source/AsyncGenerator/AsyncGenerator/AsyncCodeGenerator.cs b/Source/AsyncGenerator/AsyncGenerator/AsyncCodeGenerator.cs
new file mode 100644
index 00000000..75e55dae
--- /dev/null
+++ b/Source/AsyncGenerator/AsyncGenerator/AsyncCodeGenerator.cs
@@ -0,0 +1,439 @@
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using AsyncGenerator.Configuration;
+using AsyncGenerator.Internal;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.FindSymbols;
+using Microsoft.CodeAnalysis.MSBuild;
+
+namespace AsyncGenerator
+{
+ public class MethodData
+ {
+ public MethodData(TypeData typeData, IMethodSymbol symbol, MethodDeclarationSyntax node)
+ {
+ TypeData = typeData;
+ Symbol = symbol;
+ Node = node;
+ }
+
+ public TypeData TypeData { get; }
+
+ public IMethodSymbol Symbol { get; }
+
+ public MethodDeclarationSyntax Node { get; }
+ }
+
+ public class TypeData
+ {
+ public TypeData(NamespaceData namespaceData, INamedTypeSymbol symbol, TypeDeclarationSyntax node, TypeData parentTypeData = null)
+ {
+ NamespaceData = namespaceData;
+ ParentTypeData = parentTypeData;
+ Symbol = symbol;
+ Node = node;
+ }
+
+ public HashSet References { get; } = new HashSet();
+
+ public TypeData ParentTypeData { get; }
+
+ public NamespaceData NamespaceData { get; }
+
+ public INamedTypeSymbol Symbol { get; }
+
+ public TypeDeclarationSyntax Node { get; }
+
+ public ConcurrentDictionary MethodData { get; } = new ConcurrentDictionary();
+
+ public ConcurrentDictionary NestedTypeData { get; } = new ConcurrentDictionary();
+ }
+
+ public class NamespaceData
+ {
+ public NamespaceData(DocumentData documentData, INamespaceSymbol symbol, NamespaceDeclarationSyntax node)
+ {
+ DocumentData = documentData;
+ Symbol = symbol;
+ Node = node;
+ }
+
+ public DocumentData DocumentData { get; }
+
+ public INamespaceSymbol Symbol { get; }
+
+ public NamespaceDeclarationSyntax Node { get; }
+
+ public bool IsGlobal => Node == null;
+
+ public ConcurrentDictionary TypeData { get; } = new ConcurrentDictionary();
+
+ public TypeData GetTypeData(TypeDeclarationSyntax node, bool create = false)
+ {
+ var typeSymbol = DocumentData.SemanticModel.GetDeclaredSymbol(node);
+ return GetTypeData(typeSymbol, create);
+ }
+
+ public TypeData GetTypeData(MethodDeclarationSyntax node, bool create = false)
+ {
+ var typeSymbol = DocumentData.SemanticModel.GetDeclaredSymbol(node).ContainingType;
+ return GetTypeData(typeSymbol, create);
+ }
+
+ public TypeData GetTypeData(IMethodSymbol symbol, bool create = false)
+ {
+ return GetTypeData(symbol.ContainingType, create);
+ }
+
+ public TypeData GetTypeData(INamedTypeSymbol type, bool create = false)
+ {
+ var nestedTypes = new Stack();
+ while (type != null)
+ {
+ nestedTypes.Push(type);
+ type = type.ContainingType;
+ }
+ TypeData currentTypeData = null;
+ var path = DocumentData.FilePath;
+ while (nestedTypes.Count > 0)
+ {
+ var typeSymbol = nestedTypes.Pop().OriginalDefinition;
+ var location = typeSymbol.Locations.Single(o => o.SourceTree.FilePath == path);
+ var namespaceNode = Node ?? (SyntaxNode)DocumentData.RootNode; // Global namespace
+ var node = namespaceNode.DescendantNodes()
+ .OfType()
+ .First(o => o.ChildTokens().First(t => t.IsKind(SyntaxKind.IdentifierToken)).Span == location.SourceSpan);
+
+ var typeDataDict = currentTypeData?.NestedTypeData ?? TypeData;
+ TypeData typeData;
+ if (typeDataDict.TryGetValue(node, out typeData))
+ {
+ currentTypeData = typeData;
+ continue;
+ }
+ if (!create)
+ {
+ return null;
+ }
+ currentTypeData = typeDataDict.GetOrAdd(node, syntax => new TypeData(this, typeSymbol, node, currentTypeData));
+ }
+ return currentTypeData;
+ }
+ }
+
+ public class DocumentData
+ {
+ public DocumentData(ProjectData projectData, Document document, CompilationUnitSyntax rootNode, SemanticModel semanticModel)
+ {
+ ProjectData = projectData;
+ Document = document;
+ RootNode = rootNode;
+ SemanticModel = semanticModel;
+ GlobalNamespaceData = new NamespaceData(this, SemanticModel.Compilation.GlobalNamespace, null);
+ }
+
+ public Document Document { get; }
+
+ public string FilePath => Document.FilePath;
+
+ public ProjectData ProjectData { get; }
+
+ public CompilationUnitSyntax RootNode { get; }
+
+ public SemanticModel SemanticModel { get; }
+
+ public NamespaceData GlobalNamespaceData { get; }
+
+ public ConcurrentDictionary NamespaceData { get; } = new ConcurrentDictionary();
+
+ public TypeData GetOrCreateTypeData(TypeDeclarationSyntax node)
+ {
+ return GetNamespaceData(node, true).GetTypeData(node, true);
+ }
+
+ private NamespaceData GetNamespaceData(SyntaxNode node, bool create = false)
+ {
+ if (node == null)
+ {
+ return GlobalNamespaceData;
+ }
+ var namespaceNode = node.AncestorsAndSelf().OfType().FirstOrDefault();
+ if (namespaceNode == null)
+ {
+ return GlobalNamespaceData;
+ }
+ var namespaceSymbol = (INamespaceSymbol)ModelExtensions.GetDeclaredSymbol(SemanticModel, namespaceNode);
+ return GetNamespaceData(namespaceNode, namespaceSymbol, create);
+ }
+
+ private NamespaceData GetNamespaceData(NamespaceDeclarationSyntax namespaceNode, INamespaceSymbol namespaceSymbol, bool create = false)
+ {
+ NamespaceData namespaceData;
+ if (NamespaceData.TryGetValue(namespaceNode, out namespaceData))
+ {
+ return namespaceData;
+ }
+ return !create ? null : NamespaceData.GetOrAdd(namespaceNode, syntax => new NamespaceData(this, namespaceSymbol, namespaceNode));
+ }
+ }
+
+ public class ProjectData
+ {
+ private readonly SolutionData _solutionData;
+
+ public ProjectData(SolutionData solutionData, ProjectId projectId, ProjectConfiguration configuration)
+ {
+ _solutionData = solutionData;
+ Configuration = configuration;
+ ProjectId = projectId;
+ DirectoryPath = Path.GetDirectoryName(Project.FilePath) + @"\";
+ }
+
+ internal readonly ProjectConfiguration Configuration;
+
+ public string DirectoryPath { get; }
+
+ public ProjectId ProjectId { get; }
+
+ public Project Project
+ {
+ get { return _solutionData.Solution.GetProject(ProjectId); }
+ set { _solutionData.Solution = value.Solution; }
+ }
+
+ public ConcurrentDictionary DocumentData { get; } = new ConcurrentDictionary();
+
+
+ public DocumentData GetDocumentData(Document document)
+ {
+ DocumentData documentData;
+ if (!DocumentData.TryGetValue(document.FilePath, out documentData))
+ {
+ throw new InvalidOperationException($"Document {document.FilePath} was not found in the project {Project.Name}");
+ }
+ return documentData;
+ }
+
+ public async Task CreateDocumentData(Document document)
+ {
+ if (document.Project != Project)
+ {
+ throw new InvalidOperationException($"Document {document.FilePath} does not belong to project {Project.Name}");
+ }
+ var rootNode = (CompilationUnitSyntax)await document.GetSyntaxRootAsync().ConfigureAwait(false);
+ var semanticModel = await document.GetSemanticModelAsync().ConfigureAwait(false);
+ var documentData = new DocumentData(this, document, rootNode, semanticModel);
+ return DocumentData.AddOrUpdate(document.FilePath, documentData, (s, data) => documentData);
+ }
+
+ }
+
+ public class SolutionData
+ {
+ public SolutionData(Solution solution, MSBuildWorkspace buildWorkspace, SolutionConfiguration configuration)
+ {
+ Configuration = configuration;
+ Workspace = buildWorkspace;
+ Solution = solution;
+ }
+
+ public MSBuildWorkspace Workspace { get; }
+
+ public readonly SolutionConfiguration Configuration;
+
+ public Solution Solution { get; set; }
+
+ internal ConcurrentDictionary ProjectData { get; } = new ConcurrentDictionary();
+
+ }
+
+ public class ProjectAnalyzer
+ {
+ private IImmutableSet _analyzeDocuments;
+ private ProjectAnalyzeConfiguration _configuration;
+
+ public ProjectAnalyzer(ProjectData projectData)
+ {
+ ProjectData = projectData;
+ }
+
+ public ProjectData ProjectData { get; }
+
+ public async Task Analyze()
+ {
+ Setup();
+ var documentData = await Task.WhenAll(_analyzeDocuments
+ .Select(o => ProjectData.CreateDocumentData(o)))
+ .ConfigureAwait(false);
+
+ await Task.WhenAll(documentData
+ .Select(AnalyzeDocumentData))
+ .ConfigureAwait(false);
+ }
+
+
+ public async Task AnalyzeDocumentData(DocumentData documentData)
+ {
+ foreach (var typeDeclaration in documentData.RootNode
+ .DescendantNodes()
+ .OfType())
+ {
+ var typeData = documentData.GetOrCreateTypeData(typeDeclaration);
+ if (!_configuration.TypeSelectionPredicate(typeData.Symbol))
+ {
+ continue;
+ }
+ var typeTransform = _configuration.TypeConversionFunction(typeData.Symbol);
+ // If the type have to be defined as a new type then we need to find all references to that type
+ if (typeTransform == TypeConversion.NewType)
+ {
+ await ScanForTypeReferences(typeData).ConfigureAwait(false);
+ }
+ }
+ }
+
+ ///
+ /// When a type needs to be defined as a new type we need to find all references to them.
+ /// Reference can point to a variable, field, base type, argument definition
+ ///
+ private async Task ScanForTypeReferences(TypeData typeData)
+ {
+ // References for ctor of the type and the type itself wont have any locations
+ var references = await SymbolFinder.FindReferencesAsync(typeData.Symbol, ProjectData.Project.Solution, _analyzeDocuments).ConfigureAwait(false);
+ foreach (var refLocation in references.SelectMany(o => o.Locations))
+ {
+ var documentData = ProjectData.GetDocumentData(refLocation.Document);
+ typeData.References.Add(refLocation);
+
+ // we need to find the type where the reference location is
+ var node = documentData.RootNode.DescendantNodes(descendIntoTrivia: true)
+ .First(
+ o =>
+ {
+ if (o.IsKind(SyntaxKind.GenericName))
+ {
+ return o.ChildTokens().First(t => t.IsKind(SyntaxKind.IdentifierToken)).Span ==
+ refLocation.Location.SourceSpan;
+ }
+ return o.Span == refLocation.Location.SourceSpan;
+ });
+
+ var methodNode = node.Ancestors().OfType().FirstOrDefault();
+ if (methodNode != null)
+ {
+ var methodInfo = documentData.GetOrCreateMethodInfo(methodNode, true);
+ if (methodInfo.TypeReferences.Contains(refLocation))
+ {
+ continue;
+ }
+ methodInfo.TypeReferences.Add(refLocation);
+ }
+ else
+ {
+ var type = node.Ancestors().OfType().FirstOrDefault();
+ if (type != null)
+ {
+ var refTypeInfo = documentData.GetOrCreateTypeInfo(type);
+ if (refTypeInfo.TypeReferences.Contains(refLocation))
+ {
+ continue;
+ }
+ refTypeInfo.TypeReferences.Add(refLocation);
+ }
+ else // can happen when declaring a Name in a using statement
+ {
+ var namespaceNode = node.Ancestors().OfType().FirstOrDefault();
+ var namespaceInfo = documentData.GetNamespaceInfo(namespaceNode, true);
+ if (namespaceInfo.TypeReferences.Contains(refLocation))
+ {
+ continue;
+ }
+ namespaceInfo.TypeReferences.Add(refLocation);
+ }
+ }
+ }
+ }
+
+ private void Setup()
+ {
+ _configuration = ProjectData.Configuration.AnalyzeConfiguration;
+
+ // Documents that can be analyzed
+ _analyzeDocuments = ProjectData.Project.Documents.Where(o => _configuration.DocumentSelectionPredicate(o)).ToImmutableHashSet();
+ }
+ }
+
+
+ public class AsyncCodeGenerator
+ {
+ public async Task GenerateAsync(IAsyncCodeConfiguration configuration)
+ {
+ if (configuration == null)
+ {
+ throw new ArgumentNullException(nameof(configuration));
+ }
+ var conf = configuration.Build();
+
+ foreach (var config in conf.SolutionConfigurations)
+ {
+ var solutionData = await CreateSolutionData(config).ConfigureAwait(false);
+ foreach (var projectData in solutionData.ProjectData.Values)
+ {
+ await AnalyzeProject(projectData).ConfigureAwait(false);
+ }
+ }
+
+ //conf.SolutionConfigurations.First().ProjectConfigurations.First().TransformConfiguration.
+ }
+
+ private Task AnalyzeProject(ProjectData projectData)
+ {
+ var analyzer = new ProjectAnalyzer(projectData);
+ return analyzer.Analyze();
+ }
+
+
+ private async Task CreateSolutionData(SolutionConfiguration configuration)
+ {
+ var workspace = MSBuildWorkspace.Create();
+ var solution = await workspace.OpenSolutionAsync(configuration.Path).ConfigureAwait(false);
+ var solutionData = new SolutionData(solution, workspace, configuration);
+
+ var projectConfigs = configuration.ProjectConfigurations.ToDictionary(o => o.Name);
+ foreach (var project in solution.Projects.Where(o => projectConfigs.ContainsKey(o.Name)))
+ {
+ var config = projectConfigs[project.Name];
+ var projectData = new ProjectData(solutionData, project.Id, config);
+ RemoveGeneratedDocuments(projectData);
+ solutionData.ProjectData.AddOrUpdate(project.Id, projectData, (id, data) => projectData);
+ }
+ return solutionData;
+ }
+
+ private void RemoveGeneratedDocuments(ProjectData projectData)
+ {
+ var project = projectData.Project;
+ var asyncFolder = projectData.Configuration.TransformConfiguration.AsyncFolder;
+ if (string.IsNullOrEmpty(asyncFolder))
+ {
+ return;
+ }
+ var asyncProjectFolder = Path.Combine(projectData.DirectoryPath, asyncFolder) + @"\";
+ // remove all generated documents
+ var toRemove = project.Documents.Where(o => o.FilePath.StartsWith(asyncProjectFolder)).Select(doc => doc.Id).ToList();
+ foreach (var docId in toRemove)
+ {
+ project = project.RemoveDocument(docId);
+ }
+ projectData.Project = project;
+ }
+ }
+}
diff --git a/Source/AsyncGenerator/AsyncGenerator/AsyncGenerator.csproj b/Source/AsyncGenerator/AsyncGenerator/AsyncGenerator.csproj
new file mode 100644
index 00000000..7e3f5a10
--- /dev/null
+++ b/Source/AsyncGenerator/AsyncGenerator/AsyncGenerator.csproj
@@ -0,0 +1,213 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {9D321EA8-54AE-4741-86A8-12198551AD67}
+ Library
+ Properties
+ AsyncGenerator
+ AsyncGenerator
+ v4.6.1
+ 512
+
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+ ..\packages\ManagedEsent.1.9.4\lib\net40\Esent.Interop.dll
+ True
+
+
+ ..\packages\Microsoft.CodeAnalysis.Common.2.0.0\lib\netstandard1.3\Microsoft.CodeAnalysis.dll
+ True
+
+
+ ..\packages\Microsoft.CodeAnalysis.CSharp.2.0.0\lib\netstandard1.3\Microsoft.CodeAnalysis.CSharp.dll
+ True
+
+
+ ..\packages\Microsoft.CodeAnalysis.CSharp.Workspaces.2.0.0\lib\netstandard1.3\Microsoft.CodeAnalysis.CSharp.Workspaces.dll
+ True
+
+
+ ..\packages\Microsoft.CodeAnalysis.Elfie.0.10.6\lib\net46\Microsoft.CodeAnalysis.Elfie.dll
+ True
+
+
+ ..\packages\Microsoft.CodeAnalysis.Workspaces.Common.2.0.0\lib\net46\Microsoft.CodeAnalysis.Workspaces.dll
+ True
+
+
+ ..\packages\Microsoft.CodeAnalysis.Workspaces.Common.2.0.0\lib\net46\Microsoft.CodeAnalysis.Workspaces.Desktop.dll
+ True
+
+
+ ..\packages\Microsoft.Web.Xdt.2.1.1\lib\net40\Microsoft.Web.XmlTransform.dll
+ True
+
+
+ ..\packages\NuGet.Core.2.14.0\lib\net40-Client\NuGet.Core.dll
+ True
+
+
+
+ ..\packages\System.AppContext.4.3.0\lib\net46\System.AppContext.dll
+ True
+
+
+ ..\packages\System.Collections.Immutable.1.3.1\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll
+ True
+
+
+
+ ..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.AttributedModel.dll
+ True
+
+
+ ..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.Convention.dll
+ True
+
+
+ ..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.Hosting.dll
+ True
+
+
+ ..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.Runtime.dll
+ True
+
+
+ ..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.TypedParts.dll
+ True
+
+
+ ..\packages\System.Console.4.3.0\lib\net46\System.Console.dll
+ True
+
+
+
+ ..\packages\System.Diagnostics.FileVersionInfo.4.3.0\lib\net46\System.Diagnostics.FileVersionInfo.dll
+ True
+
+
+ ..\packages\System.Diagnostics.StackTrace.4.3.0\lib\net46\System.Diagnostics.StackTrace.dll
+ True
+
+
+ ..\packages\System.IO.Compression.4.3.0\lib\net46\System.IO.Compression.dll
+ True
+
+
+ ..\packages\System.IO.FileSystem.4.3.0\lib\net46\System.IO.FileSystem.dll
+ True
+
+
+ ..\packages\System.IO.FileSystem.Primitives.4.3.0\lib\net46\System.IO.FileSystem.Primitives.dll
+ True
+
+
+
+ ..\packages\System.Reflection.Metadata.1.4.2\lib\portable-net45+win8\System.Reflection.Metadata.dll
+ True
+
+
+ ..\packages\System.Security.Cryptography.Algorithms.4.3.0\lib\net461\System.Security.Cryptography.Algorithms.dll
+ True
+
+
+ ..\packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll
+ True
+
+
+ ..\packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll
+ True
+
+
+ ..\packages\System.Security.Cryptography.X509Certificates.4.3.0\lib\net461\System.Security.Cryptography.X509Certificates.dll
+ True
+
+
+ ..\packages\System.Text.Encoding.CodePages.4.3.0\lib\net46\System.Text.Encoding.CodePages.dll
+ True
+
+
+ ..\packages\System.Threading.Thread.4.3.0\lib\net46\System.Threading.Thread.dll
+ True
+
+
+ ..\packages\System.ValueTuple.4.3.0\lib\netstandard1.0\System.ValueTuple.dll
+ True
+
+
+
+
+
+
+
+
+ ..\packages\System.Xml.ReaderWriter.4.3.0\lib\net46\System.Xml.ReaderWriter.dll
+ True
+
+
+ ..\packages\System.Xml.XmlDocument.4.3.0\lib\net46\System.Xml.XmlDocument.dll
+ True
+
+
+ ..\packages\System.Xml.XPath.4.3.0\lib\net46\System.Xml.XPath.dll
+ True
+
+
+ ..\packages\System.Xml.XPath.XDocument.4.3.0\lib\net46\System.Xml.XPath.XDocument.dll
+ True
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Source/AsyncGenerator/AsyncGenerator/Configuration/AsyncCodeConfiguration.cs b/Source/AsyncGenerator/AsyncGenerator/Configuration/AsyncCodeConfiguration.cs
new file mode 100644
index 00000000..8f87292e
--- /dev/null
+++ b/Source/AsyncGenerator/AsyncGenerator/Configuration/AsyncCodeConfiguration.cs
@@ -0,0 +1,172 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+
+namespace AsyncGenerator.Configuration
+{
+ public interface ITransformPlugin
+ {
+ void Configure(Project project, ProjectTransformConfiguration configuration);
+ }
+
+ public interface IAnalyzePlugin
+ {
+ void Configure(Project project, ProjectAnalyzeConfiguration configuration);
+ }
+
+ public interface IProjectConfiguration
+ {
+ IProjectConfiguration ConfigureAnalyzation(Action action);
+
+ IProjectConfiguration ConfigureTransformation(Action action);
+
+ IProjectConfiguration ConfigureCompilation(string outputPath, Action action);
+ }
+
+ public class ProjectConfiguration : IProjectConfiguration
+ {
+ public ProjectConfiguration(string name)
+ {
+ Name = name;
+ AnalyzeConfiguration = new ProjectAnalyzeConfiguration();
+ TransformConfiguration = new ProjectTransformConfiguration();
+ }
+
+ public string Name { get; }
+
+ public ProjectAnalyzeConfiguration AnalyzeConfiguration { get; }
+
+ public ProjectTransformConfiguration TransformConfiguration { get; }
+
+ public ProjectCompileConfiguration CompileConfiguration { get; private set; }
+
+ public IProjectConfiguration ConfigureAnalyzation(Action action)
+ {
+ if (action == null)
+ {
+ throw new ArgumentNullException(nameof(action));
+ }
+ action(AnalyzeConfiguration);
+ return this;
+ }
+
+ public IProjectConfiguration ConfigureTransformation(Action action)
+ {
+ if (action == null)
+ {
+ throw new ArgumentNullException(nameof(action));
+ }
+ action(TransformConfiguration);
+ return this;
+ }
+
+ public IProjectConfiguration ConfigureCompilation(string outputPath, Action action)
+ {
+ if (action == null)
+ {
+ throw new ArgumentNullException(nameof(action));
+ }
+ if (action == null)
+ {
+ throw new ArgumentNullException(nameof(action));
+ }
+ CompileConfiguration = new ProjectCompileConfiguration(outputPath);
+ action(CompileConfiguration);
+ return this;
+ }
+ }
+
+ public interface ISolutionConfiguration
+ {
+ ISolutionConfiguration ConfigureProject(string projectName, Action action);
+
+ ///
+ /// Set if changes to projects and documents should be applied at the end of the transformation process
+ ///
+ ISolutionConfiguration ApplyChanges(bool value);
+ }
+
+ public class SolutionConfiguration : ISolutionConfiguration
+ {
+ public SolutionConfiguration(string path)
+ {
+ Path = path;
+ }
+
+ public List ProjectConfigurations { get; } = new List();
+
+ public string Path { get; }
+
+ public bool ApplyChanges { get; private set; }
+
+ public ISolutionConfiguration ConfigureProject(string projectName, Action action)
+ {
+ if (projectName == null)
+ {
+ throw new ArgumentNullException(nameof(projectName));
+ }
+ if (action == null)
+ {
+ throw new ArgumentNullException(nameof(action));
+ }
+ var projectConfig = new ProjectConfiguration(projectName);
+ ProjectConfigurations.Add(projectConfig);
+ action(projectConfig);
+ return this;
+ }
+
+ ISolutionConfiguration ISolutionConfiguration.ApplyChanges(bool value)
+ {
+ ApplyChanges = value;
+ return this;
+ }
+ }
+
+
+ public interface IAsyncCodeConfiguration
+ {
+ IAsyncCodeConfiguration ConfigureSolution(string solutionFilePath, Action action);
+
+ AsyncCodeConfiguration Build();
+ }
+
+ public class AsyncCodeConfiguration : IAsyncCodeConfiguration
+ {
+ public static IAsyncCodeConfiguration Create()
+ {
+ return new AsyncCodeConfiguration();
+ }
+
+ public List SolutionConfigurations { get; } = new List();
+
+ public IAsyncCodeConfiguration ConfigureSolution(string solutionFilePath, Action action)
+ {
+ if (solutionFilePath == null)
+ {
+ throw new ArgumentNullException(nameof(solutionFilePath));
+ }
+ if (action == null)
+ {
+ throw new ArgumentNullException(nameof(action));
+ }
+ if (!File.Exists(solutionFilePath))
+ {
+ throw new FileNotFoundException($"Solution not found. Path:'{solutionFilePath}'");
+ }
+ var solutionConfig = new SolutionConfiguration(solutionFilePath);
+ SolutionConfigurations.Add(solutionConfig);
+ action(solutionConfig);
+ return this;
+ }
+
+ public AsyncCodeConfiguration Build()
+ {
+ return this;
+ }
+ }
+}
diff --git a/Source/AsyncGenerator/AsyncGenerator/Configuration/IProjectAnalyzeConfiguration.cs b/Source/AsyncGenerator/AsyncGenerator/Configuration/IProjectAnalyzeConfiguration.cs
new file mode 100644
index 00000000..7ae659e6
--- /dev/null
+++ b/Source/AsyncGenerator/AsyncGenerator/Configuration/IProjectAnalyzeConfiguration.cs
@@ -0,0 +1,59 @@
+using System;
+using Microsoft.CodeAnalysis;
+
+namespace AsyncGenerator.Configuration
+{
+ public interface IProjectAnalyzeConfiguration
+ {
+ ///
+ /// Set a function that will decide what type of conversion to apply for a given method
+ ///
+ IProjectAnalyzeConfiguration MethodConversionFunction(Func func);
+
+ ///
+ /// Set a function that will decide what type of conversion to apply for a given type
+ ///
+ IProjectAnalyzeConfiguration TypeConversionFunction(Func func);
+
+ ///
+ /// Set a predicate that will decide if the document will be analyzed
+ ///
+ IProjectAnalyzeConfiguration DocumentSelectionPredicate(Predicate predicate);
+
+ ///
+ /// Set a predicate that will decide if the method will be analyzed
+ ///
+ IProjectAnalyzeConfiguration MethodSelectionPredicate(Predicate predicate);
+
+ ///
+ /// Set a predicate that will decide if the type will be analyzed
+ ///
+ IProjectAnalyzeConfiguration TypeSelectionPredicate(Predicate predicate);
+
+ ///
+ /// Set a predicate that will decide if the method that can be converted to async should be converted
+ ///
+ IProjectAnalyzeConfiguration ConvertMethodPredicate(Predicate predicate);
+
+ ///
+ /// Append a function that will try to find an async counterpart for the given method
+ ///
+ IProjectAnalyzeConfiguration AppendFindAsyncCounterpartDelegate(FindAsyncCounterpart func);
+
+ ///
+ /// Prepend a function that will try to find an async counterpart for the given method
+ ///
+ IProjectAnalyzeConfiguration PrependFindAsyncCounterpartDelegate(FindAsyncCounterpart func);
+
+ ///
+ /// Enable or disable scanning for async counterparts within a method body
+ ///
+ IProjectAnalyzeConfiguration ScanMethodBody(bool value);
+
+ ///
+ /// Enable or disable scanning for missing async counterparts
+ ///
+ IProjectAnalyzeConfiguration ScanForMissingAsyncMembers(bool value);
+
+ }
+}
diff --git a/Source/AsyncGenerator/AsyncGenerator/Configuration/IProjectCompileConfiguration.cs b/Source/AsyncGenerator/AsyncGenerator/Configuration/IProjectCompileConfiguration.cs
new file mode 100644
index 00000000..b6607c46
--- /dev/null
+++ b/Source/AsyncGenerator/AsyncGenerator/Configuration/IProjectCompileConfiguration.cs
@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace AsyncGenerator.Configuration
+{
+ public interface IProjectCompileConfiguration
+ {
+ ///
+ /// Set the path where the symbols will be placed
+ ///
+ IProjectCompileConfiguration SymbolsPath(string path);
+
+ ///
+ /// Set the path where the xml documentation will be placed
+ ///
+ IProjectCompileConfiguration XmlDocumentationPath(string path);
+ }
+}
diff --git a/Source/AsyncGenerator/AsyncGenerator/Configuration/IProjectTransformConfiguration.cs b/Source/AsyncGenerator/AsyncGenerator/Configuration/IProjectTransformConfiguration.cs
new file mode 100644
index 00000000..767dede3
--- /dev/null
+++ b/Source/AsyncGenerator/AsyncGenerator/Configuration/IProjectTransformConfiguration.cs
@@ -0,0 +1,45 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+
+namespace AsyncGenerator.Configuration
+{
+ public interface IProjectTransformConfiguration
+ {
+ ///
+ /// Set the name of the folder where all newly generated files will be stored
+ ///
+ IProjectTransformConfiguration AsyncFolder(string folderName);
+
+ ///
+ /// Set a function that can return a number of namespaces to import in a given document
+ ///
+ IProjectTransformConfiguration AdditionalDocumentNamespacesFunction(Func> func);
+
+ ///
+ /// Add a assembly reference to the project
+ ///
+ IProjectTransformConfiguration AddAssemblyReference(string assemblyPath);
+
+ ///
+ /// Set the parse options of the project
+ ///
+ IProjectTransformConfiguration ParseOptions(ParseOptions parseOptions);
+
+ ///
+ /// Wraps all generated code within the provided directive
+ ///
+ IProjectTransformConfiguration DirectiveForGeneratedCode(string directiveName);
+
+ ///
+ /// Indent all generated code using the provided indentation
+ ///
+ IProjectTransformConfiguration IndentationForGeneratedCode(string indentation);
+
+
+ }
+}
diff --git a/Source/AsyncGenerator/AsyncGenerator/Configuration/ProjectAnalyzeConfiguration.cs b/Source/AsyncGenerator/AsyncGenerator/Configuration/ProjectAnalyzeConfiguration.cs
new file mode 100644
index 00000000..e32ab6a7
--- /dev/null
+++ b/Source/AsyncGenerator/AsyncGenerator/Configuration/ProjectAnalyzeConfiguration.cs
@@ -0,0 +1,125 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis;
+
+namespace AsyncGenerator.Configuration
+{
+ public delegate Task FindAsyncCounterpart(Project project, IMethodSymbol syncMethodSymbol, bool searchInheritedTypes);
+
+ public class ProjectAnalyzeConfiguration : IProjectAnalyzeConfiguration
+ {
+ public Func MethodConversionFunction { get; private set; } = m => MethodConversion.None;
+
+ public Func TypeConversionFunction { get; private set; } = m => TypeConversion.Unknown;
+
+ public Predicate DocumentSelectionPredicate { get; private set; } = m => true;
+
+ public Predicate MethodSelectionPredicate { get; private set; } = m => true;
+
+ public Predicate TypeSelectionPredicate { get; private set; } = m => true;
+
+ public Predicate ConvertMethodPredicate { get; private set; } = m => true;
+
+ public List FindAsyncCounterpartDelegates { get; } = new List();
+
+ public bool ScanMethodBody { get; private set; }
+
+ public bool ScanForMissingAsyncMembers { get; private set; }
+
+ IProjectAnalyzeConfiguration IProjectAnalyzeConfiguration.MethodConversionFunction(Func func)
+ {
+ if (func == null)
+ {
+ throw new ArgumentNullException(nameof(func));
+ }
+ MethodConversionFunction = func;
+ return this;
+ }
+
+ IProjectAnalyzeConfiguration IProjectAnalyzeConfiguration.TypeConversionFunction(Func func)
+ {
+ if (func == null)
+ {
+ throw new ArgumentNullException(nameof(func));
+ }
+ TypeConversionFunction = func;
+ return this;
+ }
+
+ IProjectAnalyzeConfiguration IProjectAnalyzeConfiguration.DocumentSelectionPredicate(Predicate predicate)
+ {
+ if (predicate == null)
+ {
+ throw new ArgumentNullException(nameof(predicate));
+ }
+ DocumentSelectionPredicate = predicate;
+ return this;
+ }
+
+ IProjectAnalyzeConfiguration IProjectAnalyzeConfiguration.MethodSelectionPredicate(Predicate predicate)
+ {
+ if (predicate == null)
+ {
+ throw new ArgumentNullException(nameof(predicate));
+ }
+ MethodSelectionPredicate = predicate;
+ return this;
+ }
+
+ IProjectAnalyzeConfiguration IProjectAnalyzeConfiguration.TypeSelectionPredicate(Predicate predicate)
+ {
+ if (predicate == null)
+ {
+ throw new ArgumentNullException(nameof(predicate));
+ }
+ TypeSelectionPredicate = predicate;
+ return this;
+ }
+
+ IProjectAnalyzeConfiguration IProjectAnalyzeConfiguration.ConvertMethodPredicate(Predicate predicate)
+ {
+ if (predicate == null)
+ {
+ throw new ArgumentNullException(nameof(predicate));
+ }
+ ConvertMethodPredicate = predicate;
+ return this;
+ }
+
+ IProjectAnalyzeConfiguration IProjectAnalyzeConfiguration.AppendFindAsyncCounterpartDelegate(FindAsyncCounterpart func)
+ {
+ if (func == null)
+ {
+ throw new ArgumentNullException(nameof(func));
+ }
+ FindAsyncCounterpartDelegates.Add(func);
+ return this;
+ }
+
+ IProjectAnalyzeConfiguration IProjectAnalyzeConfiguration.PrependFindAsyncCounterpartDelegate(FindAsyncCounterpart func)
+ {
+ if (func == null)
+ {
+ throw new ArgumentNullException(nameof(func));
+ }
+ FindAsyncCounterpartDelegates.Insert(0, func);
+ return this;
+ }
+
+ IProjectAnalyzeConfiguration IProjectAnalyzeConfiguration.ScanMethodBody(bool value)
+ {
+ ScanMethodBody = value;
+ return this;
+ }
+
+ IProjectAnalyzeConfiguration IProjectAnalyzeConfiguration.ScanForMissingAsyncMembers(bool value)
+ {
+ ScanForMissingAsyncMembers = value;
+ return this;
+ }
+
+ }
+}
diff --git a/Source/AsyncGenerator/AsyncGenerator/Configuration/ProjectCompileConfiguration.cs b/Source/AsyncGenerator/AsyncGenerator/Configuration/ProjectCompileConfiguration.cs
new file mode 100644
index 00000000..f18e9147
--- /dev/null
+++ b/Source/AsyncGenerator/AsyncGenerator/Configuration/ProjectCompileConfiguration.cs
@@ -0,0 +1,42 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace AsyncGenerator.Configuration
+{
+ public class ProjectCompileConfiguration : IProjectCompileConfiguration
+ {
+ public ProjectCompileConfiguration(string outputPath)
+ {
+ OutputPath = outputPath;
+ }
+
+ public string OutputPath { get; }
+
+ public string SymbolsPath { get; private set; }
+
+ public string XmlDocumentationPath { get; private set; }
+
+ IProjectCompileConfiguration IProjectCompileConfiguration.SymbolsPath(string path)
+ {
+ if (path == null)
+ {
+ throw new ArgumentNullException(nameof(path));
+ }
+ SymbolsPath = path;
+ return this;
+ }
+
+ IProjectCompileConfiguration IProjectCompileConfiguration.XmlDocumentationPath(string path)
+ {
+ if (path == null)
+ {
+ throw new ArgumentNullException(nameof(path));
+ }
+ XmlDocumentationPath = path;
+ return this;
+ }
+ }
+}
diff --git a/Source/AsyncGenerator/AsyncGenerator/Configuration/ProjectTransformConfiguration.cs b/Source/AsyncGenerator/AsyncGenerator/Configuration/ProjectTransformConfiguration.cs
new file mode 100644
index 00000000..1c5b1c16
--- /dev/null
+++ b/Source/AsyncGenerator/AsyncGenerator/Configuration/ProjectTransformConfiguration.cs
@@ -0,0 +1,91 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+
+namespace AsyncGenerator.Configuration
+{
+ public class ProjectTransformConfiguration : IProjectTransformConfiguration
+ {
+ public string AsyncFolder { get; private set; } = "Async";
+
+ public Func> AdditionalDocumentNamespacesFunction { get; private set; }
+
+ public HashSet AssemblyReferences { get; } = new HashSet();
+
+ public ParseOptions ParseOptions { get; private set; }
+
+ public string DirectiveForGeneratedCode { get; private set; }
+
+ public string IndentationForGeneratedCode { get; private set; }
+
+ IProjectTransformConfiguration IProjectTransformConfiguration.AsyncFolder(string folderName)
+ {
+ if (folderName == null)
+ {
+ throw new ArgumentNullException(nameof(folderName));
+ }
+ AsyncFolder = folderName;
+ return this;
+ }
+
+ IProjectTransformConfiguration IProjectTransformConfiguration.AdditionalDocumentNamespacesFunction(
+ Func> func)
+ {
+ if (func == null)
+ {
+ throw new ArgumentNullException(nameof(func));
+ }
+ AdditionalDocumentNamespacesFunction = func;
+ return this;
+ }
+
+ IProjectTransformConfiguration IProjectTransformConfiguration.AddAssemblyReference(string assemblyPath)
+ {
+ if (assemblyPath == null)
+ {
+ throw new ArgumentNullException(nameof(assemblyPath));
+ }
+ if (!File.Exists(assemblyPath))
+ {
+ throw new FileNotFoundException(assemblyPath);
+ }
+ AssemblyReferences.Add(assemblyPath);
+ return this;
+ }
+
+ IProjectTransformConfiguration IProjectTransformConfiguration.ParseOptions(ParseOptions parseOptions)
+ {
+ if (parseOptions == null)
+ {
+ throw new ArgumentNullException(nameof(parseOptions));
+ }
+ ParseOptions = parseOptions;
+ return this;
+ }
+
+ IProjectTransformConfiguration IProjectTransformConfiguration.DirectiveForGeneratedCode(string directiveName)
+ {
+ if (directiveName == null)
+ {
+ throw new ArgumentNullException(nameof(directiveName));
+ }
+ DirectiveForGeneratedCode = directiveName;
+ return this;
+ }
+
+ IProjectTransformConfiguration IProjectTransformConfiguration.IndentationForGeneratedCode(string indentation)
+ {
+ if (indentation == null)
+ {
+ throw new ArgumentNullException(nameof(indentation));
+ }
+ IndentationForGeneratedCode = indentation;
+ return this;
+ }
+ }
+}
diff --git a/Source/AsyncGenerator/AsyncGenerator/Internal/AsyncLock.cs b/Source/AsyncGenerator/AsyncGenerator/Internal/AsyncLock.cs
new file mode 100644
index 00000000..f029832b
--- /dev/null
+++ b/Source/AsyncGenerator/AsyncGenerator/Internal/AsyncLock.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace AsyncGenerator.Internal
+{
+ internal class AsyncLock
+ {
+ private readonly AsyncSemaphore _semaphore;
+ private readonly Task _releaser;
+
+ public AsyncLock()
+ {
+ _semaphore = new AsyncSemaphore(1);
+ _releaser = Task.FromResult(new Releaser(this));
+ }
+
+ public Task LockAsync()
+ {
+ var wait = _semaphore.WaitAsync();
+ return wait.IsCompleted
+ ? _releaser
+ : wait.ContinueWith(
+ (_, state) => new Releaser((AsyncLock)state),
+ this,
+ CancellationToken.None,
+ TaskContinuationOptions.ExecuteSynchronously,
+ TaskScheduler.Default);
+ }
+
+ public struct Releaser : IDisposable
+ {
+ private readonly AsyncLock _toRelease;
+
+ internal Releaser(AsyncLock toRelease)
+ {
+ _toRelease = toRelease;
+ }
+
+ public void Dispose()
+ {
+ _toRelease?._semaphore.Release();
+ }
+ }
+ }
+}
diff --git a/Source/AsyncGenerator/AsyncGenerator/Internal/AsyncSemaphore.cs b/Source/AsyncGenerator/AsyncGenerator/Internal/AsyncSemaphore.cs
new file mode 100644
index 00000000..b96c5cbe
--- /dev/null
+++ b/Source/AsyncGenerator/AsyncGenerator/Internal/AsyncSemaphore.cs
@@ -0,0 +1,49 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace AsyncGenerator.Internal
+{
+ internal class AsyncSemaphore
+ {
+ private static readonly Task Completed = Task.FromResult(true);
+ private readonly Queue> _waiters = new Queue>();
+ private int _currentCount;
+
+ public AsyncSemaphore(int initialCount)
+ {
+ if (initialCount < 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(initialCount));
+ }
+ _currentCount = initialCount;
+ }
+ public Task WaitAsync()
+ {
+ lock (_waiters)
+ {
+ if (_currentCount > 0)
+ {
+ --_currentCount;
+ return Completed;
+ }
+ var waiter = new TaskCompletionSource();
+ _waiters.Enqueue(waiter);
+ return waiter.Task;
+ }
+ }
+
+ public void Release()
+ {
+ TaskCompletionSource toRelease = null;
+ lock (_waiters)
+ {
+ if (_waiters.Count > 0)
+ toRelease = _waiters.Dequeue();
+ else
+ ++_currentCount;
+ }
+ toRelease?.SetResult(true);
+ }
+ }
+}
diff --git a/Source/AsyncGenerator/AsyncGenerator/MethodConversion.cs b/Source/AsyncGenerator/AsyncGenerator/MethodConversion.cs
new file mode 100644
index 00000000..1432b724
--- /dev/null
+++ b/Source/AsyncGenerator/AsyncGenerator/MethodConversion.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace AsyncGenerator
+{
+ public enum MethodConversion
+ {
+ ///
+ /// The method wont be changed
+ ///
+ None = 0,
+ ///
+ /// The method will be converted to async
+ ///
+ ToAsync = 1,
+ ///
+ /// The method will be converted to async only if there is at least one method within the method body that has an async counterpart
+ ///
+ Smart = 3
+ }
+}
diff --git a/Source/AsyncGenerator/AsyncGenerator/Properties/AssemblyInfo.cs b/Source/AsyncGenerator/AsyncGenerator/Properties/AssemblyInfo.cs
new file mode 100644
index 00000000..ca3bc98a
--- /dev/null
+++ b/Source/AsyncGenerator/AsyncGenerator/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("AsyncGenerator")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("AsyncGenerator")]
+[assembly: AssemblyCopyright("Copyright © 2017")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("9d321ea8-54ae-4741-86a8-12198551ad67")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/Source/AsyncGenerator/AsyncGenerator/TypeConversion.cs b/Source/AsyncGenerator/AsyncGenerator/TypeConversion.cs
new file mode 100644
index 00000000..c8b5adf8
--- /dev/null
+++ b/Source/AsyncGenerator/AsyncGenerator/TypeConversion.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace AsyncGenerator
+{
+ public enum TypeConversion
+ {
+ ///
+ /// The type conversion will be decided by the analyzer
+ ///
+ Unknown = 0,
+ ///
+ /// A partial type will be created that will contains the async counterparts
+ ///
+ Partial = 1,
+ ///
+ /// A new type will be created with an Async postfix that will contains the async counterparts
+ ///
+ NewType = 2
+ }
+}
diff --git a/Source/AsyncGenerator/AsyncGenerator/app.config b/Source/AsyncGenerator/AsyncGenerator/app.config
new file mode 100644
index 00000000..0f29e48a
--- /dev/null
+++ b/Source/AsyncGenerator/AsyncGenerator/app.config
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Source/AsyncGenerator/AsyncGenerator/packages.config b/Source/AsyncGenerator/AsyncGenerator/packages.config
new file mode 100644
index 00000000..ed89b6ff
--- /dev/null
+++ b/Source/AsyncGenerator/AsyncGenerator/packages.config
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file