From 8ae54d629c878182a87c6f71b0d337407b88845a Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sun, 1 Aug 2021 10:21:21 +0200 Subject: [PATCH 001/162] Resolving class types with parameterless constructors --- .gitattributes | 5 + .gitignore | 364 ++++++++++++++++++++++++++++++++ Directory.build.props | 46 ++++ Icon/Yeah69Logo_256.png | Bin 0 -> 13875 bytes Main/Main.csproj | 37 ++++ Main/RoslynExtensions.cs | 54 +++++ Main/SourceGenerator.cs | 94 +++++++++ Main/StaticDelegateAttribute.cs | 13 ++ MrMeeseeks.DIE.sln | 36 ++++ README.md | 83 ++++++++ Sample/AssemblyInfo.cs | 4 + Sample/Context.cs | 17 ++ Sample/Program.cs | 4 + Sample/Sample.csproj | 27 +++ 14 files changed, 784 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 Directory.build.props create mode 100644 Icon/Yeah69Logo_256.png create mode 100644 Main/Main.csproj create mode 100644 Main/RoslynExtensions.cs create mode 100644 Main/SourceGenerator.cs create mode 100644 Main/StaticDelegateAttribute.cs create mode 100644 MrMeeseeks.DIE.sln create mode 100644 README.md create mode 100644 Sample/AssemblyInfo.cs create mode 100644 Sample/Context.cs create mode 100644 Sample/Program.cs create mode 100644 Sample/Sample.csproj diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..47e8da59 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,5 @@ +# Auto detect text files and perform LF normalization +* text=auto + +# Custom for Visual Studio +*.cs diff=csharp \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..a52a9e35 --- /dev/null +++ b/.gitignore @@ -0,0 +1,364 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# 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 +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# 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/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# 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 +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +.idea/ diff --git a/Directory.build.props b/Directory.build.props new file mode 100644 index 00000000..61a4f322 --- /dev/null +++ b/Directory.build.props @@ -0,0 +1,46 @@ + + + + v + $(MinVerVersion) + true + 9 + enable + nullable + Yeah69 + Yeah69Logo_256.png + $(RootNamespace) + + + + + true + + + + + + + $(MinVerVersion) + git + LICENSE + $(AssemblyName) + $(AssemblyName) + For further information and updates please visit the projects page. + + + + + True + + + + + + + MrMeeseeks Generator Static Delegator + -/- + https://github.com/Yeah69/MrMeeseeks.StaticDelegateGenerator + https://github.com/Yeah69/MrMeeseeks.StaticDelegateGenerator + + \ No newline at end of file diff --git a/Icon/Yeah69Logo_256.png b/Icon/Yeah69Logo_256.png new file mode 100644 index 0000000000000000000000000000000000000000..428abe4ae762086fbbc670a36a583c0d3003fff1 GIT binary patch literal 13875 zcmb`uWmHye*e1N`?gj+}DN(w+LlEhb?rx>K8!TE%6d$^~yStH+?(UfDerMMD{(bXj zTnkaxzS&ov=TSx~E6HM^lcPfrge5O0r3yiC;E!++Dl+({=aO#$z9G6w$g87*Up}a2 z5#aA=PI5Y~5QJL*`+_T}Dk1{^NaiN3?WX2v;pT4aVh*{xyR%q3*t(h;JDIaMx>%+i z3Xww)H6$-3uI`b3km0Vau65h9>>8epnUPH^$4V^L8iY<0p>O(bpIwFEZ*qB>UHQ(O zUHMJk(XSq>9GO^?Xe54k>l+7Q3n64jHk z*d8`iYJ|_E5uR#yQ`iu^wwDK!3)N8^@;#Zv3g04LXbFz2izxr3#k7Q$T2i&HJoS0> zk(*(q(G0xJ{n@|7(2B0C7I%t+Fv54}wcZ!S#JX4BQZ?|X$rJ(KpXqX}tQ=u{Q$_k? zn74NJBoN;~9*K)v8SfgwsrcaW>NM)iWYM3f2>m*~$A9~f_~3_Q7W3#Kb>V@w}*BVR;2~gL7OcMG7Be%gF8_h+dO^MYJb#szMJp1L8v# zbn!y7sJ6hp@^`k9yhMKGWRNv&$k^rtTj9+j(n@xJTB2$eOci{Gjy})HR!gK*F}I1A zhMYAS@y~@^j`7r!)luc&Gpu&!$Qbm~;X=^8z~*NQ zgMqV*)o30w$1IaaGRbNr#NkrZ16oNV)!|i2q_SJqA4A7G4W64~hW21oIiM0|KtJu@c0B+1oSbQ4 zxCdJ^T|02oJ|le4Ziq`2Mf}N$Yy;l5q$tm1IaXSg^N-AKt?za<^^d?Df`H;*EPS9o&Q=FiRg*@;LV8xOZ9+OPB7-~-qDJsg zq133g92)K~5}miGT&q+B33a)3-MiK$*5S0aaVz(o zK5ahbXlr6L-&%k2GGwDYCAZEM^5TL!vbvvU>D*QZFMgMvkF+Avz1fXh&4c;Q!xO&T ziF~o@^P3bw4(GKnsX{v~n?md$kFtyEP|t-e6-ojjE=^hcPjAxw?}Ucul4v82o~Xvq z;A-Q+_+y^#JP2=mUViT9awVNeScXuvp8aH2W#&>95f7mb7~7N0y^dewo-QGeCSM(7 zwsaacaK^m9+x`kI_Vf>-!xp%WIhea#RP7?4`liav=cFS#=T;l>k-dU5*mGg?#nW7> zbH{KC?QiJ?$Z-=e2n8Z4V1nO8sRSc7>d_# zwWa1Tt5%!rG~&_6o8>#U9zC($dE8D7L=3kpp+yEGB`Ecz3)Aetc*uM1&BmM3r^E-h zn+=zx0eV!~Yl2m)?k&!QPVIK@xx6if)mgQk?RmRZ+DFVV#-RX3>t4rz^P!#D-cD3K z*@jauFIyXXbTEy?@^?(VzV`4f$=WHc?HL$jAtX1V8;%7w!KM^(s{|vNt-QnA2AZZLUWbW@mW%V@lMR!U?5L}>!)8z z)EC3|-BFrICFZu|O$4A^i$SY!)pf8td1Kt6is{x+c@TF_~q`Fk_y%s9!i(%2Lh#K zb?hZ})I=Y6ysHV)J*ExiCQN)L0+u-jHtaGFf ztRJ*LS`clJ9|~N@PyNhmM8e->SeYzQD=Qwk#mSkmgdSEo`jIw|(%Aqwu#w#v8-&Tzp5u}}KsDNFMru*ugXp}6h{~XlY+*g;!c&isz>{k!@=Lm$q zpOWUGS-uSNx>mdpFBmRdvp>H2bk!cYrL^*(aJ9Fwg2I;drj;t&+q%~Gnx|5uGSIz| z_p@A`cSwq0YDZ~Thw^Hfgi3?|F6|3u$*y=u zqHAUvzT*$K678(W#xE0r7p}Z`u{7vYgY&mLt;ga!PZ$W0ZUh9h=<=8x1_U(fscT z<#XGy#@XvVmpvoz#ZUF8UUXDlJA`H!qbU5|uE#h8{wrO}hBow}vVMMup5Vyo5wB9J zEoBCE3-iV$wPpHqQ8`8~O7IesTWm7YKo82k739@13ldttoHL1jaxlFXtdAilA9})) zmZaUxWVdRMCh#D;pAl&Za~G}ru;p-kf`%6WXI0`5ZvUlv3@LJvw&tz5sWErOrTwsu63dt z=&NIemc5Uc1{JE`^Z4qO*Xqh?@HMEwSl;VT=y(u!mIl{L2f5C^5<1hEx(f<53N={G zH{Y`DQQJGu9F>(Et9(-WCv@GAT5lwKk1eqG`!&b4e<&)1Fx=uzNwwej$)SRy@MPQy(us#jKP7>HKe(+LZ^YAF$w5|T(Qo@YX~o{{ik?ignpW~YI#h<_RuoH zZ|P;jWE)8J&;RGbtA%Tu?@JPh0Vt<_!yPE!DOcRsF*8ko&6+T z0RKs8L4M}%8bfJxwpcO3nc~L9TedO|IMC~-X=g=RDKFg4#ct>x-pjp}XVms`W7^;v zkNim16lE|gY{}c~9lGvdhOPr=74U^My)#9y7U_HP{h=9`*&=Rp>Py|6

!)2YHj2 z)$RJ+TE4pE+N<&a)ByTcD17Ewch~PZ_qPBEVSHj4-8&1&R*`(MJH@EvouTG08p`Q6 zNFAI>Ck1hZy!{gtB8`?j@MCg%f!M;opf*KG8D`N-) z*iIZc!`CLr=1_bQ0hR zu)?|W42jc!-^b=*?{+d9!W)!LmuVM{fUKeo-ymFgUKBK))C#A`v=%9p zetj{Zu9$Oki~+`wv#;FV9DX$>tS?;ngSU($aBg|`mqu&*9Q-f8L6KjEFgWCOLP&Nm zB#9_CFljc`x|5_-aoF2D;j7ZykDEadsAD)JVe!eL@P`H{5JziGg`rLooF#w^PZglIzn$vc*L~C=;TLjJN9-yxzl=2YMY7%k_dpq7WE^oz|u56w89>9 zJpMwgFd_F7KlyRaZQ6clDI?a=p-KMxBY6;NfS4PPTl?5YSsnL%c8VUSxYS&%Zo6l} z&w`$53ojV_#qRkbAcNe3`~seu8c80B&z7M<%|5a$WFkA2hYcXD{F&LiTPp8e(nFj5 zwF>zVQ87d@qc~CTXEigG6<*Vh->FVB4w-fFBD`7SF4_zaoArG5THkQo*^<&g@Dp>R zXnH{rFvhXwk}adg7v~hBVk=XI&rp06k|naX$B!%rK9TOu7OxTRPPz%veviZb`-&Ry zh3R&;Q%44!k|@+cYItgV*c-3h$}3!DTkziew@wq+@jS3-uH@c@KjH3SUQ(#3yVaV> zF>rv&&|>Oj!_S4Z&h4j_CLFtCPid5Ogf%9^4`FcxvPa!u)PM*%PgW$}q;d?)H{Ue^ z0M_8i{X%MFz{mO2}T@05cRF++DAYUSeS*D5_K)l^knLe z|I$>EJ@z_<;GUfBzvgRD}ObcB_O9Cz&E<5N3+0o zqMU4=0%8|@7bp8qMWgTT2qGj_1pkuU44opRW%G_q~pk#5~xD-UI8O+RO=#3&(|Ma%vSAA7M4Mi$tugjOVWQG-2PL-=jv3yRlB8q zOK#}r3hxAtXODOA8Kb4ymL0bbO?W%|?=wM84P5%RX=yW$~k1r)9nGis&+u1vb z+CCkUT{aRcUA< z0VW}X2!a`gweP3Ilpic>!H3x*Byg{e_y}(#UKTWZ`iB72zkbG0#qoJG+6IntBbaE@(Dhsc_H$EWbo z@l)v5aN&VSqy5o~XoIIawkACkzz#N-8@WlJ-(;PnxEe{+@LA#jw!}(khFQJT`K?fk zAwd`fRw$M62Z^G+qVWbRGgA*>0{y&y$?^7%?O*DJ4V}C?hQL zHaEp9*C1AcmXhp+HqT01a)UXG3;E8^vQs)$wAb?u5#?uP6WY&jL3hD2Ixxmk6G_iG z35>)IN--Rf;;2)c&|s(ckY+f(&*aU%qlOo7|ySC@;^; zMwj_{tb=E-OgsgxxL-y<$AkIYxwtu%3wW`LG1TWL%46q`r5}xT9ixG6gBkfO=fLJ8 zCBPyCmC6kjEu$BYc%ZhV2XVU}^Wt_8;}CQSj?#gj5>b@&X4V6}g3uk+1yUeU5a0E~ z9U=8g_jN0B&<8*1{F&v7KZwx)Fa|S!V-k+2#5~wzod_` z-B7`E00g|TdWa$p%>oZIE_@A&6Ju{g&<_GH=OV%IX38teR~fy9gF<2!b5;M#s>;#$ zKQB=AtTwj z4k{=TLH6f${5B-z8ESEH&&}!P584p}{B_>0b07T>R|Ka>ZbmLp0O3=<$j<^FEcfs4 z{#dh1N;0E2j!880sugGh1)EMU7+!>{{Nb2wK7YJivAOb4)h?&tp1{w@etsoO~#XV1h7n9K%LMLkc;y5en9fE}F2 zuezUPTQ5g zTG@*cXE3(kMBYe2+Mrt_RBF|91e&9;6^-vlauwyQj_yj<7L-Mgx&HVf)MlC!KHn1W z^8#N!CdJ;`fvPT6twnL_I?JxWE|_*NE}?A%p9Uh&IhJ}Mawl+>l7iOKc#Od!_sU2w z{7BJa%+<_=tU$7fz+X5JBc8-&|M|Jwg;;wKV(RSU9JnLFKN~ZHSbg0huiygM!!Vwj z14{fpebbn;W7!9q9h=Bxt_IgLZ9gdK2kXYebH;f>SQXJr)NOMgLq-Bu(sega?Yi|8 zA?E$~U2aVS33ic42#`B0g!5w*lPUaT6z9ld>eCuld#T^6hS&fLCdz(AnZ22R z;mY8eK&l{?r!MaO@viB7h2$^~g`|Uys#%#y!)c>M3#M$D#G_HJaCc$U#ePDteQ#@a zXoMXAc?o!B<=xMmuk_I=do<#@bF){t;Z6d4BgVDPD<`?g>s5!!?$60`t+VZ< zUJc&jbHyRUw@Qm{ztMD$K4Ws+Mt~nJnHxqEZ-sN5yd4Mx<0-G<@vhTHf05*K#HuCx zP{H4aE9rmvL0iP@u6zt*p45RWbt?-AsDta}oF)*;5gJ9Hs$j*10?PH#xOKRd{mPyt zWv~W=b^`-MO2KINfsjzQcWXo*t@27xYg@ChXTQle7 zCEMR2>VN=#I7Sm+M346uGG9aH@WRSM*=uF%gS~$Wl0UV3Y#$s-yZhAzyIyTd96stT zPV~LMqztlf!u}YRI3SZ_jDsV|BboA>*EBfxH&$meMRd1_AaTas7JvGqzJTUMex+&+ z&nOw(applh{gW++3--s&B1Kv?+T+ZB@%LNT9p@vzazVYizMYxDvcX~e#7K)C_U2hw z_k;a2lP_6cSqGmF83QG6EWavu^pWmvC+r@%ZN8l$hXlf~#E5ueqeLn}wMb9@j0TpU z?J}jzYH-37ra<{z4pr206sdmEz(;PKoF{Cb4$B^UA3r^BSAxxwt7r80;-mW7tyFpy zv%(e*iqsnjsO_Uc`WOj{EEBpJs4tGwHo|=@Z*v-hJ+CLDf1khNjGtxa;SKBEqE%VP zNCbMN)b{3iBv6lE&(=XY^}0dy<)XF(W9Y3RE$_w3j=DIOw$6|wP=kmOU$p4>ZSVS* ztYIAKjSfgsmw^-2#vG&qRQBHSZ_ARx@9>_Cg+8asuP(L>?-Zg&s6r;okb4(6t@%XE{0v-f;F;bgqItX_mJ^ z963hamYk!f1OtiSvap&*!3k0cM)>J3e$g_Fkbq!P*L+0;2M5tcqEsezh!NP)(SAeC zr2*R#$;z))Z2rG0L(eE@I>!;e-!~%0dV0kup$e;Yi*OS6J*-Rc2IJ+BIujVA20RPn zNBxVbiJ8GgD4h6+IM3;bQ^f3tAk7d(eR?BT<-ZJUH}{gI4fWrkRleqL3~@mnUve)V zDG2YMe5>bQK$&{T1xlTuW;JuR)))r0Ri{9=DSGL=l7%Z{uJNj( zCAVbD0!|9&R4v=;c*TkZ>US%<^OiGCj_#~`xBCbO#us%{U+Z!$wBBMNVJUkQ;)4DY z3P{bO$^!c=Esh`aKG!%JjbVfoI8k^xvmg6fJp+4z^uhbr+T^0KTHLYiLy!Q^2ynwf zi!lDZgusMDCs|dUAIE$a|1LiKZlOgF>|jGV27XQuF>>IYlzZ$o$>=NcOVM(wt-}$b zCR9E|{#H|_c$Husu6~y9ZI`nLTnn5KsD}*WKeE75XbX#y77-OCq$NaG0Hi|nhp6%E z4j>uChX!&w4Hbg9wdbpJ_XE)_5zROd>T3vF9J^G+Raly=j3P!qRzIPV9nJEgbC7Pr zCW0tLlq?S1)ED4xYks_vbywi^A-ksgYw&m2wl1~R`X|Bb#ioQ^$GdM0y#HI_LYRz@ zmB|WiAUSPbWfjqnVfA+*LkHb`y}lTnEg`QKkgJsZo0EdfFf3fKfUtV9l)WmHqXk0$3DZUnaF)lobCPu2*tGcU~Jhm;@9D zRP^kZbs&!LZ6XeRCd+q9 z1HH;aFaKn=no0FQW_Wvy4-UqoAKnOU6fx4*A8)!|#D}p}pUau6GPY=A$A+%CzaX(g zqW&hodb7L5#Dh?hSBM1Dy8&18u#N^Mg`$r+P1OB|munsPDv7#qFm>G1Ds{Nxa$dLJ zo~!1A52M)QfjH5FE?4S(NnZ@oJ}CN5y>3y*UXFkIvDDyEGL0e%wQj_- z{<|dKT;R{#5fL!nB2C zuEB#_C0cIN+jRnQ#8%%%!GD(O!mn!UVsBJqFo0yrcR9)KV|IX7cxdebyqw`X{`Zsr zm1wZF0(|VG@9;N36b4AaYAP)zMC=$`ZvBRt#K|?L$ZqRpE)_xFS_*$AcRptn{?LD& zCJ;yXge42!V_!(|Z(}m!i~Hos{y6H+hw&32mj};Z7K|4d0e#QwxlAe+j3LvxU}RJ? z6}^8^)U1QGU{XD%CEC)z(-m5XDgI?y<*3uZf;IRWXKm^*oSTe0X2EpNmiabVtSA#s zE{3kv!Z4$ORSTg=B@+~?Yx-*nfx{*~E|;6$DTiavuP;Fyx_$c zI7+~b@p$+?oIPCX@nrIn-D0zpHt}sM_aYGy1CF1}nCf)U>J^$4aww`8m3F-@hv?w&}_j=Ao4Rw+WctWEa5`FvLKEs9`lRFKe1jTWpjSyDWrjs-_Y_a+Hujr zS|kgyYjvfjaVKMPw^Nm!R0e`QS$7*KZK~HV`jKa)0i_*e)Wg#f>H;vsu$knj%PglP z+J009;2v!E0BkE`ksSLEqE|AvW4VeDK90Q9f`$jD>T_k1C;Wr>{^!BpnyR0gKc)BA zJzjjQ8ft)AZ8~~*iUX=gZ^;5u-ke3$OQbxZu62OoS}4#I_4&>fqe&x8A7g82T0+R* zIo|&O14^54DJFS~dK(BzW}!euRQcH|&smK|b=&(2|D2SiIWhdrT%G+7P!V|4_iLxr z70nU;br)!azCDs!RV?(ynEcJDjDPyi*@w#3WrYFCFAb8Y(w{1fA0f}TSLvE-p z0i_J>qY1q)da2yb5OSbyjHBNp1Zo7un~DIBiDl7FKqNh2!*nFjRU*oiB` zT@-JYYDmkf&X!RoNMYhLNyclF3;Vg`v#$qlmrj|i(2G96dCjLRf2+Azt=?}KIe$`= z1(BKAqjyrY1hmPwed=6y3v)qqbaeOe2^ue~bk;ZygQ-mA=95D>-Ob90Kk+mpn`Az~ zA>u+jGp`PO4)`*Edc3=oF#SQ9tI5CmJ|q{oQPifcL!tN#n2Nv^+|Dk-VgGb=5Y5S& z+4jefvt{~$y4qln_0nzH-Q|xevz0zXeo8^=kNSb?!-@c{tO!+~70wp#08WuW#oK>n z`)Dn)APTWKB_9P3jLkt+Q z(OLjwsZXuX%8jct#Yytb`V-3}XFlHMKa287SuK`Igi-J#~;= z3FQ@NrnSf!z-5P_f8oX>T#!dete1Zon}@3&EF0dOqi>P)(O0?}BECVD08yC(-V9=K;l-YYj{3@v>aCJ+ zjfH>Mx}8pMzFfC^lXy_Mfz}YSkiV-^rn>{?hL~0KA6A^G?=w@O>zaPi&+#{?$f?y# zSXu^K44DD2`p{JWo&17NG+ZMrMCw)Gth?#h?pXo<-MMJ*(2?WXK&Dl9VDvkaiQ7i6 zF+n&u)MV22ZXDj@#46ciF%k|AceAx7oTCjo(un_Lkwk|cBa4TMHw;K2(hsCCLusr$ zcfjL4+kYi|;Q}40%(nTU)p@vAqU#cd6bjFppFPLCqxS9|nKYk?^t-{Kc5)frrI<=6 z6GkW?e3cc$6v7@>9mT^aq!|$}>dMMbmsxiC_4(W0M<$8}!2ST4W38xJG=!nCY(RYT z-xjRp$~AQW5R_vWFLPEs^pCLBv{ax_xDcj8U6pstgwocvq^tP%&3{8OXEJZB33Wv5 z!#t-ha{sV;&itF*imBPa-IaGgxf)?)fd?l{lp~!4kFAP5bZ&WA#=zMi;oR-B(ds}~ z1PG3C0V@=5=I(A6x0V{WF5bPTrQ3Er_RwOJrOB>60wYjdpb@yy#>?Zr*WPu+lu!+Qk7O$H2s|2Uw9itDAHy5b0=BV zJfmO!UHFTU@i7CJ&E4sXxvW0Q%h!sn{X7>#ixMWs@DQZz-$3bb&=M-l;7!xa`ZS9& zpBsUN*K1!%F}XD*=}mN|cV^Pv*^ekwLKRC)_c{kK?z2}pcCcI$I1I}EX`+HY8eT-_ zpDuzd3oTm;x?on*Z}6(ZP}s#C(Bd6o+ji_2jd5-@_zdNA!AF>egg{)kwGdJ?t-bFvPrujY@MHV* zQ>&0f7x)YR97h2srQ-LK+6z)BR>p->4#rcE$s#ix6axak?Z@hwO3Aq!4!uv=m~UCX zu7MMjrIFevW@l!C2=L4bPd66Gl^~Yzv6`9W{iTQp4zUwJkoEf}%S)~WBPGAWWU$Qj z4&$r^wNc=?5hI}d$h>HfloUd_89FCehfm1SfYaE~sD04_M}A74B~k)oz^j+LpQ?i2 zr_QAWf>U35RwW6Np0hU#f&Wlt*PrcT`gAUt27>~XB+?i%(&9^rL&)wm+iq-i(%coZ z>^om$eZ75~D+S#K0<9Wm5rHIKVsd%&e_raNQ=>>3SQ-BPMz$u_@W5sUf*XPU_tf%e z^MrHt&$=idzlH?GB2kbrAj6V@@AX8pL+6zupPL|?$xX$+l6zu#u3)a}6zMd!Eni!& z{MlQ_7Le?=@u^eyC*b)21|`jX4OkO32sVg3E;=t76#d{QG{vO4lzktZ6!gP2$6!SI%d%XzPhHO@)lko6 z;AM=3+ZLN8qHeuIu`LK|pqYo`v-tX;8Q!gtV}tajbPHZ=;UX8oy~KY0*H^tj<|SFG z3%EJ&K>^iAwe6bhw-H0u%dg#o`Srk1{IR2PE;0X$D;;!#@DdE!L{=%A*XrM9w{7-= zC_Xr>FlQRH>9yD5NP%z%X6t@;OJXD*XxXC%lGyN1z;VGE10@Ntfv6H+Pb}{)uk2%n zju#+7n>Ay`Ep4t#_tWuh4=jZF-Vz7c{HW<95&J&-S-|}+!ShO0NXu@hOLML^00f@~ z@&%HAhY@*4hMM~^_=2S)!iz8@b1A7pYd7mjQmgxUdjFAGKWJ4{+Ro6Kc{E5Tn!biMl{VL(W#NE$MB?{yVmUuyvP|#2XO!f^gh(u? zApzm=l`d^zI0AcutJ8rW_`KbDScJ9axAa57i5x=+rh*`u*UtkF4Vq!I>mPvj^LJXY z#Rqe+5`*WOLFNDgfwHxA6TNgjOmIkyYfyPn^>8EZEpA@`Z;u*zizdMPps-dKPP!-B zX*E(p&$G#86yq(>&+qJf1{c^Fz2Eb&!l@CxLGK>f{x=;B#)*oBoG(`t5H*SJbGtDy zJK0SrMDIa;6?wSAK88>yQyY}{=aYz{3F77~jC#&0Q3C5mUj zGo88*fr>2uq@S_)yOI3{tQsp6E8V@1zrpo5B#HjK4jt9^HDR7_S{SoxO4=!9$meq0 z0O05O0uz57oU;6(KcVyK^C;n)j!*V>4w#?-f zlBK4AU@fHFX81qA#T_iMP)+M`*mUEUwO}>9cl_xcfg@&^5Stj6yRR(aYRw5Qlmy5v zBo8TWf$H+e`QXX#px#7; z9|HFS6&Sx%X9&oEb(i@i-4H7g<37l671RU0om6xNocPpJ#mSEm&^DQS$zmulr3-(= zdI}<^%%z-+$NhH>cze}T<)LXNSu{|5I9O&}%NhPzrbeYjU?_`%!AYt|nNoFV-=;z%C95M;;kIll{+8{mbeyjudpBkn=^l78r8{mK`(U zv@K-!ox=P1djY^uJ8(Y+&iqrKtrK-Mvhd#fraCPxJ2z-o!*dI_xNA>1oihaD07+Su^OyT86T;N#^cC!~gVu3_} zvuv#2Z;LJXK8&m_?RxEYwVKQv#n*G@w=m}u7BaPa7p>cxapBk? z7Jru%HEotZis%a1Z^S!@tr_HBwKj2C48*hk24ziKcv*FtBa0S)l~M|`D>8xe}N zH1nAl`BfsRg3;IyX~s+a$3x8X@Na2=e^*4U;g3Asw;&I5%hjUbK?vD@YSBLbP+H@n zr9l^;WLB}7+R-4#Fx`B<75hWZKgb0vlD>?o3ay#l0ChzRIWBVmoXQs!1OUX^jQJ`& zy!<->3l9~>3uBZLm$pF~ZCV_e8{8i>>h`zHvd&bJ1Z$bzFHm|9IrKWNEYeE`Xv1M* z5-1ROyxw5%XVUg1Sq!uSc|+Sw!;YP_iMxwCDpXe#SJEbDF7k&-tCwF~uS5oCzX$po zJaDEwOo0p>oC!$kPV4DNo}|>t&1Hw={FCMbswZJ4Q}>&Vhpo4jAX}OJB`hZ^RD9+6 zQEZIjHJaj-<`l9a&Qq!ddCzFV3wWcfT7Z71wzSmrk`^Au0N?>QWprXG7^Fm7fvB%| zpqK~*`Q*7%*Ntm&poz`0+oR}z)&nv2ThPA{x*dN}d9AO|%9*^zt7l5*zwJ~>zx;+vJgU61phmr(ejaUabk+rO^wg_qN2d;xB?74P|c|jI!dqp@+CeXVR6<40mfH3 zu601d5(2>@SVXhFqFHVG7u(uA$;|QU$8gU9eya!&wt-rkqB+yrdB+f>&xkNUe)ehD z6DBaR)?s3j(Lf=~ur;L0@ylZMb5bd?t(VBM(r9h&x^p_+>szzSiW5f+I2PPCAXjQ~ zLuYs`*J^^1r|;Q>-~9aIO-6%g5~kk|>f+WAkw3tBsB|1>1Gg{1Su!DE?qkD;`qgt$ zrGL5aDZBKsI{U)kM^Hh=%KHfW#=8t^i2zM%8rRKAT#YAGF=J$U?GQSYILzoag@Kqu z(0uR1I@{(ByVYc>irlL&HieYt4fwDq0Su^7p!eocz5_FFB~59PwfT(J;Hd68&gpv4+Ei94!IPVj*(ntRMhZdD#YQO(43iU`OWv(#<_aLSMfnV~{N>arVMnV4z D^64xk literal 0 HcmV?d00001 diff --git a/Main/Main.csproj b/Main/Main.csproj new file mode 100644 index 00000000..63d40e71 --- /dev/null +++ b/Main/Main.csproj @@ -0,0 +1,37 @@ + + + + Library + netstandard2.0 + MrMeeseeks.DIE + $(RootNamespace) + + true + + + + AllEnabledByDefault + preview + true + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + diff --git a/Main/RoslynExtensions.cs b/Main/RoslynExtensions.cs new file mode 100644 index 00000000..a68ae978 --- /dev/null +++ b/Main/RoslynExtensions.cs @@ -0,0 +1,54 @@ +using System.Linq; +using Microsoft.CodeAnalysis; + +namespace MrMeeseeks.StaticDelegateGenerator +{ + internal static class RoslynExtensions + { + + // Picked from https://github.com/YairHalberstadt/stronginject Thank you! + public static bool IsOrReferencesErrorType(this ITypeSymbol type) + { + if (!type.ContainingType?.IsOrReferencesErrorType() ?? false) + return false; + return type switch + { + IErrorTypeSymbol => true, + IArrayTypeSymbol array => array.ElementType.IsOrReferencesErrorType(), + IPointerTypeSymbol pointer => pointer.PointedAtType.IsOrReferencesErrorType(), + INamedTypeSymbol named => !named.IsUnboundGenericType && named.TypeArguments.Any(IsOrReferencesErrorType), + _ => false, + }; + } + + // Picked from https://github.com/YairHalberstadt/stronginject Thank you! + public static bool IsAccessibleInternally(this ITypeSymbol type) + { + if (type is ITypeParameterSymbol) + return true; + if (!type.ContainingType?.IsAccessibleInternally() ?? false) + return false; + return type switch + { + IArrayTypeSymbol array => array.ElementType.IsAccessibleInternally(), + IPointerTypeSymbol pointer => pointer.PointedAtType.IsAccessibleInternally(), + INamedTypeSymbol named => named.DeclaredAccessibility is Accessibility.Public or Accessibility.ProtectedOrInternal or Accessibility.Internal + && named.TypeArguments.All(IsAccessibleInternally), + _ => false, + }; + } + + // Picked from https://github.com/YairHalberstadt/stronginject Thank you! + public static string FullName(this ITypeSymbol type) => + type.ToDisplayString(new SymbolDisplayFormat( + globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Included, + typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces, + genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters, + parameterOptions: SymbolDisplayParameterOptions.IncludeType | SymbolDisplayParameterOptions.IncludeParamsRefOut, + memberOptions: SymbolDisplayMemberOptions.IncludeRef)); + + // Picked from https://github.com/YairHalberstadt/stronginject Thank you! + public static string FullName(this INamespaceSymbol @namespace) => + @namespace.ToDisplayString(new SymbolDisplayFormat(typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces)); + } +} \ No newline at end of file diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs new file mode 100644 index 00000000..8aeb2ba0 --- /dev/null +++ b/Main/SourceGenerator.cs @@ -0,0 +1,94 @@ +using System.Linq; +using System.Text; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Text; + +namespace MrMeeseeks.StaticDelegateGenerator +{ + [Generator] + public class SourceGenerator : ISourceGenerator + { + public void Initialize(GeneratorInitializationContext context) + { + } + + public void Execute(GeneratorExecutionContext context) + { + context.ReportDiagnostic(Diagnostic.Create( + new DiagnosticDescriptor("DIE00", "INFO", "Start", "INFO", DiagnosticSeverity.Warning, true), + Location.None)); + if (context + .Compilation + .GetTypeByMetadataName(typeof(ContainerAttribute).FullName ?? "") is not { } attributeType) + return; + + foreach (var attributeData in context + .Compilation + .Assembly + .GetAttributes() + .Where(ad => ad.AttributeClass?.Equals(attributeType, SymbolEqualityComparer.Default) ?? false)) + { + var countConstructorArguments = attributeData.ConstructorArguments.Length; + if (countConstructorArguments is not 1) + { + // Invalid code, ignore + continue; + } + + var typeConstant = attributeData.ConstructorArguments[0]; + if (typeConstant.Kind != TypedConstantKind.Type) + { + // Invalid code, ignore + continue; + } + if (!CheckValidType(typeConstant, out var type)) + { + continue; + } + + var containerClassName = $"{type.Name}Container"; + + context.ReportDiagnostic(Diagnostic.Create( + new DiagnosticDescriptor("DIE01", "INFO", type.FullName(), "INFO", DiagnosticSeverity.Warning, true), + Location.None)); + + var generatedContainer = new StringBuilder(); + + generatedContainer = generatedContainer + .AppendLine($"namespace MrMeeseeks.DIE") + .AppendLine($"{{") + .AppendLine($" internal class {containerClassName}") + .AppendLine($" {{") + .AppendLine($" public {type.FullName()} Resolve() => new {type.FullName()}();") + .AppendLine($" }}") + .AppendLine($"}}") + ; + + var containerSource = CSharpSyntaxTree + .ParseText(SourceText.From(generatedContainer.ToString(), Encoding.UTF8)) + .GetRoot() + .NormalizeWhitespace() + .SyntaxTree + .GetText(); + context.AddSource($"{type.Name}.g.cs", containerSource); + } + } + + private bool CheckValidType(TypedConstant typedConstant, out INamedTypeSymbol type) + { + type = (typedConstant.Value as INamedTypeSymbol)!; + if (typedConstant.Value is null) + return false; + if (type.IsOrReferencesErrorType()) + // we will report an error for this case anyway. + return false; + if (type.IsUnboundGenericType) + return false; + if (!type.IsAccessibleInternally()) + return false; + + return true; + } + } +} diff --git a/Main/StaticDelegateAttribute.cs b/Main/StaticDelegateAttribute.cs new file mode 100644 index 00000000..d68449ba --- /dev/null +++ b/Main/StaticDelegateAttribute.cs @@ -0,0 +1,13 @@ +using System; + +namespace MrMeeseeks.StaticDelegateGenerator +{ + [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] + public class ContainerAttribute : Attribute + { + // ReSharper disable once UnusedParameter.Local *** Is used in the generator + public ContainerAttribute(Type type) + { + } + } +} diff --git a/MrMeeseeks.DIE.sln b/MrMeeseeks.DIE.sln new file mode 100644 index 00000000..a2f191f2 --- /dev/null +++ b/MrMeeseeks.DIE.sln @@ -0,0 +1,36 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31423.177 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Main", "Main\Main.csproj", "{943520B9-1502-48BB-A8FE-57103557E256}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sample", "Sample\Sample.csproj", "{5DFB446B-AAC8-450A-95A1-A55EF6BB37DB}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Misc", "Misc", "{4BFDBE50-2316-463E-B587-3F367D591FDF}" + ProjectSection(SolutionItems) = preProject + Directory.build.props = Directory.build.props + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {943520B9-1502-48BB-A8FE-57103557E256}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {943520B9-1502-48BB-A8FE-57103557E256}.Debug|Any CPU.Build.0 = Debug|Any CPU + {943520B9-1502-48BB-A8FE-57103557E256}.Release|Any CPU.ActiveCfg = Release|Any CPU + {943520B9-1502-48BB-A8FE-57103557E256}.Release|Any CPU.Build.0 = Release|Any CPU + {5DFB446B-AAC8-450A-95A1-A55EF6BB37DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5DFB446B-AAC8-450A-95A1-A55EF6BB37DB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5DFB446B-AAC8-450A-95A1-A55EF6BB37DB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5DFB446B-AAC8-450A-95A1-A55EF6BB37DB}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {7BD98588-FA68-4B8A-A76B-DEA1CDE30E92} + EndGlobalSection +EndGlobal diff --git a/README.md b/README.md new file mode 100644 index 00000000..af300e7c --- /dev/null +++ b/README.md @@ -0,0 +1,83 @@ +# MrMeeseeks.StaticDelegateGenerator + +This Generator applies the Delegate pattern (similar or synonomous to Proxy, Wrapper, Adapter patterns) to the static elements (properties and methods) of a given type. + +The explanations of the whys and hows here won't go much into the details of the basics. It's recommended to have a look into the Dependency Inversion Principle (DIP; it's one of the SOLID principles) & Dependency Injection and Object Oriented Programming (OOP) patterns like Proxy, Wrapper, Adapter and Delegate patterns. The patterns are all similar in the way how they are implemtented. They just differ in use cases. This project chose to go with the term Delegate, because it seemed to be most fitting. + +## Why and which problem does it solve? + +Let's directly start with a bad example: + +```C# +internal class BadExampleUsingStaticDependencyInConstructor +{ + public BadExampleUsingStaticDependencyInConstructor() + { + Console.WriteLine(DateTime.Now); + } +} +``` + +This is a violation of the DIP, because `DateTime.Now` is a dependency on a concrete implementation rather than an abstraction. That is always the case with references to static code. The issue here is that you cannot switch implementations. For example, this would make unit tests which depend on `DateTime.Now` returning a very concrete value impossible. + + +This is just indirectly the problem which `MrMeeseeks.StaticDelegateGenerator` solves. The problem which this project solves directly can be inferred from the solution to the problem of the bad example abover. Meaning the solution being the next problem. Here the solution: + +```C# +internal interface IDateTimeNowStaticDelegate +{ + DateTime Now { get; } +} + +internal class DateTimeNowStaticDelegate : IDateTimeNowStaticDelegate +{ + public DateTime Now => DateTime.Now; +} + +internal class SolvedExampleWithConstructorInjection +{ + public SolvedExampleWithConstructorInjection( + IDateTimeNowStaticDelegate dateTimeNowStaticDelegate) + { + Console.WriteLine(dateTimeNowStaticDelegate.Now); + } +} +``` + +Solution: we delegate to the static code and wrap it into an concrete implementation implementing an interface which finally gets injected by constructor injection (DI). Let's call that the (Static) Delegate pattern. + +DIP is happy, problem solved, right? Not yet. Here comes the human component into play. Maintaining the Delegate pattern for all static references becomes tedious and monotonous fast. Also it bloats the code base (more code, more files) without doing something new (it just delegates to already existing functionality). + +And that is exactly the problem which `MrMeeseeks.StaticDelegateGenerator` is trying to solves. + +## Usage + +First, get the latest release version of the nuget package: + +``` +Install-Package MrMeeseeks.StaticDelegateGenerator +``` + +Then declare which type you want to get a Static Delegate from via the `StaticDelegate`-Attribute. For `DateTime` it would look like: + +```C# +using System; +using MrMeeseeks.StaticDelegateGenerator; + +[assembly: StaticDelegate(typeof(DateTime))] +``` + +The Source Generator will then generate an interface called `IDateTimeStaticDelegate` and a corresponding concrete implementation `DateTimeStaticDelegate` which you can use inplace of `DateTime`: + +```C# +internal class SolvedExampleWithStaticDelegate +{ + public SolvedExampleWithStaticDelegate( + IDateTimeStaticDelegate dateTimeNowStaticDelegate) + { + Console.WriteLine(dateTimeNowStaticDelegate.Now); + } +} +``` + +Of course you would need to setup your DI to inject `DateTimeStaticDelegate` into this constructor parameter. However, this is a topic of its own which won't be covered here. diff --git a/Sample/AssemblyInfo.cs b/Sample/AssemblyInfo.cs new file mode 100644 index 00000000..785b13f8 --- /dev/null +++ b/Sample/AssemblyInfo.cs @@ -0,0 +1,4 @@ +using MrMeeseeks.StaticDelegate.Sample; +using MrMeeseeks.StaticDelegateGenerator; + +[assembly: Container(typeof(Context))] \ No newline at end of file diff --git a/Sample/Context.cs b/Sample/Context.cs new file mode 100644 index 00000000..a67cdd33 --- /dev/null +++ b/Sample/Context.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MrMeeseeks.StaticDelegate.Sample +{ + class Context + { + public String Text => "Hello, world"; + public Context() + { + + } + } +} diff --git a/Sample/Program.cs b/Sample/Program.cs new file mode 100644 index 00000000..8f411c91 --- /dev/null +++ b/Sample/Program.cs @@ -0,0 +1,4 @@ +System.Console.WriteLine( + new MrMeeseeks.DIE.ContextContainer() + .Resolve() + .Text); diff --git a/Sample/Sample.csproj b/Sample/Sample.csproj new file mode 100644 index 00000000..29a5781e --- /dev/null +++ b/Sample/Sample.csproj @@ -0,0 +1,27 @@ + + + + Exe + net5.0 + + MrMeeseeks.StaticDelegate.Sample + true + $(BaseIntermediateOutputPath)\GeneratedFiles + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + From 05657b0788c811865ab5f2b33cb6ca8a9fbb4488 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sat, 7 Aug 2021 11:36:34 +0200 Subject: [PATCH 002/162] Resolving interface types which have a single implementation with parameterless constructors --- ...gateAttribute.cs => ContainerAttribute.cs} | 0 Main/ExecuteImpl.cs | 110 ++++++++++++++++++ Main/GetAllImplementations.cs | 36 ++++++ Main/InitializeImpl.cs | 26 +++++ Main/Main.csproj | 5 +- Main/Properties/launchSettings.json | 8 ++ Main/SourceGenerator.cs | 87 ++------------ Main/SyntaxReceiver.cs | 19 +++ Main/TypeToImplementationMapper.cs | 37 ++++++ MrMeeseeks.DIE.sln | 6 + Sample/AssemblyInfo.cs | 2 +- Sample/Class1.cs | 9 ++ Sample/Context.cs | 13 ++- Sample/Program.cs | 6 +- Sample/Sample.csproj | 2 +- SampleChild/Class1.cs | 11 ++ SampleChild/SampleChild.csproj | 7 ++ 17 files changed, 292 insertions(+), 92 deletions(-) rename Main/{StaticDelegateAttribute.cs => ContainerAttribute.cs} (100%) create mode 100644 Main/ExecuteImpl.cs create mode 100644 Main/GetAllImplementations.cs create mode 100644 Main/InitializeImpl.cs create mode 100644 Main/Properties/launchSettings.json create mode 100644 Main/SyntaxReceiver.cs create mode 100644 Main/TypeToImplementationMapper.cs create mode 100644 Sample/Class1.cs create mode 100644 SampleChild/Class1.cs create mode 100644 SampleChild/SampleChild.csproj diff --git a/Main/StaticDelegateAttribute.cs b/Main/ContainerAttribute.cs similarity index 100% rename from Main/StaticDelegateAttribute.cs rename to Main/ContainerAttribute.cs diff --git a/Main/ExecuteImpl.cs b/Main/ExecuteImpl.cs new file mode 100644 index 00000000..d8f98af3 --- /dev/null +++ b/Main/ExecuteImpl.cs @@ -0,0 +1,110 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Text; +using MrMeeseeks.StaticDelegateGenerator; +using System.Linq; +using System.Text; + +namespace MrMeeseeks.DIE +{ + internal interface IExecute + { + void Execute(); + } + + internal class ExecuteImpl : IExecute + { + private readonly GeneratorExecutionContext context; + private readonly ITypeToImplementationsMapper typeToImplementationMapper; + + public ExecuteImpl( + GeneratorExecutionContext context, + ITypeToImplementationsMapper typeToImplementationMapper) + { + this.context = context; + this.typeToImplementationMapper = typeToImplementationMapper; + } + + public void Execute() + { + context.ReportDiagnostic(Diagnostic.Create( + new DiagnosticDescriptor("DIE00", "INFO", "Start", "INFO", DiagnosticSeverity.Warning, true), + Location.None)); + if (context + .Compilation + .GetTypeByMetadataName(typeof(ContainerAttribute).FullName ?? "") is not { } attributeType) + return; + + + foreach (var attributeData in context + .Compilation + .Assembly + .GetAttributes() + .Where(ad => ad.AttributeClass?.Equals(attributeType, SymbolEqualityComparer.Default) ?? false)) + { + var countConstructorArguments = attributeData.ConstructorArguments.Length; + if (countConstructorArguments is not 1) + { + // Invalid code, ignore + continue; + } + + var typeConstant = attributeData.ConstructorArguments[0]; + if (typeConstant.Kind != TypedConstantKind.Type) + { + // Invalid code, ignore + continue; + } + if (!CheckValidType(typeConstant, out var type)) + { + continue; + } + + var containerClassName = $"{type.Name}Container"; + + context.ReportDiagnostic(Diagnostic.Create( + new DiagnosticDescriptor("DIE01", "INFO", type.FullName(), "INFO", DiagnosticSeverity.Warning, true), + Location.None)); + + var typeToInject = typeToImplementationMapper.Map(type).First(); + + var generatedContainer = new StringBuilder(); + + generatedContainer = generatedContainer + .AppendLine($"namespace MrMeeseeks.DIE") + .AppendLine($"{{") + .AppendLine($" internal class {containerClassName}") + .AppendLine($" {{") + .AppendLine($" public {type.FullName()} Resolve() => new {typeToInject.FullName()}();") + .AppendLine($" }}") + .AppendLine($"}}") + ; + + var containerSource = CSharpSyntaxTree + .ParseText(SourceText.From(generatedContainer.ToString(), Encoding.UTF8)) + .GetRoot() + .NormalizeWhitespace() + .SyntaxTree + .GetText(); + context.AddSource($"{type.Name}.g.cs", containerSource); + } + } + + private bool CheckValidType(TypedConstant typedConstant, out INamedTypeSymbol type) + { + type = (typedConstant.Value as INamedTypeSymbol)!; + if (typedConstant.Value is null) + return false; + if (type.IsOrReferencesErrorType()) + // we will report an error for this case anyway. + return false; + if (type.IsUnboundGenericType) + return false; + if (!type.IsAccessibleInternally()) + return false; + + return true; + } + } +} diff --git a/Main/GetAllImplementations.cs b/Main/GetAllImplementations.cs new file mode 100644 index 00000000..0d2284e6 --- /dev/null +++ b/Main/GetAllImplementations.cs @@ -0,0 +1,36 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; + +namespace MrMeeseeks.DIE +{ + public interface IGetAllImplementations + { + IReadOnlyList AllImplementations { get; } + } + + class GetAllImplementations : IGetAllImplementations + { + private GeneratorExecutionContext context; + + public GetAllImplementations(GeneratorExecutionContext context) + { + this.context = context; + } + + public IReadOnlyList AllImplementations => new ReadOnlyCollection(context.Compilation.SyntaxTrees + .Select(st => (st, context.Compilation.GetSemanticModel(st))) + .SelectMany(t => t.st + .GetRoot() + .DescendantNodesAndSelf() + .OfType() + .Select(c => t.Item2.GetDeclaredSymbol(c)) + .Where(c => c is not null) + .OfType()) + .ToList()); + } +} diff --git a/Main/InitializeImpl.cs b/Main/InitializeImpl.cs new file mode 100644 index 00000000..0b7eeb8c --- /dev/null +++ b/Main/InitializeImpl.cs @@ -0,0 +1,26 @@ +using Microsoft.CodeAnalysis; +using System; + +namespace MrMeeseeks.DIE +{ + public interface IInitialize + { + void Initialize(); + } + + class InitializeImpl : IInitialize + { + private readonly GeneratorInitializationContext context; + private readonly Func syntaxReceiverFactory; + + public InitializeImpl( + GeneratorInitializationContext context, + Func syntaxReceiverFactory) + { + this.context = context; + this.syntaxReceiverFactory = syntaxReceiverFactory; + } + + public void Initialize() => context.RegisterForSyntaxNotifications(() => syntaxReceiverFactory()); + } +} diff --git a/Main/Main.csproj b/Main/Main.csproj index 63d40e71..64844e4c 100644 --- a/Main/Main.csproj +++ b/Main/Main.csproj @@ -7,6 +7,7 @@ $(RootNamespace) true + true @@ -22,12 +23,14 @@ - + + all runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/Main/Properties/launchSettings.json b/Main/Properties/launchSettings.json new file mode 100644 index 00000000..048ecac2 --- /dev/null +++ b/Main/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "Main": { + "commandName": "DebugRoslynComponent", + "targetProject": "..\\Sample\\Sample.csproj" + } + } +} \ No newline at end of file diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index 8aeb2ba0..bc92426b 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -1,8 +1,6 @@ -using System.Linq; -using System.Text; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis; +using MrMeeseeks.DIE; +using System; namespace MrMeeseeks.StaticDelegateGenerator { @@ -11,84 +9,15 @@ public class SourceGenerator : ISourceGenerator { public void Initialize(GeneratorInitializationContext context) { + Func syntaxReceiverFactory = () => new SyntaxReceiver(); + new InitializeImpl(context, syntaxReceiverFactory).Initialize(); } public void Execute(GeneratorExecutionContext context) { - context.ReportDiagnostic(Diagnostic.Create( - new DiagnosticDescriptor("DIE00", "INFO", "Start", "INFO", DiagnosticSeverity.Warning, true), - Location.None)); - if (context - .Compilation - .GetTypeByMetadataName(typeof(ContainerAttribute).FullName ?? "") is not { } attributeType) - return; - - foreach (var attributeData in context - .Compilation - .Assembly - .GetAttributes() - .Where(ad => ad.AttributeClass?.Equals(attributeType, SymbolEqualityComparer.Default) ?? false)) - { - var countConstructorArguments = attributeData.ConstructorArguments.Length; - if (countConstructorArguments is not 1) - { - // Invalid code, ignore - continue; - } - - var typeConstant = attributeData.ConstructorArguments[0]; - if (typeConstant.Kind != TypedConstantKind.Type) - { - // Invalid code, ignore - continue; - } - if (!CheckValidType(typeConstant, out var type)) - { - continue; - } - - var containerClassName = $"{type.Name}Container"; - - context.ReportDiagnostic(Diagnostic.Create( - new DiagnosticDescriptor("DIE01", "INFO", type.FullName(), "INFO", DiagnosticSeverity.Warning, true), - Location.None)); - - var generatedContainer = new StringBuilder(); - - generatedContainer = generatedContainer - .AppendLine($"namespace MrMeeseeks.DIE") - .AppendLine($"{{") - .AppendLine($" internal class {containerClassName}") - .AppendLine($" {{") - .AppendLine($" public {type.FullName()} Resolve() => new {type.FullName()}();") - .AppendLine($" }}") - .AppendLine($"}}") - ; - - var containerSource = CSharpSyntaxTree - .ParseText(SourceText.From(generatedContainer.ToString(), Encoding.UTF8)) - .GetRoot() - .NormalizeWhitespace() - .SyntaxTree - .GetText(); - context.AddSource($"{type.Name}.g.cs", containerSource); - } - } - - private bool CheckValidType(TypedConstant typedConstant, out INamedTypeSymbol type) - { - type = (typedConstant.Value as INamedTypeSymbol)!; - if (typedConstant.Value is null) - return false; - if (type.IsOrReferencesErrorType()) - // we will report an error for this case anyway. - return false; - if (type.IsUnboundGenericType) - return false; - if (!type.IsAccessibleInternally()) - return false; - - return true; + var getAllImplementations = new GetAllImplementations(context); + var typeToImplementationMapper = new TypeToImplementationsMapper(getAllImplementations); + new ExecuteImpl(context, typeToImplementationMapper).Execute(); } } } diff --git a/Main/SyntaxReceiver.cs b/Main/SyntaxReceiver.cs new file mode 100644 index 00000000..c634fe97 --- /dev/null +++ b/Main/SyntaxReceiver.cs @@ -0,0 +1,19 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.Collections.Generic; + +namespace MrMeeseeks.DIE +{ + public class SyntaxReceiver : ISyntaxReceiver + { + public List Candidates { get; } = new(); + + public void OnVisitSyntaxNode(SyntaxNode syntaxNode) + { + if (syntaxNode is ClassDeclarationSyntax classDeclarationSyntax) + { + Candidates.Add(classDeclarationSyntax); + } + } + } +} diff --git a/Main/TypeToImplementationMapper.cs b/Main/TypeToImplementationMapper.cs new file mode 100644 index 00000000..06b63134 --- /dev/null +++ b/Main/TypeToImplementationMapper.cs @@ -0,0 +1,37 @@ +using Microsoft.CodeAnalysis; +using System.Collections.Generic; +using System.Linq; + +namespace MrMeeseeks.DIE +{ + public interface ITypeToImplementationsMapper + { + IList Map(INamedTypeSymbol typeSymbol); + } + + class TypeToImplementationsMapper : ITypeToImplementationsMapper + { + private readonly Dictionary> map; + + public TypeToImplementationsMapper( + IGetAllImplementations getAllImplementations) => + map = getAllImplementations + .AllImplementations + .SelectMany(i => + { + return i.AllInterfaces.Select(ii => (ii, i)).Prepend((i, i)); + }) + .GroupBy(t => t.Item1, t => t.Item2) + .ToDictionary(g => g.Key, g => g.ToList()); + + public IList Map(INamedTypeSymbol typeSymbol) + { + if(map.TryGetValue(typeSymbol, out var implementations)) + { + return implementations; + } + + return new List(); + } + } +} diff --git a/MrMeeseeks.DIE.sln b/MrMeeseeks.DIE.sln index a2f191f2..9b1ff7d1 100644 --- a/MrMeeseeks.DIE.sln +++ b/MrMeeseeks.DIE.sln @@ -12,6 +12,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Misc", "Misc", "{4BFDBE50-2 Directory.build.props = Directory.build.props EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SampleChild", "SampleChild\SampleChild.csproj", "{6925C30D-D532-46FD-9DE8-80317129EDC9}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -26,6 +28,10 @@ Global {5DFB446B-AAC8-450A-95A1-A55EF6BB37DB}.Debug|Any CPU.Build.0 = Debug|Any CPU {5DFB446B-AAC8-450A-95A1-A55EF6BB37DB}.Release|Any CPU.ActiveCfg = Release|Any CPU {5DFB446B-AAC8-450A-95A1-A55EF6BB37DB}.Release|Any CPU.Build.0 = Release|Any CPU + {6925C30D-D532-46FD-9DE8-80317129EDC9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6925C30D-D532-46FD-9DE8-80317129EDC9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6925C30D-D532-46FD-9DE8-80317129EDC9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6925C30D-D532-46FD-9DE8-80317129EDC9}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Sample/AssemblyInfo.cs b/Sample/AssemblyInfo.cs index 785b13f8..f02c4efc 100644 --- a/Sample/AssemblyInfo.cs +++ b/Sample/AssemblyInfo.cs @@ -1,4 +1,4 @@ using MrMeeseeks.StaticDelegate.Sample; using MrMeeseeks.StaticDelegateGenerator; -[assembly: Container(typeof(Context))] \ No newline at end of file +[assembly: Container(typeof(IContext))] \ No newline at end of file diff --git a/Sample/Class1.cs b/Sample/Class1.cs new file mode 100644 index 00000000..85a85adf --- /dev/null +++ b/Sample/Class1.cs @@ -0,0 +1,9 @@ +namespace SampleChild +{ + public interface IChild + { } + + public class Child : IChild + { + } +} diff --git a/Sample/Context.cs b/Sample/Context.cs index a67cdd33..6aa773b2 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -1,15 +1,16 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace MrMeeseeks.StaticDelegate.Sample { - class Context + internal interface IContext + { + String Text { get; } + } + + internal class Context : IContext { public String Text => "Hello, world"; - public Context() + public Context()//(Child child) { } diff --git a/Sample/Program.cs b/Sample/Program.cs index 8f411c91..df5d8ef2 100644 --- a/Sample/Program.cs +++ b/Sample/Program.cs @@ -1,4 +1,2 @@ -System.Console.WriteLine( - new MrMeeseeks.DIE.ContextContainer() - .Resolve() - .Text); +//System.Console.WriteLine("Hello, world!"); +System.Console.WriteLine(new MrMeeseeks.DIE.IContextContainer().Resolve().Text); diff --git a/Sample/Sample.csproj b/Sample/Sample.csproj index 29a5781e..dcc74d1b 100644 --- a/Sample/Sample.csproj +++ b/Sample/Sample.csproj @@ -17,7 +17,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/SampleChild/Class1.cs b/SampleChild/Class1.cs new file mode 100644 index 00000000..83e8b34e --- /dev/null +++ b/SampleChild/Class1.cs @@ -0,0 +1,11 @@ +using System; + +namespace SampleChild +{ + public interface IChild + { } + + public class Child : IChild + { + } +} diff --git a/SampleChild/SampleChild.csproj b/SampleChild/SampleChild.csproj new file mode 100644 index 00000000..f208d303 --- /dev/null +++ b/SampleChild/SampleChild.csproj @@ -0,0 +1,7 @@ + + + + net5.0 + + + From bdc804fdd7141977e86f17fd1ddec1abbe510c83 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sun, 8 Aug 2021 22:52:35 +0200 Subject: [PATCH 003/162] Constructors with parameters --- Main/DependencyWrapper.cs | 18 +++++ Main/DiagLogger.cs | 34 ++++++++ Main/ExecuteImpl.cs | 82 +++---------------- Main/GenerateContainer.cs | 125 +++++++++++++++++++++++++++++ Main/GetAllImplementations.cs | 4 +- Main/InitializeImpl.cs | 4 +- Main/IsExternalInit.cs | 10 +++ Main/SourceGenerator.cs | 4 +- Main/SyntaxReceiver.cs | 2 +- Main/TypeToImplementationMapper.cs | 4 +- Sample/{Class1.cs => Child.cs} | 2 +- Sample/Context.cs | 2 +- 12 files changed, 208 insertions(+), 83 deletions(-) create mode 100644 Main/DependencyWrapper.cs create mode 100644 Main/DiagLogger.cs create mode 100644 Main/GenerateContainer.cs create mode 100644 Main/IsExternalInit.cs rename Sample/{Class1.cs => Child.cs} (64%) diff --git a/Main/DependencyWrapper.cs b/Main/DependencyWrapper.cs new file mode 100644 index 00000000..21e32891 --- /dev/null +++ b/Main/DependencyWrapper.cs @@ -0,0 +1,18 @@ +using Microsoft.CodeAnalysis; +using System.Collections.Generic; + +namespace MrMeeseeks.DIE +{ + internal enum ResolutionStage + { + Prefix, + Postfix + } + + internal record DependencyWrapper( + ResolutionStage ResolutionStage, + int Id, + INamedTypeSymbol InjectedType, + INamedTypeSymbol ImplementationType, + IReadOnlyList ParameterIds); +} diff --git a/Main/DiagLogger.cs b/Main/DiagLogger.cs new file mode 100644 index 00000000..66de461d --- /dev/null +++ b/Main/DiagLogger.cs @@ -0,0 +1,34 @@ +using Microsoft.CodeAnalysis; +using System; +using System.Collections.Generic; +using System.Text; + +namespace MrMeeseeks.DIE +{ + internal interface IDiagLogger + { + void Log(int id, string message); + + void Log(int id, string title, string message, string category, DiagnosticSeverity diagnosticSeverity); + } + + internal class DiagLogger : IDiagLogger + { + private readonly GeneratorExecutionContext context; + + public DiagLogger( + GeneratorExecutionContext context) + { + this.context = context; + } + + public void Log(int id, string title, string message, string category, DiagnosticSeverity diagnosticSeverity) + { + context.ReportDiagnostic(Diagnostic.Create( + new DiagnosticDescriptor($"DIE{id.ToString().PadLeft(3, '0')}", title, message, category, diagnosticSeverity, true), + Location.None)); + } + + public void Log(int id, string message) => Log(id, "INFO", message, "INFO", DiagnosticSeverity.Warning); + } +} diff --git a/Main/ExecuteImpl.cs b/Main/ExecuteImpl.cs index d8f98af3..5f13c5f9 100644 --- a/Main/ExecuteImpl.cs +++ b/Main/ExecuteImpl.cs @@ -1,10 +1,6 @@ using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Text; using MrMeeseeks.StaticDelegateGenerator; using System.Linq; -using System.Text; namespace MrMeeseeks.DIE { @@ -16,21 +12,22 @@ internal interface IExecute internal class ExecuteImpl : IExecute { private readonly GeneratorExecutionContext context; - private readonly ITypeToImplementationsMapper typeToImplementationMapper; + private readonly IContainerGenerator containerGenerator; + private readonly IDiagLogger diagLogger; public ExecuteImpl( GeneratorExecutionContext context, - ITypeToImplementationsMapper typeToImplementationMapper) + IContainerGenerator containerGenerator, + IDiagLogger diagLogger) { this.context = context; - this.typeToImplementationMapper = typeToImplementationMapper; + this.containerGenerator = containerGenerator; + this.diagLogger = diagLogger; } public void Execute() { - context.ReportDiagnostic(Diagnostic.Create( - new DiagnosticDescriptor("DIE00", "INFO", "Start", "INFO", DiagnosticSeverity.Warning, true), - Location.None)); + diagLogger.Log(0, "Start Execute"); if (context .Compilation .GetTypeByMetadataName(typeof(ContainerAttribute).FullName ?? "") is not { } attributeType) @@ -42,69 +39,8 @@ public void Execute() .Assembly .GetAttributes() .Where(ad => ad.AttributeClass?.Equals(attributeType, SymbolEqualityComparer.Default) ?? false)) - { - var countConstructorArguments = attributeData.ConstructorArguments.Length; - if (countConstructorArguments is not 1) - { - // Invalid code, ignore - continue; - } - - var typeConstant = attributeData.ConstructorArguments[0]; - if (typeConstant.Kind != TypedConstantKind.Type) - { - // Invalid code, ignore - continue; - } - if (!CheckValidType(typeConstant, out var type)) - { - continue; - } - - var containerClassName = $"{type.Name}Container"; - - context.ReportDiagnostic(Diagnostic.Create( - new DiagnosticDescriptor("DIE01", "INFO", type.FullName(), "INFO", DiagnosticSeverity.Warning, true), - Location.None)); - - var typeToInject = typeToImplementationMapper.Map(type).First(); - - var generatedContainer = new StringBuilder(); - - generatedContainer = generatedContainer - .AppendLine($"namespace MrMeeseeks.DIE") - .AppendLine($"{{") - .AppendLine($" internal class {containerClassName}") - .AppendLine($" {{") - .AppendLine($" public {type.FullName()} Resolve() => new {typeToInject.FullName()}();") - .AppendLine($" }}") - .AppendLine($"}}") - ; - - var containerSource = CSharpSyntaxTree - .ParseText(SourceText.From(generatedContainer.ToString(), Encoding.UTF8)) - .GetRoot() - .NormalizeWhitespace() - .SyntaxTree - .GetText(); - context.AddSource($"{type.Name}.g.cs", containerSource); - } - } - - private bool CheckValidType(TypedConstant typedConstant, out INamedTypeSymbol type) - { - type = (typedConstant.Value as INamedTypeSymbol)!; - if (typedConstant.Value is null) - return false; - if (type.IsOrReferencesErrorType()) - // we will report an error for this case anyway. - return false; - if (type.IsUnboundGenericType) - return false; - if (!type.IsAccessibleInternally()) - return false; - - return true; + containerGenerator.Generate(attributeData); + diagLogger.Log(2, "End Execute"); } } } diff --git a/Main/GenerateContainer.cs b/Main/GenerateContainer.cs new file mode 100644 index 00000000..ff30c4c1 --- /dev/null +++ b/Main/GenerateContainer.cs @@ -0,0 +1,125 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Text; +using MrMeeseeks.StaticDelegateGenerator; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace MrMeeseeks.DIE +{ + internal interface IContainerGenerator + { + void Generate(AttributeData attributeData); + } + + internal class ContainerGenrator : IContainerGenerator + { + private readonly GeneratorExecutionContext context; + private readonly IDiagLogger diagLogger; + private readonly ITypeToImplementationsMapper typeToImplementationMapper; + + public ContainerGenrator( + GeneratorExecutionContext context, + IDiagLogger diagLogger, + ITypeToImplementationsMapper typeToImplementationMapper) + { + this.context = context; + this.diagLogger = diagLogger; + this.typeToImplementationMapper = typeToImplementationMapper; + } + + public void Generate(AttributeData attributeData) + { + var countConstructorArguments = attributeData.ConstructorArguments.Length; + if (countConstructorArguments is not 1) + { + // Invalid code, ignore + return; + } + + var typeConstant = attributeData.ConstructorArguments[0]; + if (typeConstant.Kind != TypedConstantKind.Type) + { + // Invalid code, ignore + return; + } + if (!CheckValidType(typeConstant, out var type)) + { + return; + } + var id = -1; + var stack = new Stack(); + + var containerClassName = $"{type.Name}Container"; + + var typeToInject = typeToImplementationMapper.Map(type).First(); + + stack.Push(new DependencyWrapper(ResolutionStage.Prefix, ++id, type, typeToInject, new List())); + + var generatedContainer = new StringBuilder() + .AppendLine($"namespace MrMeeseeks.DIE") + .AppendLine($"{{") + .AppendLine($" internal class {containerClassName}") + .AppendLine($" {{") + .AppendLine($" public {type.FullName()} Resolve()") + .AppendLine($" {{"); + + while (stack.Any()) + { + var subject = stack.Pop(); + if (subject is { ResolutionStage: ResolutionStage.Prefix }) + { + var parameterIds = new List(); + stack.Push(subject with { ResolutionStage = ResolutionStage.Postfix, ParameterIds = parameterIds }); + var ctor = subject.ImplementationType.Constructors.First(); + foreach (var parameter in ctor.Parameters.Select(p => p.Type)) + { + var namedParameter = (INamedTypeSymbol)parameter; + var typeToInjectParameter = typeToImplementationMapper.Map(namedParameter).First(); + var parameterWrapper = new DependencyWrapper(ResolutionStage.Prefix, ++id, namedParameter, typeToInjectParameter, new List()); + stack.Push(parameterWrapper); + parameterIds.Add(parameterWrapper.Id); + } + } + else if (subject is { ResolutionStage: ResolutionStage.Postfix }) + { + generatedContainer = generatedContainer + .AppendLine($" var _{subject.Id} = new {subject.ImplementationType.FullName()}({string.Join(", ", subject.ParameterIds.Select(id => $"_{id}"))});") + ; + }//*/ + } + + generatedContainer = generatedContainer + .AppendLine($" return _0;") + .AppendLine($" }}") + .AppendLine($" }}") + .AppendLine($"}}") + ; + + var containerSource = CSharpSyntaxTree + .ParseText(SourceText.From(generatedContainer.ToString(), Encoding.UTF8)) + .GetRoot() + .NormalizeWhitespace() + .SyntaxTree + .GetText(); + context.AddSource($"{type.Name}.g.cs", containerSource); + } + + private bool CheckValidType(TypedConstant typedConstant, out INamedTypeSymbol type) + { + type = (typedConstant.Value as INamedTypeSymbol)!; + if (typedConstant.Value is null) + return false; + if (type.IsOrReferencesErrorType()) + // we will report an error for this case anyway. + return false; + if (type.IsUnboundGenericType) + return false; + if (!type.IsAccessibleInternally()) + return false; + + return true; + } + } +} diff --git a/Main/GetAllImplementations.cs b/Main/GetAllImplementations.cs index 0d2284e6..35e128ba 100644 --- a/Main/GetAllImplementations.cs +++ b/Main/GetAllImplementations.cs @@ -8,12 +8,12 @@ namespace MrMeeseeks.DIE { - public interface IGetAllImplementations + internal interface IGetAllImplementations { IReadOnlyList AllImplementations { get; } } - class GetAllImplementations : IGetAllImplementations + internal class GetAllImplementations : IGetAllImplementations { private GeneratorExecutionContext context; diff --git a/Main/InitializeImpl.cs b/Main/InitializeImpl.cs index 0b7eeb8c..cd22cda6 100644 --- a/Main/InitializeImpl.cs +++ b/Main/InitializeImpl.cs @@ -3,12 +3,12 @@ namespace MrMeeseeks.DIE { - public interface IInitialize + internal interface IInitialize { void Initialize(); } - class InitializeImpl : IInitialize + internal class InitializeImpl : IInitialize { private readonly GeneratorInitializationContext context; private readonly Func syntaxReceiverFactory; diff --git a/Main/IsExternalInit.cs b/Main/IsExternalInit.cs new file mode 100644 index 00000000..9938f4c9 --- /dev/null +++ b/Main/IsExternalInit.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace System.Runtime.CompilerServices +{ + public class IsExternalInit + { + } +} diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index bc92426b..80b71ca3 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -15,9 +15,11 @@ public void Initialize(GeneratorInitializationContext context) public void Execute(GeneratorExecutionContext context) { + var diagLogger = new DiagLogger(context); var getAllImplementations = new GetAllImplementations(context); var typeToImplementationMapper = new TypeToImplementationsMapper(getAllImplementations); - new ExecuteImpl(context, typeToImplementationMapper).Execute(); + var containerGenerator = new ContainerGenrator(context, diagLogger, typeToImplementationMapper); + new ExecuteImpl(context, containerGenerator, diagLogger).Execute(); } } } diff --git a/Main/SyntaxReceiver.cs b/Main/SyntaxReceiver.cs index c634fe97..4eee265e 100644 --- a/Main/SyntaxReceiver.cs +++ b/Main/SyntaxReceiver.cs @@ -4,7 +4,7 @@ namespace MrMeeseeks.DIE { - public class SyntaxReceiver : ISyntaxReceiver + internal class SyntaxReceiver : ISyntaxReceiver { public List Candidates { get; } = new(); diff --git a/Main/TypeToImplementationMapper.cs b/Main/TypeToImplementationMapper.cs index 06b63134..f61dc9e9 100644 --- a/Main/TypeToImplementationMapper.cs +++ b/Main/TypeToImplementationMapper.cs @@ -4,12 +4,12 @@ namespace MrMeeseeks.DIE { - public interface ITypeToImplementationsMapper + internal interface ITypeToImplementationsMapper { IList Map(INamedTypeSymbol typeSymbol); } - class TypeToImplementationsMapper : ITypeToImplementationsMapper + internal class TypeToImplementationsMapper : ITypeToImplementationsMapper { private readonly Dictionary> map; diff --git a/Sample/Class1.cs b/Sample/Child.cs similarity index 64% rename from Sample/Class1.cs rename to Sample/Child.cs index 85a85adf..6a2fcdd3 100644 --- a/Sample/Class1.cs +++ b/Sample/Child.cs @@ -1,4 +1,4 @@ -namespace SampleChild +namespace MrMeeseeks.StaticDelegate.Sample { public interface IChild { } diff --git a/Sample/Context.cs b/Sample/Context.cs index 6aa773b2..d1aae4cc 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -10,7 +10,7 @@ internal interface IContext internal class Context : IContext { public String Text => "Hello, world"; - public Context()//(Child child) + public Context(IChild child) { } From 320dc6db0d980388d2114bcd5336d4b8eae02c90 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sun, 15 Aug 2021 19:59:25 +0200 Subject: [PATCH 004/162] Implemented Spy Source Generator --- Main/DiagLogger.cs | 3 -- Main/GenerateContainer.cs | 1 - Main/GetAllImplementations.cs | 1 - Main/IsExternalInit.cs | 6 +-- Main/RoslynExtensions.cs | 4 +- Main/SourceGenerator.cs | 3 +- MrMeeseeks.DIE.sln | 8 +++- Sample/AssemblyInfo.cs | 2 +- Sample/Child.cs | 9 ---- Sample/Context.cs | 3 +- Sample/Program.cs | 4 +- Sample/Sample.csproj | 3 +- SampleChild/{Class1.cs => Child.cs} | 4 +- SampleChild/InternalChild.cs | 9 ++++ SampleChild/SampleChild.csproj | 12 +++++ Spy/ContainerAttribute.cs | 13 ++++++ Spy/DependencyWrapper.cs | 18 ++++++++ Spy/DiagLogger.cs | 31 +++++++++++++ Spy/ExecuteImpl.cs | 36 +++++++++++++++ Spy/GenerateContainer.cs | 72 +++++++++++++++++++++++++++++ Spy/GetAllImplementations.cs | 35 ++++++++++++++ Spy/InitializeImpl.cs | 26 +++++++++++ Spy/IsExternalInit.cs | 6 +++ Spy/RoslynExtensions.cs | 54 ++++++++++++++++++++++ Spy/SourceGenerator.cs | 23 +++++++++ Spy/Spy.csproj | 39 ++++++++++++++++ Spy/SyntaxReceiver.cs | 19 ++++++++ 27 files changed, 412 insertions(+), 32 deletions(-) delete mode 100644 Sample/Child.cs rename SampleChild/{Class1.cs => Child.cs} (68%) create mode 100644 SampleChild/InternalChild.cs create mode 100644 Spy/ContainerAttribute.cs create mode 100644 Spy/DependencyWrapper.cs create mode 100644 Spy/DiagLogger.cs create mode 100644 Spy/ExecuteImpl.cs create mode 100644 Spy/GenerateContainer.cs create mode 100644 Spy/GetAllImplementations.cs create mode 100644 Spy/InitializeImpl.cs create mode 100644 Spy/IsExternalInit.cs create mode 100644 Spy/RoslynExtensions.cs create mode 100644 Spy/SourceGenerator.cs create mode 100644 Spy/Spy.csproj create mode 100644 Spy/SyntaxReceiver.cs diff --git a/Main/DiagLogger.cs b/Main/DiagLogger.cs index 66de461d..58d0cdc4 100644 --- a/Main/DiagLogger.cs +++ b/Main/DiagLogger.cs @@ -1,7 +1,4 @@ using Microsoft.CodeAnalysis; -using System; -using System.Collections.Generic; -using System.Text; namespace MrMeeseeks.DIE { diff --git a/Main/GenerateContainer.cs b/Main/GenerateContainer.cs index ff30c4c1..42ab2772 100644 --- a/Main/GenerateContainer.cs +++ b/Main/GenerateContainer.cs @@ -1,7 +1,6 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Text; -using MrMeeseeks.StaticDelegateGenerator; using System.Collections.Generic; using System.Linq; using System.Text; diff --git a/Main/GetAllImplementations.cs b/Main/GetAllImplementations.cs index 35e128ba..ca311c63 100644 --- a/Main/GetAllImplementations.cs +++ b/Main/GetAllImplementations.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; -using System.Text; namespace MrMeeseeks.DIE { diff --git a/Main/IsExternalInit.cs b/Main/IsExternalInit.cs index 9938f4c9..df783a36 100644 --- a/Main/IsExternalInit.cs +++ b/Main/IsExternalInit.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace System.Runtime.CompilerServices +namespace System.Runtime.CompilerServices { public class IsExternalInit { diff --git a/Main/RoslynExtensions.cs b/Main/RoslynExtensions.cs index a68ae978..fc75dede 100644 --- a/Main/RoslynExtensions.cs +++ b/Main/RoslynExtensions.cs @@ -1,7 +1,7 @@ using System.Linq; using Microsoft.CodeAnalysis; -namespace MrMeeseeks.StaticDelegateGenerator +namespace MrMeeseeks.DIE { internal static class RoslynExtensions { @@ -48,7 +48,7 @@ public static string FullName(this ITypeSymbol type) => memberOptions: SymbolDisplayMemberOptions.IncludeRef)); // Picked from https://github.com/YairHalberstadt/stronginject Thank you! - public static string FullName(this INamespaceSymbol @namespace) => + public static string FullName(this INamespaceSymbol @namespace) => @namespace.ToDisplayString(new SymbolDisplayFormat(typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces)); } } \ No newline at end of file diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index 80b71ca3..15eb9981 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -1,8 +1,7 @@ using Microsoft.CodeAnalysis; -using MrMeeseeks.DIE; using System; -namespace MrMeeseeks.StaticDelegateGenerator +namespace MrMeeseeks.DIE { [Generator] public class SourceGenerator : ISourceGenerator diff --git a/MrMeeseeks.DIE.sln b/MrMeeseeks.DIE.sln index 9b1ff7d1..4c439f53 100644 --- a/MrMeeseeks.DIE.sln +++ b/MrMeeseeks.DIE.sln @@ -12,7 +12,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Misc", "Misc", "{4BFDBE50-2 Directory.build.props = Directory.build.props EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SampleChild", "SampleChild\SampleChild.csproj", "{6925C30D-D532-46FD-9DE8-80317129EDC9}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SampleChild", "SampleChild\SampleChild.csproj", "{6925C30D-D532-46FD-9DE8-80317129EDC9}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Spy", "Spy\Spy.csproj", "{441E6E31-2472-42C0-AE6F-2676CB15ACDF}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -32,6 +34,10 @@ Global {6925C30D-D532-46FD-9DE8-80317129EDC9}.Debug|Any CPU.Build.0 = Debug|Any CPU {6925C30D-D532-46FD-9DE8-80317129EDC9}.Release|Any CPU.ActiveCfg = Release|Any CPU {6925C30D-D532-46FD-9DE8-80317129EDC9}.Release|Any CPU.Build.0 = Release|Any CPU + {441E6E31-2472-42C0-AE6F-2676CB15ACDF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {441E6E31-2472-42C0-AE6F-2676CB15ACDF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {441E6E31-2472-42C0-AE6F-2676CB15ACDF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {441E6E31-2472-42C0-AE6F-2676CB15ACDF}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Sample/AssemblyInfo.cs b/Sample/AssemblyInfo.cs index f02c4efc..7422f4b1 100644 --- a/Sample/AssemblyInfo.cs +++ b/Sample/AssemblyInfo.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.StaticDelegate.Sample; +using MrMeeseeks.DIE.Sample; using MrMeeseeks.StaticDelegateGenerator; [assembly: Container(typeof(IContext))] \ No newline at end of file diff --git a/Sample/Child.cs b/Sample/Child.cs deleted file mode 100644 index 6a2fcdd3..00000000 --- a/Sample/Child.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace MrMeeseeks.StaticDelegate.Sample -{ - public interface IChild - { } - - public class Child : IChild - { - } -} diff --git a/Sample/Context.cs b/Sample/Context.cs index d1aae4cc..d7e8aedf 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -1,6 +1,7 @@ using System; +using MrMeeseeks.DIE.SampleChild; -namespace MrMeeseeks.StaticDelegate.Sample +namespace MrMeeseeks.DIE.Sample { internal interface IContext { diff --git a/Sample/Program.cs b/Sample/Program.cs index df5d8ef2..3227255b 100644 --- a/Sample/Program.cs +++ b/Sample/Program.cs @@ -1,2 +1,2 @@ -//System.Console.WriteLine("Hello, world!"); -System.Console.WriteLine(new MrMeeseeks.DIE.IContextContainer().Resolve().Text); +System.Console.WriteLine("Hello, world!"); +//System.Console.WriteLine(new MrMeeseeks.DIE.IContextContainer().Resolve().Text); diff --git a/Sample/Sample.csproj b/Sample/Sample.csproj index dcc74d1b..760c1b1e 100644 --- a/Sample/Sample.csproj +++ b/Sample/Sample.csproj @@ -4,7 +4,7 @@ Exe net5.0 - MrMeeseeks.StaticDelegate.Sample + MrMeeseeks.DIE.Sample true $(BaseIntermediateOutputPath)\GeneratedFiles @@ -22,6 +22,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/SampleChild/Class1.cs b/SampleChild/Child.cs similarity index 68% rename from SampleChild/Class1.cs rename to SampleChild/Child.cs index 83e8b34e..03817639 100644 --- a/SampleChild/Class1.cs +++ b/SampleChild/Child.cs @@ -1,6 +1,4 @@ -using System; - -namespace SampleChild +namespace MrMeeseeks.DIE.SampleChild { public interface IChild { } diff --git a/SampleChild/InternalChild.cs b/SampleChild/InternalChild.cs new file mode 100644 index 00000000..6109b58a --- /dev/null +++ b/SampleChild/InternalChild.cs @@ -0,0 +1,9 @@ +namespace MrMeeseeks.DIE.SampleChild +{ + internal interface IInternalChild + {} + internal class InternalChild : IInternalChild + { + + } +} \ No newline at end of file diff --git a/SampleChild/SampleChild.csproj b/SampleChild/SampleChild.csproj index f208d303..d0ab0682 100644 --- a/SampleChild/SampleChild.csproj +++ b/SampleChild/SampleChild.csproj @@ -2,6 +2,18 @@ net5.0 + + MrMeeseeks.DIE.SampleChild + true + $(BaseIntermediateOutputPath)\GeneratedFiles + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + diff --git a/Spy/ContainerAttribute.cs b/Spy/ContainerAttribute.cs new file mode 100644 index 00000000..36c03a7b --- /dev/null +++ b/Spy/ContainerAttribute.cs @@ -0,0 +1,13 @@ +using System; + +namespace MrMeeseeks.DIE.Spy +{ + [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] + public class ContainerAttribute : Attribute + { + // ReSharper disable once UnusedParameter.Local *** Is used in the generator + public ContainerAttribute(Type type) + { + } + } +} diff --git a/Spy/DependencyWrapper.cs b/Spy/DependencyWrapper.cs new file mode 100644 index 00000000..b2102049 --- /dev/null +++ b/Spy/DependencyWrapper.cs @@ -0,0 +1,18 @@ +using Microsoft.CodeAnalysis; +using System.Collections.Generic; + +namespace MrMeeseeks.DIE.Spy +{ + internal enum ResolutionStage + { + Prefix, + Postfix + } + + internal record DependencyWrapper( + ResolutionStage ResolutionStage, + int Id, + INamedTypeSymbol InjectedType, + INamedTypeSymbol ImplementationType, + IReadOnlyList ParameterIds); +} diff --git a/Spy/DiagLogger.cs b/Spy/DiagLogger.cs new file mode 100644 index 00000000..a22ea859 --- /dev/null +++ b/Spy/DiagLogger.cs @@ -0,0 +1,31 @@ +using Microsoft.CodeAnalysis; + +namespace MrMeeseeks.DIE.Spy +{ + internal interface IDiagLogger + { + void Log(int id, string message); + + void Log(int id, string title, string message, string category, DiagnosticSeverity diagnosticSeverity); + } + + internal class DiagLogger : IDiagLogger + { + private readonly GeneratorExecutionContext context; + + public DiagLogger( + GeneratorExecutionContext context) + { + this.context = context; + } + + public void Log(int id, string title, string message, string category, DiagnosticSeverity diagnosticSeverity) + { + context.ReportDiagnostic(Diagnostic.Create( + new DiagnosticDescriptor($"DIESPY{id.ToString().PadLeft(3, '0')}", title, message, category, diagnosticSeverity, true), + Location.None)); + } + + public void Log(int id, string message) => Log(id, "INFO", message, "INFO", DiagnosticSeverity.Warning); + } +} diff --git a/Spy/ExecuteImpl.cs b/Spy/ExecuteImpl.cs new file mode 100644 index 00000000..d1ac63f7 --- /dev/null +++ b/Spy/ExecuteImpl.cs @@ -0,0 +1,36 @@ +using Microsoft.CodeAnalysis; + +namespace MrMeeseeks.DIE.Spy +{ + internal interface IExecute + { + void Execute(); + } + + internal class ExecuteImpl : IExecute + { + private readonly GeneratorExecutionContext context; + private readonly IContainerGenerator containerGenerator; + private readonly IDiagLogger diagLogger; + + public ExecuteImpl( + GeneratorExecutionContext context, + IContainerGenerator containerGenerator, + IDiagLogger diagLogger) + { + this.context = context; + this.containerGenerator = containerGenerator; + this.diagLogger = diagLogger; + } + + public void Execute() + { + diagLogger.Log(0, "Start Execute"); + + containerGenerator.Generate( + context.Compilation.Assembly.Name); + + diagLogger.Log(2, "End Execute"); + } + } +} diff --git a/Spy/GenerateContainer.cs b/Spy/GenerateContainer.cs new file mode 100644 index 00000000..cdf54dc8 --- /dev/null +++ b/Spy/GenerateContainer.cs @@ -0,0 +1,72 @@ +using System.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Text; +using System.Text; + +namespace MrMeeseeks.DIE.Spy +{ + internal interface IContainerGenerator + { + void Generate(string namespaceName); + } + + internal class ContainerGenerator : IContainerGenerator + { + private readonly GeneratorExecutionContext context; + private readonly IGetAllImplementations getAllImplementations; + + public ContainerGenerator( + GeneratorExecutionContext context, + IGetAllImplementations getAllImplementations) + { + this.context = context; + this.getAllImplementations = getAllImplementations; + } + + public void Generate(string namespaceName) + { + var generatedContainer = new StringBuilder() + .AppendLine($"namespace {namespaceName}") + .AppendLine($"{{") + .AppendLine($" public class PublicTypes") + .AppendLine($" {{") + ; + + var i = -1; + foreach (var type in getAllImplementations.AllImplementations.Where(t => t.DeclaredAccessibility == Accessibility.Public)) + { + generatedContainer = generatedContainer + .AppendLine($" public {type.FullName()} Type{++i} {{ get; }}") + ; + } + + generatedContainer = generatedContainer + .AppendLine($" }}") + .AppendLine($" internal class InternalTypes") + .AppendLine($" {{") + ; + + i = -1; + foreach (var type in getAllImplementations.AllImplementations.Where(t => t.DeclaredAccessibility == Accessibility.Internal)) + { + generatedContainer = generatedContainer + .AppendLine($" internal {type.FullName()} Type{++i} {{ get; }}") + ; + } + + generatedContainer = generatedContainer + .AppendLine($" }}") + .AppendLine($"}}") + ; + + var containerSource = CSharpSyntaxTree + .ParseText(SourceText.From(generatedContainer.ToString(), Encoding.UTF8)) + .GetRoot() + .NormalizeWhitespace() + .SyntaxTree + .GetText(); + context.AddSource($"PublicTypes.g.cs", containerSource); + } + } +} diff --git a/Spy/GetAllImplementations.cs b/Spy/GetAllImplementations.cs new file mode 100644 index 00000000..27a6593f --- /dev/null +++ b/Spy/GetAllImplementations.cs @@ -0,0 +1,35 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; + +namespace MrMeeseeks.DIE.Spy +{ + internal interface IGetAllImplementations + { + IReadOnlyList AllImplementations { get; } + } + + internal class GetAllImplementations : IGetAllImplementations + { + private GeneratorExecutionContext context; + + public GetAllImplementations(GeneratorExecutionContext context) + { + this.context = context; + } + + public IReadOnlyList AllImplementations => new ReadOnlyCollection(context.Compilation.SyntaxTrees + .Select(st => (st, context.Compilation.GetSemanticModel(st))) + .SelectMany(t => t.st + .GetRoot() + .DescendantNodesAndSelf() + .OfType() + .Select(c => t.Item2.GetDeclaredSymbol(c)) + .Where(c => c is not null) + .OfType()) + .ToList()); + } +} diff --git a/Spy/InitializeImpl.cs b/Spy/InitializeImpl.cs new file mode 100644 index 00000000..482ff9a6 --- /dev/null +++ b/Spy/InitializeImpl.cs @@ -0,0 +1,26 @@ +using Microsoft.CodeAnalysis; +using System; + +namespace MrMeeseeks.DIE.Spy +{ + internal interface IInitialize + { + void Initialize(); + } + + internal class InitializeImpl : IInitialize + { + private readonly GeneratorInitializationContext context; + private readonly Func syntaxReceiverFactory; + + public InitializeImpl( + GeneratorInitializationContext context, + Func syntaxReceiverFactory) + { + this.context = context; + this.syntaxReceiverFactory = syntaxReceiverFactory; + } + + public void Initialize() => context.RegisterForSyntaxNotifications(() => syntaxReceiverFactory()); + } +} diff --git a/Spy/IsExternalInit.cs b/Spy/IsExternalInit.cs new file mode 100644 index 00000000..df783a36 --- /dev/null +++ b/Spy/IsExternalInit.cs @@ -0,0 +1,6 @@ +namespace System.Runtime.CompilerServices +{ + public class IsExternalInit + { + } +} diff --git a/Spy/RoslynExtensions.cs b/Spy/RoslynExtensions.cs new file mode 100644 index 00000000..8b5f9e71 --- /dev/null +++ b/Spy/RoslynExtensions.cs @@ -0,0 +1,54 @@ +using System.Linq; +using Microsoft.CodeAnalysis; + +namespace MrMeeseeks.DIE.Spy +{ + internal static class RoslynExtensions + { + + // Picked from https://github.com/YairHalberstadt/stronginject Thank you! + public static bool IsOrReferencesErrorType(this ITypeSymbol type) + { + if (!type.ContainingType?.IsOrReferencesErrorType() ?? false) + return false; + return type switch + { + IErrorTypeSymbol => true, + IArrayTypeSymbol array => array.ElementType.IsOrReferencesErrorType(), + IPointerTypeSymbol pointer => pointer.PointedAtType.IsOrReferencesErrorType(), + INamedTypeSymbol named => !named.IsUnboundGenericType && named.TypeArguments.Any(IsOrReferencesErrorType), + _ => false, + }; + } + + // Picked from https://github.com/YairHalberstadt/stronginject Thank you! + public static bool IsAccessibleInternally(this ITypeSymbol type) + { + if (type is ITypeParameterSymbol) + return true; + if (!type.ContainingType?.IsAccessibleInternally() ?? false) + return false; + return type switch + { + IArrayTypeSymbol array => array.ElementType.IsAccessibleInternally(), + IPointerTypeSymbol pointer => pointer.PointedAtType.IsAccessibleInternally(), + INamedTypeSymbol named => named.DeclaredAccessibility is Accessibility.Public or Accessibility.ProtectedOrInternal or Accessibility.Internal + && named.TypeArguments.All(IsAccessibleInternally), + _ => false, + }; + } + + // Picked from https://github.com/YairHalberstadt/stronginject Thank you! + public static string FullName(this ITypeSymbol type) => + type.ToDisplayString(new SymbolDisplayFormat( + globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Included, + typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces, + genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters, + parameterOptions: SymbolDisplayParameterOptions.IncludeType | SymbolDisplayParameterOptions.IncludeParamsRefOut, + memberOptions: SymbolDisplayMemberOptions.IncludeRef)); + + // Picked from https://github.com/YairHalberstadt/stronginject Thank you! + public static string FullName(this INamespaceSymbol @namespace) => + @namespace.ToDisplayString(new SymbolDisplayFormat(typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces)); + } +} \ No newline at end of file diff --git a/Spy/SourceGenerator.cs b/Spy/SourceGenerator.cs new file mode 100644 index 00000000..59376449 --- /dev/null +++ b/Spy/SourceGenerator.cs @@ -0,0 +1,23 @@ +using Microsoft.CodeAnalysis; +using System; + +namespace MrMeeseeks.DIE.Spy +{ + [Generator] + public class SourceGenerator : ISourceGenerator + { + public void Initialize(GeneratorInitializationContext context) + { + Func syntaxReceiverFactory = () => new SyntaxReceiver(); + new InitializeImpl(context, syntaxReceiverFactory).Initialize(); + } + + public void Execute(GeneratorExecutionContext context) + { + var diagLogger = new DiagLogger(context); + var getAllImplementations = new GetAllImplementations(context); + var containerGenerator = new ContainerGenerator(context, getAllImplementations); + new ExecuteImpl(context, containerGenerator, diagLogger).Execute(); + } + } +} diff --git a/Spy/Spy.csproj b/Spy/Spy.csproj new file mode 100644 index 00000000..a57191b7 --- /dev/null +++ b/Spy/Spy.csproj @@ -0,0 +1,39 @@ + + + + Library + netstandard2.0 + MrMeeseeks.DIE.Spy + $(RootNamespace) + + true + true + + + + AllEnabledByDefault + preview + true + + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + diff --git a/Spy/SyntaxReceiver.cs b/Spy/SyntaxReceiver.cs new file mode 100644 index 00000000..32f3cc46 --- /dev/null +++ b/Spy/SyntaxReceiver.cs @@ -0,0 +1,19 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.Collections.Generic; + +namespace MrMeeseeks.DIE.Spy +{ + internal class SyntaxReceiver : ISyntaxReceiver + { + public List Candidates { get; } = new(); + + public void OnVisitSyntaxNode(SyntaxNode syntaxNode) + { + if (syntaxNode is ClassDeclarationSyntax classDeclarationSyntax) + { + Candidates.Add(classDeclarationSyntax); + } + } + } +} From fec84e67ef6b19244e5634197f31d8331c817621 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Fri, 17 Sep 2021 21:30:59 +0200 Subject: [PATCH 005/162] Switch from attribute-based to partial-class-based container generation --- Main/DiagLogger.cs | 10 +- Main/ExecuteImpl.cs | 48 +++++---- Main/GenerateContainer.cs | 147 ++++++++++++++-------------- Main/GetAllImplementations.cs | 8 +- Main/IContainer.cs | 6 ++ Main/InitializeImpl.cs | 10 +- Main/Main.csproj | 10 +- Main/Properties/launchSettings.json | 3 +- Main/RoslynExtensions.cs | 9 +- Main/SourceGenerator.cs | 5 +- Main/TypeToImplementationMapper.cs | 6 +- Main/WellKnownTypes.cs | 48 +++++++++ Sample/AssemblyInfo.cs | 4 - Sample/Container.cs | 8 ++ Sample/Context.cs | 3 +- Spy/DiagLogger.cs | 6 +- Spy/ExecuteImpl.cs | 20 ++-- Spy/GenerateContainer.cs | 14 +-- Spy/GetAllImplementations.cs | 8 +- Spy/InitializeImpl.cs | 10 +- Spy/Spy.csproj | 2 +- 21 files changed, 228 insertions(+), 157 deletions(-) create mode 100644 Main/IContainer.cs create mode 100644 Main/WellKnownTypes.cs delete mode 100644 Sample/AssemblyInfo.cs create mode 100644 Sample/Container.cs diff --git a/Main/DiagLogger.cs b/Main/DiagLogger.cs index 58d0cdc4..c44d4893 100644 --- a/Main/DiagLogger.cs +++ b/Main/DiagLogger.cs @@ -4,28 +4,28 @@ namespace MrMeeseeks.DIE { internal interface IDiagLogger { - void Log(int id, string message); + void Log(string message); void Log(int id, string title, string message, string category, DiagnosticSeverity diagnosticSeverity); } internal class DiagLogger : IDiagLogger { - private readonly GeneratorExecutionContext context; + private readonly GeneratorExecutionContext _context; public DiagLogger( GeneratorExecutionContext context) { - this.context = context; + _context = context; } public void Log(int id, string title, string message, string category, DiagnosticSeverity diagnosticSeverity) { - context.ReportDiagnostic(Diagnostic.Create( + _context.ReportDiagnostic(Diagnostic.Create( new DiagnosticDescriptor($"DIE{id.ToString().PadLeft(3, '0')}", title, message, category, diagnosticSeverity, true), Location.None)); } - public void Log(int id, string message) => Log(id, "INFO", message, "INFO", DiagnosticSeverity.Warning); + public void Log(string message) => Log(0, "INFO", message, "INFO", DiagnosticSeverity.Warning); } } diff --git a/Main/ExecuteImpl.cs b/Main/ExecuteImpl.cs index 5f13c5f9..f6f9f49e 100644 --- a/Main/ExecuteImpl.cs +++ b/Main/ExecuteImpl.cs @@ -1,4 +1,5 @@ using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; using MrMeeseeks.StaticDelegateGenerator; using System.Linq; @@ -11,36 +12,49 @@ internal interface IExecute internal class ExecuteImpl : IExecute { - private readonly GeneratorExecutionContext context; - private readonly IContainerGenerator containerGenerator; - private readonly IDiagLogger diagLogger; + private readonly GeneratorExecutionContext _context; + private readonly WellKnownTypes _wellKnownTypes; + private readonly IContainerGenerator _containerGenerator; + private readonly IDiagLogger _diagLogger; public ExecuteImpl( GeneratorExecutionContext context, + WellKnownTypes wellKnownTypes, IContainerGenerator containerGenerator, IDiagLogger diagLogger) { - this.context = context; - this.containerGenerator = containerGenerator; - this.diagLogger = diagLogger; + _context = context; + _wellKnownTypes = wellKnownTypes; + _containerGenerator = containerGenerator; + _diagLogger = diagLogger; } public void Execute() { - diagLogger.Log(0, "Start Execute"); - if (context + _diagLogger.Log("Start Execute"); + if (_context .Compilation .GetTypeByMetadataName(typeof(ContainerAttribute).FullName ?? "") is not { } attributeType) return; - - - foreach (var attributeData in context - .Compilation - .Assembly - .GetAttributes() - .Where(ad => ad.AttributeClass?.Equals(attributeType, SymbolEqualityComparer.Default) ?? false)) - containerGenerator.Generate(attributeData); - diagLogger.Log(2, "End Execute"); + foreach (var syntaxTree in _context.Compilation.SyntaxTrees) + { + var semanticModel = _context.Compilation.GetSemanticModel(syntaxTree); + var containerClasses = syntaxTree + .GetRoot() + .DescendantNodesAndSelf() + .OfType() + .Select(x => semanticModel.GetDeclaredSymbol(x)) + .Where(x => x != null) + .OfType() + .Where(x => x.AllInterfaces.Any(x => x.OriginalDefinition.Equals(_wellKnownTypes.Container, SymbolEqualityComparer.Default))); + foreach (var namedTypeSymbol in containerClasses) + { + _diagLogger.Log($"Container type {namedTypeSymbol.Name}"); + _containerGenerator.Generate(namedTypeSymbol); + } + } + + _diagLogger.Log("End Execute"); } } } diff --git a/Main/GenerateContainer.cs b/Main/GenerateContainer.cs index 42ab2772..079a3c06 100644 --- a/Main/GenerateContainer.cs +++ b/Main/GenerateContainer.cs @@ -9,89 +9,57 @@ namespace MrMeeseeks.DIE { internal interface IContainerGenerator { - void Generate(AttributeData attributeData); + void Generate(INamedTypeSymbol containerClass); } - internal class ContainerGenrator : IContainerGenerator + internal class ContainerGenerator : IContainerGenerator { - private readonly GeneratorExecutionContext context; - private readonly IDiagLogger diagLogger; - private readonly ITypeToImplementationsMapper typeToImplementationMapper; + private readonly GeneratorExecutionContext _context; + private readonly IDiagLogger _diagLogger; + private readonly WellKnownTypes _wellKnownTypes; + private readonly ITypeToImplementationsMapper _typeToImplementationsMapper; - public ContainerGenrator( + public ContainerGenerator( GeneratorExecutionContext context, IDiagLogger diagLogger, - ITypeToImplementationsMapper typeToImplementationMapper) + WellKnownTypes wellKnownTypes, + ITypeToImplementationsMapper typeToImplementationsMapper) { - this.context = context; - this.diagLogger = diagLogger; - this.typeToImplementationMapper = typeToImplementationMapper; + _context = context; + _diagLogger = diagLogger; + _wellKnownTypes = wellKnownTypes; + _typeToImplementationsMapper = typeToImplementationsMapper; } - public void Generate(AttributeData attributeData) + public void Generate(INamedTypeSymbol containerClass) { - var countConstructorArguments = attributeData.ConstructorArguments.Length; - if (countConstructorArguments is not 1) + var namedTypeSymbol = containerClass.AllInterfaces.Single(x => x.OriginalDefinition.Equals(_wellKnownTypes.Container, SymbolEqualityComparer.Default)); + _diagLogger.Log($"Interface type {namedTypeSymbol.FullName()}"); + var typeParameterSymbol = namedTypeSymbol.TypeArguments.Single(); + _diagLogger.Log($"Generic type {typeParameterSymbol.FullName()}"); + if (typeParameterSymbol is not INamedTypeSymbol { } type + || type.IsUnboundGenericType + || !type.IsAccessibleInternally()) { - // Invalid code, ignore + _diagLogger.Log($"return generation"); return; } - var typeConstant = attributeData.ConstructorArguments[0]; - if (typeConstant.Kind != TypedConstantKind.Type) - { - // Invalid code, ignore - return; - } - if (!CheckValidType(typeConstant, out var type)) - { - return; - } - var id = -1; - var stack = new Stack(); - - var containerClassName = $"{type.Name}Container"; - - var typeToInject = typeToImplementationMapper.Map(type).First(); - - stack.Push(new DependencyWrapper(ResolutionStage.Prefix, ++id, type, typeToInject, new List())); + var typeToInject = _typeToImplementationsMapper.Map(type).First(); var generatedContainer = new StringBuilder() .AppendLine($"namespace MrMeeseeks.DIE") .AppendLine($"{{") - .AppendLine($" internal class {containerClassName}") - .AppendLine($" {{") - .AppendLine($" public {type.FullName()} Resolve()") - .AppendLine($" {{"); + .AppendLine($" internal partial class {containerClass.Name}") + .AppendLine($" {{"); - while (stack.Any()) - { - var subject = stack.Pop(); - if (subject is { ResolutionStage: ResolutionStage.Prefix }) - { - var parameterIds = new List(); - stack.Push(subject with { ResolutionStage = ResolutionStage.Postfix, ParameterIds = parameterIds }); - var ctor = subject.ImplementationType.Constructors.First(); - foreach (var parameter in ctor.Parameters.Select(p => p.Type)) - { - var namedParameter = (INamedTypeSymbol)parameter; - var typeToInjectParameter = typeToImplementationMapper.Map(namedParameter).First(); - var parameterWrapper = new DependencyWrapper(ResolutionStage.Prefix, ++id, namedParameter, typeToInjectParameter, new List()); - stack.Push(parameterWrapper); - parameterIds.Add(parameterWrapper.Id); - } - } - else if (subject is { ResolutionStage: ResolutionStage.Postfix }) - { - generatedContainer = generatedContainer - .AppendLine($" var _{subject.Id} = new {subject.ImplementationType.FullName()}({string.Join(", ", subject.ParameterIds.Select(id => $"_{id}"))});") - ; - }//*/ - } + generatedContainer = GenerateResolveFunction(generatedContainer, type, typeToInject, _typeToImplementationsMapper); generatedContainer = generatedContainer .AppendLine($" return _0;") - .AppendLine($" }}") + .AppendLine($" }}"); + + generatedContainer = generatedContainer .AppendLine($" }}") .AppendLine($"}}") ; @@ -102,23 +70,50 @@ public void Generate(AttributeData attributeData) .NormalizeWhitespace() .SyntaxTree .GetText(); - context.AddSource($"{type.Name}.g.cs", containerSource); - } + _context.AddSource($"{type.Name}.g.cs", containerSource); - private bool CheckValidType(TypedConstant typedConstant, out INamedTypeSymbol type) - { - type = (typedConstant.Value as INamedTypeSymbol)!; - if (typedConstant.Value is null) - return false; - if (type.IsOrReferencesErrorType()) - // we will report an error for this case anyway. - return false; - if (type.IsUnboundGenericType) - return false; - if (!type.IsAccessibleInternally()) - return false; + static StringBuilder GenerateResolveFunction( + StringBuilder stringBuilder, + INamedTypeSymbol namedTypeSymbol, + INamedTypeSymbol typeToInject, + ITypeToImplementationsMapper typeToImplementationsMapper) + { + stringBuilder = stringBuilder + .AppendLine($" public {namedTypeSymbol.FullName()} Resolve()") + .AppendLine($" {{"); + + var id = -1; + var stack = new Stack(); + stack.Push(new DependencyWrapper(ResolutionStage.Prefix, ++id, namedTypeSymbol, typeToInject, new List())); + while (stack.Any()) + { + var subject = stack.Pop(); + if (subject is { ResolutionStage: ResolutionStage.Prefix }) + { + var parameterIds = new List(); + stack.Push(subject with { ResolutionStage = ResolutionStage.Postfix, ParameterIds = parameterIds }); + var ctor = subject.ImplementationType.Constructors.First(); + foreach (var parameter in ctor.Parameters.Select(p => p.Type)) + { + var namedParameter = (INamedTypeSymbol)parameter; + var typeToInjectParameter = typeToImplementationsMapper.Map(namedParameter).First(); + var parameterWrapper = new DependencyWrapper(ResolutionStage.Prefix, ++id, namedParameter, + typeToInjectParameter, new List()); + stack.Push(parameterWrapper); + parameterIds.Add(parameterWrapper.Id); + } + } + else if (subject is { ResolutionStage: ResolutionStage.Postfix }) + { + stringBuilder = stringBuilder + .AppendLine( + $" var _{subject.Id} = new {subject.ImplementationType.FullName()}({string.Join(", ", subject.ParameterIds.Select(id => $"_{id}"))});") + ; + } + } - return true; + return stringBuilder; + } } } } diff --git a/Main/GetAllImplementations.cs b/Main/GetAllImplementations.cs index ca311c63..8196aeb5 100644 --- a/Main/GetAllImplementations.cs +++ b/Main/GetAllImplementations.cs @@ -14,15 +14,15 @@ internal interface IGetAllImplementations internal class GetAllImplementations : IGetAllImplementations { - private GeneratorExecutionContext context; + private GeneratorExecutionContext _context; public GetAllImplementations(GeneratorExecutionContext context) { - this.context = context; + _context = context; } - public IReadOnlyList AllImplementations => new ReadOnlyCollection(context.Compilation.SyntaxTrees - .Select(st => (st, context.Compilation.GetSemanticModel(st))) + public IReadOnlyList AllImplementations => new ReadOnlyCollection(_context.Compilation.SyntaxTrees + .Select(st => (st, _context.Compilation.GetSemanticModel(st))) .SelectMany(t => t.st .GetRoot() .DescendantNodesAndSelf() diff --git a/Main/IContainer.cs b/Main/IContainer.cs new file mode 100644 index 00000000..f646ccb0 --- /dev/null +++ b/Main/IContainer.cs @@ -0,0 +1,6 @@ +namespace MrMeeseeks.DIE +{ + public partial interface IContainer + { + } +} diff --git a/Main/InitializeImpl.cs b/Main/InitializeImpl.cs index cd22cda6..07e3d2d4 100644 --- a/Main/InitializeImpl.cs +++ b/Main/InitializeImpl.cs @@ -10,17 +10,17 @@ internal interface IInitialize internal class InitializeImpl : IInitialize { - private readonly GeneratorInitializationContext context; - private readonly Func syntaxReceiverFactory; + private readonly GeneratorInitializationContext _context; + private readonly Func _syntaxReceiverFactory; public InitializeImpl( GeneratorInitializationContext context, Func syntaxReceiverFactory) { - this.context = context; - this.syntaxReceiverFactory = syntaxReceiverFactory; + _context = context; + _syntaxReceiverFactory = syntaxReceiverFactory; } - public void Initialize() => context.RegisterForSyntaxNotifications(() => syntaxReceiverFactory()); + public void Initialize() => _context.RegisterForSyntaxNotifications(() => _syntaxReceiverFactory()); } } diff --git a/Main/Main.csproj b/Main/Main.csproj index 64844e4c..fecb057f 100644 --- a/Main/Main.csproj +++ b/Main/Main.csproj @@ -7,7 +7,7 @@ $(RootNamespace) true - true + true @@ -23,14 +23,14 @@ - - - + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - diff --git a/Main/Properties/launchSettings.json b/Main/Properties/launchSettings.json index 048ecac2..622b6d1b 100644 --- a/Main/Properties/launchSettings.json +++ b/Main/Properties/launchSettings.json @@ -1,8 +1,7 @@ { "profiles": { "Main": { - "commandName": "DebugRoslynComponent", - "targetProject": "..\\Sample\\Sample.csproj" + "commandName": "Executable" } } } \ No newline at end of file diff --git a/Main/RoslynExtensions.cs b/Main/RoslynExtensions.cs index fc75dede..f1fb0ba6 100644 --- a/Main/RoslynExtensions.cs +++ b/Main/RoslynExtensions.cs @@ -1,11 +1,16 @@ -using System.Linq; +using System; +using System.Linq; using Microsoft.CodeAnalysis; namespace MrMeeseeks.DIE { internal static class RoslynExtensions { - + public static INamedTypeSymbol? GetTypeOrReport(this Compilation compilation, string metadataName) + { + var typeSymbol = compilation.GetTypeByMetadataName(metadataName); + return typeSymbol; + } // Picked from https://github.com/YairHalberstadt/stronginject Thank you! public static bool IsOrReferencesErrorType(this ITypeSymbol type) { diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index 15eb9981..5132ea46 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -17,8 +17,9 @@ public void Execute(GeneratorExecutionContext context) var diagLogger = new DiagLogger(context); var getAllImplementations = new GetAllImplementations(context); var typeToImplementationMapper = new TypeToImplementationsMapper(getAllImplementations); - var containerGenerator = new ContainerGenrator(context, diagLogger, typeToImplementationMapper); - new ExecuteImpl(context, containerGenerator, diagLogger).Execute(); + var _ = WellKnownTypes.TryCreate(context.Compilation, out var wellKnownTypes); + var containerGenerator = new ContainerGenerator(context, diagLogger, wellKnownTypes, typeToImplementationMapper); + new ExecuteImpl(context, wellKnownTypes, containerGenerator, diagLogger).Execute(); } } } diff --git a/Main/TypeToImplementationMapper.cs b/Main/TypeToImplementationMapper.cs index f61dc9e9..18db0687 100644 --- a/Main/TypeToImplementationMapper.cs +++ b/Main/TypeToImplementationMapper.cs @@ -11,11 +11,11 @@ internal interface ITypeToImplementationsMapper internal class TypeToImplementationsMapper : ITypeToImplementationsMapper { - private readonly Dictionary> map; + private readonly Dictionary> _map; public TypeToImplementationsMapper( IGetAllImplementations getAllImplementations) => - map = getAllImplementations + _map = getAllImplementations .AllImplementations .SelectMany(i => { @@ -26,7 +26,7 @@ public TypeToImplementationsMapper( public IList Map(INamedTypeSymbol typeSymbol) { - if(map.TryGetValue(typeSymbol, out var implementations)) + if(_map.TryGetValue(typeSymbol, out var implementations)) { return implementations; } diff --git a/Main/WellKnownTypes.cs b/Main/WellKnownTypes.cs new file mode 100644 index 00000000..03bdd8df --- /dev/null +++ b/Main/WellKnownTypes.cs @@ -0,0 +1,48 @@ +using Microsoft.CodeAnalysis; + +namespace MrMeeseeks.DIE +{ + internal record WellKnownTypes( + INamedTypeSymbol Container, + INamedTypeSymbol Disposable, + INamedTypeSymbol AsyncDisposable, + INamedTypeSymbol ValueTask, + INamedTypeSymbol ValueTask1, + INamedTypeSymbol Task1, + INamedTypeSymbol ObjectDisposedException) + { + public static bool TryCreate(Compilation compilation, out WellKnownTypes wellKnownTypes) + { + var iContainer = compilation.GetTypeOrReport("MrMeeseeks.DIE.IContainer`1"); + var iDisposable = compilation.GetTypeOrReport("System.IDisposable"); + var iAsyncDisposable = compilation.GetTypeOrReport("System.IAsyncDisposable"); + var valueTask = compilation.GetTypeOrReport("System.Threading.Tasks.ValueTask"); + var valueTask1 = compilation.GetTypeOrReport("System.Threading.Tasks.ValueTask`1"); + var task1 = compilation.GetTypeOrReport("System.Threading.Tasks.Task`1"); + var objectDisposedException = compilation.GetTypeOrReport("System.ObjectDisposedException"); + + if (iContainer is null + || iDisposable is null + || iAsyncDisposable is null + || valueTask is null + || valueTask1 is null + || task1 is null + || objectDisposedException is null) + { + wellKnownTypes = null!; + return false; + } + + wellKnownTypes = new WellKnownTypes( + Container: iContainer, + Disposable: iDisposable, + AsyncDisposable: iAsyncDisposable, + ValueTask: valueTask, + ValueTask1: valueTask1, + Task1: task1, + ObjectDisposedException: objectDisposedException); + + return true; + } + } +} \ No newline at end of file diff --git a/Sample/AssemblyInfo.cs b/Sample/AssemblyInfo.cs deleted file mode 100644 index 7422f4b1..00000000 --- a/Sample/AssemblyInfo.cs +++ /dev/null @@ -1,4 +0,0 @@ -using MrMeeseeks.DIE.Sample; -using MrMeeseeks.StaticDelegateGenerator; - -[assembly: Container(typeof(IContext))] \ No newline at end of file diff --git a/Sample/Container.cs b/Sample/Container.cs new file mode 100644 index 00000000..7e134dbb --- /dev/null +++ b/Sample/Container.cs @@ -0,0 +1,8 @@ +using MrMeeseeks.DIE; + +namespace MrMeeseeks.DIE.Sample +{ + public partial class Container : IContainer + { + } +} diff --git a/Sample/Context.cs b/Sample/Context.cs index d7e8aedf..c735c8a1 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -1,5 +1,4 @@ using System; -using MrMeeseeks.DIE.SampleChild; namespace MrMeeseeks.DIE.Sample { @@ -11,7 +10,7 @@ internal interface IContext internal class Context : IContext { public String Text => "Hello, world"; - public Context(IChild child) + public Context()//IChild child) { } diff --git a/Spy/DiagLogger.cs b/Spy/DiagLogger.cs index a22ea859..462b44e1 100644 --- a/Spy/DiagLogger.cs +++ b/Spy/DiagLogger.cs @@ -11,17 +11,17 @@ internal interface IDiagLogger internal class DiagLogger : IDiagLogger { - private readonly GeneratorExecutionContext context; + private readonly GeneratorExecutionContext _context; public DiagLogger( GeneratorExecutionContext context) { - this.context = context; + _context = context; } public void Log(int id, string title, string message, string category, DiagnosticSeverity diagnosticSeverity) { - context.ReportDiagnostic(Diagnostic.Create( + _context.ReportDiagnostic(Diagnostic.Create( new DiagnosticDescriptor($"DIESPY{id.ToString().PadLeft(3, '0')}", title, message, category, diagnosticSeverity, true), Location.None)); } diff --git a/Spy/ExecuteImpl.cs b/Spy/ExecuteImpl.cs index d1ac63f7..7e9a2c34 100644 --- a/Spy/ExecuteImpl.cs +++ b/Spy/ExecuteImpl.cs @@ -9,28 +9,28 @@ internal interface IExecute internal class ExecuteImpl : IExecute { - private readonly GeneratorExecutionContext context; - private readonly IContainerGenerator containerGenerator; - private readonly IDiagLogger diagLogger; + private readonly GeneratorExecutionContext _context; + private readonly IContainerGenerator _containerGenerator; + private readonly IDiagLogger _diagLogger; public ExecuteImpl( GeneratorExecutionContext context, IContainerGenerator containerGenerator, IDiagLogger diagLogger) { - this.context = context; - this.containerGenerator = containerGenerator; - this.diagLogger = diagLogger; + _context = context; + _containerGenerator = containerGenerator; + _diagLogger = diagLogger; } public void Execute() { - diagLogger.Log(0, "Start Execute"); + _diagLogger.Log(0, "Start Execute"); - containerGenerator.Generate( - context.Compilation.Assembly.Name); + _containerGenerator.Generate( + _context.Compilation.Assembly.Name); - diagLogger.Log(2, "End Execute"); + _diagLogger.Log(2, "End Execute"); } } } diff --git a/Spy/GenerateContainer.cs b/Spy/GenerateContainer.cs index cdf54dc8..ca495bcc 100644 --- a/Spy/GenerateContainer.cs +++ b/Spy/GenerateContainer.cs @@ -13,15 +13,15 @@ internal interface IContainerGenerator internal class ContainerGenerator : IContainerGenerator { - private readonly GeneratorExecutionContext context; - private readonly IGetAllImplementations getAllImplementations; + private readonly GeneratorExecutionContext _context; + private readonly IGetAllImplementations _getAllImplementations; public ContainerGenerator( GeneratorExecutionContext context, IGetAllImplementations getAllImplementations) { - this.context = context; - this.getAllImplementations = getAllImplementations; + _context = context; + _getAllImplementations = getAllImplementations; } public void Generate(string namespaceName) @@ -34,7 +34,7 @@ public void Generate(string namespaceName) ; var i = -1; - foreach (var type in getAllImplementations.AllImplementations.Where(t => t.DeclaredAccessibility == Accessibility.Public)) + foreach (var type in _getAllImplementations.AllImplementations.Where(t => t.DeclaredAccessibility == Accessibility.Public)) { generatedContainer = generatedContainer .AppendLine($" public {type.FullName()} Type{++i} {{ get; }}") @@ -48,7 +48,7 @@ public void Generate(string namespaceName) ; i = -1; - foreach (var type in getAllImplementations.AllImplementations.Where(t => t.DeclaredAccessibility == Accessibility.Internal)) + foreach (var type in _getAllImplementations.AllImplementations.Where(t => t.DeclaredAccessibility == Accessibility.Internal)) { generatedContainer = generatedContainer .AppendLine($" internal {type.FullName()} Type{++i} {{ get; }}") @@ -66,7 +66,7 @@ public void Generate(string namespaceName) .NormalizeWhitespace() .SyntaxTree .GetText(); - context.AddSource($"PublicTypes.g.cs", containerSource); + _context.AddSource($"PublicTypes.g.cs", containerSource); } } } diff --git a/Spy/GetAllImplementations.cs b/Spy/GetAllImplementations.cs index 27a6593f..44d2f076 100644 --- a/Spy/GetAllImplementations.cs +++ b/Spy/GetAllImplementations.cs @@ -14,15 +14,15 @@ internal interface IGetAllImplementations internal class GetAllImplementations : IGetAllImplementations { - private GeneratorExecutionContext context; + private GeneratorExecutionContext _context; public GetAllImplementations(GeneratorExecutionContext context) { - this.context = context; + _context = context; } - public IReadOnlyList AllImplementations => new ReadOnlyCollection(context.Compilation.SyntaxTrees - .Select(st => (st, context.Compilation.GetSemanticModel(st))) + public IReadOnlyList AllImplementations => new ReadOnlyCollection(_context.Compilation.SyntaxTrees + .Select(st => (st, _context.Compilation.GetSemanticModel(st))) .SelectMany(t => t.st .GetRoot() .DescendantNodesAndSelf() diff --git a/Spy/InitializeImpl.cs b/Spy/InitializeImpl.cs index 482ff9a6..297b77dd 100644 --- a/Spy/InitializeImpl.cs +++ b/Spy/InitializeImpl.cs @@ -10,17 +10,17 @@ internal interface IInitialize internal class InitializeImpl : IInitialize { - private readonly GeneratorInitializationContext context; - private readonly Func syntaxReceiverFactory; + private readonly GeneratorInitializationContext _context; + private readonly Func _syntaxReceiverFactory; public InitializeImpl( GeneratorInitializationContext context, Func syntaxReceiverFactory) { - this.context = context; - this.syntaxReceiverFactory = syntaxReceiverFactory; + _context = context; + _syntaxReceiverFactory = syntaxReceiverFactory; } - public void Initialize() => context.RegisterForSyntaxNotifications(() => syntaxReceiverFactory()); + public void Initialize() => _context.RegisterForSyntaxNotifications(() => _syntaxReceiverFactory()); } } diff --git a/Spy/Spy.csproj b/Spy/Spy.csproj index a57191b7..c9f01e3f 100644 --- a/Spy/Spy.csproj +++ b/Spy/Spy.csproj @@ -24,7 +24,7 @@ - + all From d32d0c103479ae101375de233500427e9a810185 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sat, 25 Sep 2021 14:28:21 +0200 Subject: [PATCH 006/162] Collect type information from the spies --- Main/GetAllImplementations.cs | 3 +- Main/GetAssemblyAttributes.cs | 24 +++++++ Main/SourceGenerator.cs | 3 +- .../SpyAttribute.cs | 12 ++-- Main/TypeToImplementationMapper.cs | 72 +++++++++++++++++-- Main/WellKnownTypes.cs | 6 ++ Sample/Container.cs | 3 + Sample/Context.cs | 3 +- SampleChild/AssemblyInfo.cs | 3 + SampleChild/Child.cs | 2 + Spy/DependencyWrapper.cs | 18 ----- Spy/DiagLogger.cs | 14 ++-- Spy/ExecuteImpl.cs | 4 +- Spy/GetAllImplementations.cs | 1 - Spy/InitializeImpl.cs | 26 ------- Spy/IsExternalInit.cs | 6 -- Spy/RoslynExtensions.cs | 40 +---------- Spy/SourceGenerator.cs | 13 ++-- Spy/SyntaxReceiver.cs | 19 ----- 19 files changed, 128 insertions(+), 144 deletions(-) create mode 100644 Main/GetAssemblyAttributes.cs rename Spy/ContainerAttribute.cs => Main/SpyAttribute.cs (51%) create mode 100644 SampleChild/AssemblyInfo.cs delete mode 100644 Spy/DependencyWrapper.cs delete mode 100644 Spy/InitializeImpl.cs delete mode 100644 Spy/IsExternalInit.cs delete mode 100644 Spy/SyntaxReceiver.cs diff --git a/Main/GetAllImplementations.cs b/Main/GetAllImplementations.cs index 8196aeb5..c19d0c06 100644 --- a/Main/GetAllImplementations.cs +++ b/Main/GetAllImplementations.cs @@ -1,6 +1,5 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; -using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; @@ -14,7 +13,7 @@ internal interface IGetAllImplementations internal class GetAllImplementations : IGetAllImplementations { - private GeneratorExecutionContext _context; + private readonly GeneratorExecutionContext _context; public GetAllImplementations(GeneratorExecutionContext context) { diff --git a/Main/GetAssemblyAttributes.cs b/Main/GetAssemblyAttributes.cs new file mode 100644 index 00000000..f45b1eb0 --- /dev/null +++ b/Main/GetAssemblyAttributes.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; +using System.Collections.ObjectModel; +using Microsoft.CodeAnalysis; + +namespace MrMeeseeks.DIE +{ + public interface IGetAssemblyAttributes + { + IReadOnlyList AllAssemblyAttributes { get; } + } + + internal class GetAssemblyAttributes : IGetAssemblyAttributes + { + private readonly GeneratorExecutionContext _context; + + public GetAssemblyAttributes(GeneratorExecutionContext context) + { + _context = context; + } + + public IReadOnlyList AllAssemblyAttributes => new ReadOnlyCollection( + _context.Compilation.Assembly.GetAttributes()); + } +} \ No newline at end of file diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index 5132ea46..aea97648 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -16,8 +16,9 @@ public void Execute(GeneratorExecutionContext context) { var diagLogger = new DiagLogger(context); var getAllImplementations = new GetAllImplementations(context); - var typeToImplementationMapper = new TypeToImplementationsMapper(getAllImplementations); + var getAssemblyAttributes = new GetAssemblyAttributes(context); var _ = WellKnownTypes.TryCreate(context.Compilation, out var wellKnownTypes); + var typeToImplementationMapper = new TypeToImplementationsMapper(wellKnownTypes, diagLogger, getAllImplementations, getAssemblyAttributes); var containerGenerator = new ContainerGenerator(context, diagLogger, wellKnownTypes, typeToImplementationMapper); new ExecuteImpl(context, wellKnownTypes, containerGenerator, diagLogger).Execute(); } diff --git a/Spy/ContainerAttribute.cs b/Main/SpyAttribute.cs similarity index 51% rename from Spy/ContainerAttribute.cs rename to Main/SpyAttribute.cs index 36c03a7b..01675cc5 100644 --- a/Spy/ContainerAttribute.cs +++ b/Main/SpyAttribute.cs @@ -1,13 +1,11 @@ -using System; +using System; -namespace MrMeeseeks.DIE.Spy +namespace MrMeeseeks.DIE { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] - public class ContainerAttribute : Attribute + public class SpyAttribute : Attribute { // ReSharper disable once UnusedParameter.Local *** Is used in the generator - public ContainerAttribute(Type type) - { - } + public SpyAttribute(params Type[] type) {} } -} +} \ No newline at end of file diff --git a/Main/TypeToImplementationMapper.cs b/Main/TypeToImplementationMapper.cs index 18db0687..153caec1 100644 --- a/Main/TypeToImplementationMapper.cs +++ b/Main/TypeToImplementationMapper.cs @@ -1,5 +1,7 @@ -using Microsoft.CodeAnalysis; +using System; +using Microsoft.CodeAnalysis; using System.Collections.Generic; +using System.Collections.Immutable; using System.Linq; namespace MrMeeseeks.DIE @@ -14,16 +16,74 @@ internal class TypeToImplementationsMapper : ITypeToImplementationsMapper private readonly Dictionary> _map; public TypeToImplementationsMapper( - IGetAllImplementations getAllImplementations) => + WellKnownTypes wellKnownTypes, + IDiagLogger diagLogger, + IGetAllImplementations getAllImplementations, + IGetAssemblyAttributes getAssemblyAttributes) + { + _map = getAllImplementations .AllImplementations - .SelectMany(i => - { - return i.AllInterfaces.Select(ii => (ii, i)).Prepend((i, i)); - }) + .Concat(GetSpiedImplementations()) + .SelectMany(i => { return i.AllInterfaces.Select(ii => (ii, i)).Prepend((i, i)); }) .GroupBy(t => t.Item1, t => t.Item2) .ToDictionary(g => g.Key, g => g.ToList()); + IEnumerable GetSpiedImplementations() => getAssemblyAttributes + .AllAssemblyAttributes + .Where(ad => + ad.AttributeClass?.Equals(wellKnownTypes.SpyAttribute, SymbolEqualityComparer.Default) ?? false) + .SelectMany(ad => + { + var countConstructorArguments = ad.ConstructorArguments.Length; + if (countConstructorArguments is not 1) + { + // Invalid code, ignore + return ImmutableArray.Create(); + } + + var typeConstant = ad.ConstructorArguments[0]; + if (typeConstant.Kind != TypedConstantKind.Array) + { + // Invalid code, ignore + return ImmutableArray.Create(); + } + + return typeConstant.Values; + }) + .Select(tc => + { + if (!CheckValidType(tc, out var type)) + { + return null; + } + + return type; + }) + .Where(t => t is not null) + .OfType() + .SelectMany(t => t.GetMembers() + .OfType() + .Select(p => p.Type) + .OfType()); + + bool CheckValidType(TypedConstant typedConstant, out INamedTypeSymbol type) + { + type = (typedConstant.Value as INamedTypeSymbol)!; + if (typedConstant.Value is null) + return false; + if (type.IsOrReferencesErrorType()) + // we will report an error for this case anyway. + return false; + if (type.IsUnboundGenericType) + return false; + if (!type.IsAccessibleInternally()) + return false; + + return true; + } + } + public IList Map(INamedTypeSymbol typeSymbol) { if(_map.TryGetValue(typeSymbol, out var implementations)) diff --git a/Main/WellKnownTypes.cs b/Main/WellKnownTypes.cs index 03bdd8df..87bfcd97 100644 --- a/Main/WellKnownTypes.cs +++ b/Main/WellKnownTypes.cs @@ -4,6 +4,7 @@ namespace MrMeeseeks.DIE { internal record WellKnownTypes( INamedTypeSymbol Container, + INamedTypeSymbol SpyAttribute, INamedTypeSymbol Disposable, INamedTypeSymbol AsyncDisposable, INamedTypeSymbol ValueTask, @@ -21,7 +22,11 @@ public static bool TryCreate(Compilation compilation, out WellKnownTypes wellKno var task1 = compilation.GetTypeOrReport("System.Threading.Tasks.Task`1"); var objectDisposedException = compilation.GetTypeOrReport("System.ObjectDisposedException"); + var spyAttribute = compilation + .GetTypeByMetadataName(typeof(SpyAttribute).FullName ?? ""); + if (iContainer is null + || spyAttribute is null || iDisposable is null || iAsyncDisposable is null || valueTask is null @@ -35,6 +40,7 @@ public static bool TryCreate(Compilation compilation, out WellKnownTypes wellKno wellKnownTypes = new WellKnownTypes( Container: iContainer, + SpyAttribute: spyAttribute, Disposable: iDisposable, AsyncDisposable: iAsyncDisposable, ValueTask: valueTask, diff --git a/Sample/Container.cs b/Sample/Container.cs index 7e134dbb..c66a0efd 100644 --- a/Sample/Container.cs +++ b/Sample/Container.cs @@ -1,4 +1,7 @@ using MrMeeseeks.DIE; +using SampleChild; + +[assembly:Spy(typeof(PublicTypes), typeof(InternalTypes))] namespace MrMeeseeks.DIE.Sample { diff --git a/Sample/Context.cs b/Sample/Context.cs index c735c8a1..d7e8aedf 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -1,4 +1,5 @@ using System; +using MrMeeseeks.DIE.SampleChild; namespace MrMeeseeks.DIE.Sample { @@ -10,7 +11,7 @@ internal interface IContext internal class Context : IContext { public String Text => "Hello, world"; - public Context()//IChild child) + public Context(IChild child) { } diff --git a/SampleChild/AssemblyInfo.cs b/SampleChild/AssemblyInfo.cs new file mode 100644 index 00000000..8a25a86d --- /dev/null +++ b/SampleChild/AssemblyInfo.cs @@ -0,0 +1,3 @@ +using System.Runtime.CompilerServices; + +[assembly:InternalsVisibleTo("Sample")] \ No newline at end of file diff --git a/SampleChild/Child.cs b/SampleChild/Child.cs index 03817639..5f05d9a5 100644 --- a/SampleChild/Child.cs +++ b/SampleChild/Child.cs @@ -5,5 +5,7 @@ public interface IChild public class Child : IChild { + internal Child( + IInternalChild innerChild){} } } diff --git a/Spy/DependencyWrapper.cs b/Spy/DependencyWrapper.cs deleted file mode 100644 index b2102049..00000000 --- a/Spy/DependencyWrapper.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Microsoft.CodeAnalysis; -using System.Collections.Generic; - -namespace MrMeeseeks.DIE.Spy -{ - internal enum ResolutionStage - { - Prefix, - Postfix - } - - internal record DependencyWrapper( - ResolutionStage ResolutionStage, - int Id, - INamedTypeSymbol InjectedType, - INamedTypeSymbol ImplementationType, - IReadOnlyList ParameterIds); -} diff --git a/Spy/DiagLogger.cs b/Spy/DiagLogger.cs index 462b44e1..a652115e 100644 --- a/Spy/DiagLogger.cs +++ b/Spy/DiagLogger.cs @@ -4,9 +4,7 @@ namespace MrMeeseeks.DIE.Spy { internal interface IDiagLogger { - void Log(int id, string message); - - void Log(int id, string title, string message, string category, DiagnosticSeverity diagnosticSeverity); + void Log(string message); } internal class DiagLogger : IDiagLogger @@ -19,13 +17,11 @@ public DiagLogger( _context = context; } - public void Log(int id, string title, string message, string category, DiagnosticSeverity diagnosticSeverity) - { + private void Log(int id, string title, string message, string category, DiagnosticSeverity diagnosticSeverity) => _context.ReportDiagnostic(Diagnostic.Create( - new DiagnosticDescriptor($"DIESPY{id.ToString().PadLeft(3, '0')}", title, message, category, diagnosticSeverity, true), - Location.None)); - } + new DiagnosticDescriptor($"DIESPY{id.ToString().PadLeft(3, '0')}", title, message, category, diagnosticSeverity, true), + Location.None)); - public void Log(int id, string message) => Log(id, "INFO", message, "INFO", DiagnosticSeverity.Warning); + public void Log(string message) => Log(0, "INFO", message, "INFO", DiagnosticSeverity.Warning); } } diff --git a/Spy/ExecuteImpl.cs b/Spy/ExecuteImpl.cs index 7e9a2c34..90da1596 100644 --- a/Spy/ExecuteImpl.cs +++ b/Spy/ExecuteImpl.cs @@ -25,12 +25,12 @@ public ExecuteImpl( public void Execute() { - _diagLogger.Log(0, "Start Execute"); + _diagLogger.Log("Start Execute"); _containerGenerator.Generate( _context.Compilation.Assembly.Name); - _diagLogger.Log(2, "End Execute"); + _diagLogger.Log("End Execute"); } } } diff --git a/Spy/GetAllImplementations.cs b/Spy/GetAllImplementations.cs index 44d2f076..0750365f 100644 --- a/Spy/GetAllImplementations.cs +++ b/Spy/GetAllImplementations.cs @@ -1,6 +1,5 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; -using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; diff --git a/Spy/InitializeImpl.cs b/Spy/InitializeImpl.cs deleted file mode 100644 index 297b77dd..00000000 --- a/Spy/InitializeImpl.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Microsoft.CodeAnalysis; -using System; - -namespace MrMeeseeks.DIE.Spy -{ - internal interface IInitialize - { - void Initialize(); - } - - internal class InitializeImpl : IInitialize - { - private readonly GeneratorInitializationContext _context; - private readonly Func _syntaxReceiverFactory; - - public InitializeImpl( - GeneratorInitializationContext context, - Func syntaxReceiverFactory) - { - _context = context; - _syntaxReceiverFactory = syntaxReceiverFactory; - } - - public void Initialize() => _context.RegisterForSyntaxNotifications(() => _syntaxReceiverFactory()); - } -} diff --git a/Spy/IsExternalInit.cs b/Spy/IsExternalInit.cs deleted file mode 100644 index df783a36..00000000 --- a/Spy/IsExternalInit.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace System.Runtime.CompilerServices -{ - public class IsExternalInit - { - } -} diff --git a/Spy/RoslynExtensions.cs b/Spy/RoslynExtensions.cs index 8b5f9e71..dfb56889 100644 --- a/Spy/RoslynExtensions.cs +++ b/Spy/RoslynExtensions.cs @@ -1,43 +1,9 @@ -using System.Linq; -using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis; namespace MrMeeseeks.DIE.Spy { internal static class RoslynExtensions { - - // Picked from https://github.com/YairHalberstadt/stronginject Thank you! - public static bool IsOrReferencesErrorType(this ITypeSymbol type) - { - if (!type.ContainingType?.IsOrReferencesErrorType() ?? false) - return false; - return type switch - { - IErrorTypeSymbol => true, - IArrayTypeSymbol array => array.ElementType.IsOrReferencesErrorType(), - IPointerTypeSymbol pointer => pointer.PointedAtType.IsOrReferencesErrorType(), - INamedTypeSymbol named => !named.IsUnboundGenericType && named.TypeArguments.Any(IsOrReferencesErrorType), - _ => false, - }; - } - - // Picked from https://github.com/YairHalberstadt/stronginject Thank you! - public static bool IsAccessibleInternally(this ITypeSymbol type) - { - if (type is ITypeParameterSymbol) - return true; - if (!type.ContainingType?.IsAccessibleInternally() ?? false) - return false; - return type switch - { - IArrayTypeSymbol array => array.ElementType.IsAccessibleInternally(), - IPointerTypeSymbol pointer => pointer.PointedAtType.IsAccessibleInternally(), - INamedTypeSymbol named => named.DeclaredAccessibility is Accessibility.Public or Accessibility.ProtectedOrInternal or Accessibility.Internal - && named.TypeArguments.All(IsAccessibleInternally), - _ => false, - }; - } - // Picked from https://github.com/YairHalberstadt/stronginject Thank you! public static string FullName(this ITypeSymbol type) => type.ToDisplayString(new SymbolDisplayFormat( @@ -46,9 +12,5 @@ public static string FullName(this ITypeSymbol type) => genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters, parameterOptions: SymbolDisplayParameterOptions.IncludeType | SymbolDisplayParameterOptions.IncludeParamsRefOut, memberOptions: SymbolDisplayMemberOptions.IncludeRef)); - - // Picked from https://github.com/YairHalberstadt/stronginject Thank you! - public static string FullName(this INamespaceSymbol @namespace) => - @namespace.ToDisplayString(new SymbolDisplayFormat(typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces)); } } \ No newline at end of file diff --git a/Spy/SourceGenerator.cs b/Spy/SourceGenerator.cs index 59376449..474bdd3e 100644 --- a/Spy/SourceGenerator.cs +++ b/Spy/SourceGenerator.cs @@ -1,5 +1,4 @@ using Microsoft.CodeAnalysis; -using System; namespace MrMeeseeks.DIE.Spy { @@ -8,16 +7,16 @@ public class SourceGenerator : ISourceGenerator { public void Initialize(GeneratorInitializationContext context) { - Func syntaxReceiverFactory = () => new SyntaxReceiver(); - new InitializeImpl(context, syntaxReceiverFactory).Initialize(); } public void Execute(GeneratorExecutionContext context) { - var diagLogger = new DiagLogger(context); - var getAllImplementations = new GetAllImplementations(context); - var containerGenerator = new ContainerGenerator(context, getAllImplementations); - new ExecuteImpl(context, containerGenerator, diagLogger).Execute(); + IDiagLogger diagLogger = new DiagLogger(context); + IGetAllImplementations getAllImplementations = new GetAllImplementations(context); + IContainerGenerator containerGenerator = new ContainerGenerator(context, getAllImplementations); + IExecute execute = new ExecuteImpl(context, containerGenerator, diagLogger); + + execute.Execute(); } } } diff --git a/Spy/SyntaxReceiver.cs b/Spy/SyntaxReceiver.cs deleted file mode 100644 index 32f3cc46..00000000 --- a/Spy/SyntaxReceiver.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using System.Collections.Generic; - -namespace MrMeeseeks.DIE.Spy -{ - internal class SyntaxReceiver : ISyntaxReceiver - { - public List Candidates { get; } = new(); - - public void OnVisitSyntaxNode(SyntaxNode syntaxNode) - { - if (syntaxNode is ClassDeclarationSyntax classDeclarationSyntax) - { - Candidates.Add(classDeclarationSyntax); - } - } - } -} From 90f42cd46f266552f22e750f0c7cc51fb7141f03 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sat, 2 Oct 2021 14:37:52 +0200 Subject: [PATCH 007/162] Splitting creation of resolution tree and generation of the container code based upon it. --- Main/ContainerAttribute.cs | 13 ----- Main/ContainerInfo.cs | 44 +++++++++++++++ Main/DependencyWrapper.cs | 15 ++++++ Main/ExecuteImpl.cs | 23 +++++--- Main/GenerateContainer.cs | 96 ++++++++++++--------------------- Main/ResolutionTreeFactory.cs | 54 +++++++++++++++++++ Main/SourceGenerator.cs | 7 ++- Sample/Container.cs | 2 +- Sample/Context.cs | 6 +-- Sample/Program.cs | 9 +++- Sample/Sample.csproj | 1 + Sample/StrongInjectContainer.cs | 13 +++++ SampleChild/Child.cs | 2 +- SampleChild/InternalChild.cs | 2 +- 14 files changed, 194 insertions(+), 93 deletions(-) delete mode 100644 Main/ContainerAttribute.cs create mode 100644 Main/ContainerInfo.cs create mode 100644 Main/ResolutionTreeFactory.cs create mode 100644 Sample/StrongInjectContainer.cs diff --git a/Main/ContainerAttribute.cs b/Main/ContainerAttribute.cs deleted file mode 100644 index d68449ba..00000000 --- a/Main/ContainerAttribute.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; - -namespace MrMeeseeks.StaticDelegateGenerator -{ - [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] - public class ContainerAttribute : Attribute - { - // ReSharper disable once UnusedParameter.Local *** Is used in the generator - public ContainerAttribute(Type type) - { - } - } -} diff --git a/Main/ContainerInfo.cs b/Main/ContainerInfo.cs new file mode 100644 index 00000000..945f773b --- /dev/null +++ b/Main/ContainerInfo.cs @@ -0,0 +1,44 @@ +using System.Linq; +using Microsoft.CodeAnalysis; + +namespace MrMeeseeks.DIE +{ + public interface IContainerInfo + { + string Name { get; } + string Namespace { get; } + bool IsValid { get; } + INamedTypeSymbol? ResolutionRootType { get; } + } + + internal class ContainerInfo : IContainerInfo + { + public ContainerInfo( + // parameters + INamedTypeSymbol containerClass, + + // dependencies + WellKnownTypes wellKnowTypes) + { + Name = containerClass.Name; + Namespace = containerClass.ContainingNamespace.FullName(); + + var namedTypeSymbol = containerClass.AllInterfaces.Single(x => x.OriginalDefinition.Equals(wellKnowTypes.Container, SymbolEqualityComparer.Default)); + var typeParameterSymbol = namedTypeSymbol.TypeArguments.Single(); + if (typeParameterSymbol is INamedTypeSymbol { IsUnboundGenericType: false } type && type.IsAccessibleInternally()) + { + ResolutionRootType = type; + IsValid = true; + } + else + { + IsValid = false; + } + } + + public string Name { get; } + public string Namespace { get; } + public bool IsValid { get; } + public INamedTypeSymbol? ResolutionRootType { get; } + } +} \ No newline at end of file diff --git a/Main/DependencyWrapper.cs b/Main/DependencyWrapper.cs index 21e32891..9f2a44ff 100644 --- a/Main/DependencyWrapper.cs +++ b/Main/DependencyWrapper.cs @@ -14,5 +14,20 @@ internal record DependencyWrapper( int Id, INamedTypeSymbol InjectedType, INamedTypeSymbol ImplementationType, + string ImplementationTypeFullName, IReadOnlyList ParameterIds); + + internal abstract record ResolutionBase( + string Reference, + string TypeFullName); + + internal record InterfaceResolution( + string Reference, + string TypeFullName, + ResolutionBase Dependency) : ResolutionBase(Reference, TypeFullName); + + internal record ConstructorResolution( + string Reference, + string TypeFullName, + IReadOnlyList Dependencies) : ResolutionBase(Reference, TypeFullName); } diff --git a/Main/ExecuteImpl.cs b/Main/ExecuteImpl.cs index f6f9f49e..23867cc0 100644 --- a/Main/ExecuteImpl.cs +++ b/Main/ExecuteImpl.cs @@ -1,6 +1,6 @@ -using Microsoft.CodeAnalysis; +using System; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; -using MrMeeseeks.StaticDelegateGenerator; using System.Linq; namespace MrMeeseeks.DIE @@ -15,27 +15,29 @@ internal class ExecuteImpl : IExecute private readonly GeneratorExecutionContext _context; private readonly WellKnownTypes _wellKnownTypes; private readonly IContainerGenerator _containerGenerator; + private readonly IResolutionTreeFactory _resolutionTreeFactory; + private readonly Func _containerInfoFactory; private readonly IDiagLogger _diagLogger; public ExecuteImpl( GeneratorExecutionContext context, WellKnownTypes wellKnownTypes, IContainerGenerator containerGenerator, + IResolutionTreeFactory resolutionTreeFactory, + Func containerInfoFactory, IDiagLogger diagLogger) { _context = context; _wellKnownTypes = wellKnownTypes; _containerGenerator = containerGenerator; + _resolutionTreeFactory = resolutionTreeFactory; + _containerInfoFactory = containerInfoFactory; _diagLogger = diagLogger; } public void Execute() { _diagLogger.Log("Start Execute"); - if (_context - .Compilation - .GetTypeByMetadataName(typeof(ContainerAttribute).FullName ?? "") is not { } attributeType) - return; foreach (var syntaxTree in _context.Compilation.SyntaxTrees) { var semanticModel = _context.Compilation.GetSemanticModel(syntaxTree); @@ -49,8 +51,13 @@ public void Execute() .Where(x => x.AllInterfaces.Any(x => x.OriginalDefinition.Equals(_wellKnownTypes.Container, SymbolEqualityComparer.Default))); foreach (var namedTypeSymbol in containerClasses) { - _diagLogger.Log($"Container type {namedTypeSymbol.Name}"); - _containerGenerator.Generate(namedTypeSymbol); + var containerInfo = _containerInfoFactory(namedTypeSymbol); + if (containerInfo.IsValid && containerInfo.ResolutionRootType is { }) + { + var resolutionRoot = _resolutionTreeFactory.Create(containerInfo.ResolutionRootType); + _containerGenerator.Generate(containerInfo, resolutionRoot); + } + else throw new NotImplementedException("Handle non-valid container information"); } } diff --git a/Main/GenerateContainer.cs b/Main/GenerateContainer.cs index 079a3c06..6326d1e9 100644 --- a/Main/GenerateContainer.cs +++ b/Main/GenerateContainer.cs @@ -1,4 +1,5 @@ -using Microsoft.CodeAnalysis; +using System; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Text; using System.Collections.Generic; @@ -9,58 +10,46 @@ namespace MrMeeseeks.DIE { internal interface IContainerGenerator { - void Generate(INamedTypeSymbol containerClass); + void Generate(IContainerInfo containerInfo, ResolutionBase resolutionBase); } internal class ContainerGenerator : IContainerGenerator { private readonly GeneratorExecutionContext _context; private readonly IDiagLogger _diagLogger; - private readonly WellKnownTypes _wellKnownTypes; - private readonly ITypeToImplementationsMapper _typeToImplementationsMapper; public ContainerGenerator( GeneratorExecutionContext context, - IDiagLogger diagLogger, - WellKnownTypes wellKnownTypes, - ITypeToImplementationsMapper typeToImplementationsMapper) + IDiagLogger diagLogger) { _context = context; _diagLogger = diagLogger; - _wellKnownTypes = wellKnownTypes; - _typeToImplementationsMapper = typeToImplementationsMapper; } - public void Generate(INamedTypeSymbol containerClass) + public void Generate(IContainerInfo containerInfo, ResolutionBase resolutionBase) { - var namedTypeSymbol = containerClass.AllInterfaces.Single(x => x.OriginalDefinition.Equals(_wellKnownTypes.Container, SymbolEqualityComparer.Default)); - _diagLogger.Log($"Interface type {namedTypeSymbol.FullName()}"); - var typeParameterSymbol = namedTypeSymbol.TypeArguments.Single(); - _diagLogger.Log($"Generic type {typeParameterSymbol.FullName()}"); - if (typeParameterSymbol is not INamedTypeSymbol { } type - || type.IsUnboundGenericType - || !type.IsAccessibleInternally()) + if (!containerInfo.IsValid || containerInfo.ResolutionRootType is null) { _diagLogger.Log($"return generation"); return; } - - var typeToInject = _typeToImplementationsMapper.Map(type).First(); - + var generatedContainer = new StringBuilder() - .AppendLine($"namespace MrMeeseeks.DIE") + .AppendLine($"namespace {containerInfo.Namespace}") + .AppendLine($"{{") + .AppendLine($"partial class {containerInfo.Name}") .AppendLine($"{{") - .AppendLine($" internal partial class {containerClass.Name}") - .AppendLine($" {{"); + .AppendLine($"public {resolutionBase.TypeFullName} Resolve()") + .AppendLine($"{{"); - generatedContainer = GenerateResolveFunction(generatedContainer, type, typeToInject, _typeToImplementationsMapper); + generatedContainer = GenerateResolveFunctionAlternative(generatedContainer, resolutionBase); generatedContainer = generatedContainer - .AppendLine($" return _0;") - .AppendLine($" }}"); + .AppendLine($"return {resolutionBase.Reference};") + .AppendLine($"}}"); generatedContainer = generatedContainer - .AppendLine($" }}") + .AppendLine($"}}") .AppendLine($"}}") ; @@ -70,46 +59,29 @@ public void Generate(INamedTypeSymbol containerClass) .NormalizeWhitespace() .SyntaxTree .GetText(); - _context.AddSource($"{type.Name}.g.cs", containerSource); + _context.AddSource($"{containerInfo.Namespace}.{containerInfo.Name}.g.cs", containerSource); - static StringBuilder GenerateResolveFunction( - StringBuilder stringBuilder, - INamedTypeSymbol namedTypeSymbol, - INamedTypeSymbol typeToInject, - ITypeToImplementationsMapper typeToImplementationsMapper) + static StringBuilder GenerateResolveFunctionAlternative( + StringBuilder stringBuilder, + ResolutionBase resolution) { - stringBuilder = stringBuilder - .AppendLine($" public {namedTypeSymbol.FullName()} Resolve()") - .AppendLine($" {{"); - - var id = -1; - var stack = new Stack(); - stack.Push(new DependencyWrapper(ResolutionStage.Prefix, ++id, namedTypeSymbol, typeToInject, new List())); - while (stack.Any()) + switch (resolution) { - var subject = stack.Pop(); - if (subject is { ResolutionStage: ResolutionStage.Prefix }) - { - var parameterIds = new List(); - stack.Push(subject with { ResolutionStage = ResolutionStage.Postfix, ParameterIds = parameterIds }); - var ctor = subject.ImplementationType.Constructors.First(); - foreach (var parameter in ctor.Parameters.Select(p => p.Type)) + case InterfaceResolution interfaceResolution: + stringBuilder = GenerateResolveFunctionAlternative(stringBuilder, interfaceResolution.Dependency); + stringBuilder = stringBuilder.AppendLine( + $"var {interfaceResolution.Reference} = ({interfaceResolution.TypeFullName}) {interfaceResolution.Dependency.Reference};"); + break; + case ConstructorResolution constructorResolution: + foreach (var parameterResolution in constructorResolution.Dependencies) { - var namedParameter = (INamedTypeSymbol)parameter; - var typeToInjectParameter = typeToImplementationsMapper.Map(namedParameter).First(); - var parameterWrapper = new DependencyWrapper(ResolutionStage.Prefix, ++id, namedParameter, - typeToInjectParameter, new List()); - stack.Push(parameterWrapper); - parameterIds.Add(parameterWrapper.Id); + stringBuilder = GenerateResolveFunctionAlternative(stringBuilder, parameterResolution); } - } - else if (subject is { ResolutionStage: ResolutionStage.Postfix }) - { - stringBuilder = stringBuilder - .AppendLine( - $" var _{subject.Id} = new {subject.ImplementationType.FullName()}({string.Join(", ", subject.ParameterIds.Select(id => $"_{id}"))});") - ; - } + stringBuilder = stringBuilder.AppendLine( + $"var {constructorResolution.Reference} = new {constructorResolution.TypeFullName}({string.Join(", ", constructorResolution.Dependencies.Select(d => d.Reference))});"); + break; + default: + throw new Exception("Unexpected case or not implemented."); } return stringBuilder; diff --git a/Main/ResolutionTreeFactory.cs b/Main/ResolutionTreeFactory.cs new file mode 100644 index 00000000..fd9528c8 --- /dev/null +++ b/Main/ResolutionTreeFactory.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using Microsoft.CodeAnalysis; + +namespace MrMeeseeks.DIE +{ + internal interface IResolutionTreeFactory + { + ResolutionBase Create(INamedTypeSymbol root); + } + + internal class ResolutionTreeFactory : IResolutionTreeFactory + { + private readonly ITypeToImplementationsMapper _typeToImplementationsMapper; + private int _id = -1; + + public ResolutionTreeFactory( + ITypeToImplementationsMapper typeToImplementationsMapper) + { + _typeToImplementationsMapper = typeToImplementationsMapper; + } + + public ResolutionBase Create(INamedTypeSymbol type) + { + if (type.TypeKind == TypeKind.Interface) + { + var implementationType = _typeToImplementationsMapper + .Map(type) + .FirstOrDefault() ?? throw new NotImplementedException("What if several possible implementations exist"); + return new InterfaceResolution( + $"_{++_id}", + type.FullName(), + Create(implementationType)); + } + if (type.TypeKind == TypeKind.Class) + { + var implementationType = _typeToImplementationsMapper + .Map(type) + .FirstOrDefault() ?? throw new NotImplementedException("What if several possible implementations exist"); + var constructor = implementationType.Constructors.FirstOrDefault() + ?? throw new NotImplementedException("What if no constructor exists or several possible constructors exist"); + return new ConstructorResolution( + $"_{++_id}", + implementationType.FullName(), + new ReadOnlyCollection( + constructor.Parameters.Select(p => Create(p.Type as INamedTypeSymbol ?? throw new NotImplementedException("What if parameter type is not INamedTypeSymbol?"))).ToList())); + } + + throw new NotImplementedException("What if type neither interface nor class"); + } + } +} \ No newline at end of file diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index aea97648..ce1f7e37 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -19,8 +19,11 @@ public void Execute(GeneratorExecutionContext context) var getAssemblyAttributes = new GetAssemblyAttributes(context); var _ = WellKnownTypes.TryCreate(context.Compilation, out var wellKnownTypes); var typeToImplementationMapper = new TypeToImplementationsMapper(wellKnownTypes, diagLogger, getAllImplementations, getAssemblyAttributes); - var containerGenerator = new ContainerGenerator(context, diagLogger, wellKnownTypes, typeToImplementationMapper); - new ExecuteImpl(context, wellKnownTypes, containerGenerator, diagLogger).Execute(); + var containerGenerator = new ContainerGenerator(context, diagLogger); + var resolutionTreeFactory = new ResolutionTreeFactory(typeToImplementationMapper); + new ExecuteImpl(context, wellKnownTypes, containerGenerator, resolutionTreeFactory, ContainerInfoFactory, diagLogger).Execute(); + + IContainerInfo ContainerInfoFactory(INamedTypeSymbol type) => new ContainerInfo(type, wellKnownTypes); } } } diff --git a/Sample/Container.cs b/Sample/Container.cs index c66a0efd..0693e9e9 100644 --- a/Sample/Container.cs +++ b/Sample/Container.cs @@ -5,7 +5,7 @@ namespace MrMeeseeks.DIE.Sample { - public partial class Container : IContainer + internal partial class Container : IContainer { } } diff --git a/Sample/Context.cs b/Sample/Context.cs index d7e8aedf..dce63b69 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -5,13 +5,13 @@ namespace MrMeeseeks.DIE.Sample { internal interface IContext { - String Text { get; } + string Text { get; } } internal class Context : IContext { - public String Text => "Hello, world"; - public Context(IChild child) + public string Text => "Hello, world!"; + public Context(Child child) { } diff --git a/Sample/Program.cs b/Sample/Program.cs index 3227255b..4d11aef8 100644 --- a/Sample/Program.cs +++ b/Sample/Program.cs @@ -1,2 +1,7 @@ -System.Console.WriteLine("Hello, world!"); -//System.Console.WriteLine(new MrMeeseeks.DIE.IContextContainer().Resolve().Text); +using MrMeeseeks.DIE.Sample; +using StrongInject; + +System.Console.WriteLine("Hello, world!"); +System.Console.WriteLine(new Container().Resolve().Text); +System.Console.WriteLine(new StrongInjectContainer().Run(c => c.Text)); + diff --git a/Sample/Sample.csproj b/Sample/Sample.csproj index 760c1b1e..0f8770f7 100644 --- a/Sample/Sample.csproj +++ b/Sample/Sample.csproj @@ -14,6 +14,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/Sample/StrongInjectContainer.cs b/Sample/StrongInjectContainer.cs new file mode 100644 index 00000000..ab4e37b2 --- /dev/null +++ b/Sample/StrongInjectContainer.cs @@ -0,0 +1,13 @@ +using MrMeeseeks.DIE.SampleChild; +using StrongInject; + +namespace MrMeeseeks.DIE.Sample +{ + [Register(typeof(Context), typeof(IContext))] + [Register(typeof(Child), typeof(Child), typeof(IChild))] + [Register(typeof(InternalChild), typeof(IInternalChild))] + internal partial class StrongInjectContainer : StrongInject.IContainer + { + + } +} \ No newline at end of file diff --git a/SampleChild/Child.cs b/SampleChild/Child.cs index 5f05d9a5..90e7becf 100644 --- a/SampleChild/Child.cs +++ b/SampleChild/Child.cs @@ -5,7 +5,7 @@ public interface IChild public class Child : IChild { - internal Child( + public Child( IInternalChild innerChild){} } } diff --git a/SampleChild/InternalChild.cs b/SampleChild/InternalChild.cs index 6109b58a..b8cbe7d8 100644 --- a/SampleChild/InternalChild.cs +++ b/SampleChild/InternalChild.cs @@ -1,6 +1,6 @@ namespace MrMeeseeks.DIE.SampleChild { - internal interface IInternalChild + public interface IInternalChild {} internal class InternalChild : IInternalChild { From 67507af234f3e0c6e838178cc4708a74a11da832 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sun, 3 Oct 2021 09:13:33 +0200 Subject: [PATCH 008/162] Minor adjustments --- Main/DependencyWrapper.cs | 19 ++------------ Main/GenerateContainer.cs | 45 ++++++++++++++++++++++++--------- Main/ResolutionTreeFactory.cs | 16 +++++++++--- Sample/Context.cs | 2 +- Sample/StrongInjectContainer.cs | 2 ++ 5 files changed, 50 insertions(+), 34 deletions(-) diff --git a/Main/DependencyWrapper.cs b/Main/DependencyWrapper.cs index 9f2a44ff..397028aa 100644 --- a/Main/DependencyWrapper.cs +++ b/Main/DependencyWrapper.cs @@ -1,22 +1,7 @@ -using Microsoft.CodeAnalysis; -using System.Collections.Generic; +using System.Collections.Generic; namespace MrMeeseeks.DIE { - internal enum ResolutionStage - { - Prefix, - Postfix - } - - internal record DependencyWrapper( - ResolutionStage ResolutionStage, - int Id, - INamedTypeSymbol InjectedType, - INamedTypeSymbol ImplementationType, - string ImplementationTypeFullName, - IReadOnlyList ParameterIds); - internal abstract record ResolutionBase( string Reference, string TypeFullName); @@ -29,5 +14,5 @@ internal record InterfaceResolution( internal record ConstructorResolution( string Reference, string TypeFullName, - IReadOnlyList Dependencies) : ResolutionBase(Reference, TypeFullName); + IReadOnlyList<(string name, ResolutionBase Dependency)> Parameter) : ResolutionBase(Reference, TypeFullName); } diff --git a/Main/GenerateContainer.cs b/Main/GenerateContainer.cs index 6326d1e9..a38874eb 100644 --- a/Main/GenerateContainer.cs +++ b/Main/GenerateContainer.cs @@ -2,7 +2,6 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Text; -using System.Collections.Generic; using System.Linq; using System.Text; @@ -42,7 +41,9 @@ public void Generate(IContainerInfo containerInfo, ResolutionBase resolutionBase .AppendLine($"public {resolutionBase.TypeFullName} Resolve()") .AppendLine($"{{"); - generatedContainer = GenerateResolveFunctionAlternative(generatedContainer, resolutionBase); + generatedContainer = GenerateResolveFunctionFields(generatedContainer, resolutionBase); + + generatedContainer = GenerateResolveFunction(generatedContainer, resolutionBase); generatedContainer = generatedContainer .AppendLine($"return {resolutionBase.Reference};") @@ -61,24 +62,44 @@ public void Generate(IContainerInfo containerInfo, ResolutionBase resolutionBase .GetText(); _context.AddSource($"{containerInfo.Namespace}.{containerInfo.Name}.g.cs", containerSource); - static StringBuilder GenerateResolveFunctionAlternative( + static StringBuilder GenerateResolveFunctionFields( + StringBuilder stringBuilder, + ResolutionBase resolution) + { + switch (resolution) + { + case InterfaceResolution(var reference, var typeFullName, var resolutionBase): + stringBuilder = GenerateResolveFunctionFields(stringBuilder, resolutionBase); + stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); + break; + case ConstructorResolution(var reference, var typeFullName, var parameters): + stringBuilder = parameters.Aggregate(stringBuilder, + (builder, tuple) => GenerateResolveFunctionFields(builder, tuple.Dependency)); + stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); + break; + default: + throw new Exception("Unexpected case or not implemented."); + } + + return stringBuilder; + } + + static StringBuilder GenerateResolveFunction( StringBuilder stringBuilder, ResolutionBase resolution) { switch (resolution) { - case InterfaceResolution interfaceResolution: - stringBuilder = GenerateResolveFunctionAlternative(stringBuilder, interfaceResolution.Dependency); + case InterfaceResolution(var reference, var typeFullName, var resolutionBase): + stringBuilder = GenerateResolveFunction(stringBuilder, resolutionBase); stringBuilder = stringBuilder.AppendLine( - $"var {interfaceResolution.Reference} = ({interfaceResolution.TypeFullName}) {interfaceResolution.Dependency.Reference};"); + $"{reference} = ({typeFullName}) {resolutionBase.Reference};"); break; - case ConstructorResolution constructorResolution: - foreach (var parameterResolution in constructorResolution.Dependencies) - { - stringBuilder = GenerateResolveFunctionAlternative(stringBuilder, parameterResolution); - } + case ConstructorResolution(var reference, var typeFullName, var parameters): + stringBuilder = parameters.Aggregate(stringBuilder, + (builder, tuple) => GenerateResolveFunction(builder, tuple.Dependency)); stringBuilder = stringBuilder.AppendLine( - $"var {constructorResolution.Reference} = new {constructorResolution.TypeFullName}({string.Join(", ", constructorResolution.Dependencies.Select(d => d.Reference))});"); + $"{reference} = new {typeFullName}({string.Join(", ", parameters.Select(d => $"{d.name}: {d.Dependency.Reference}"))});"); break; default: throw new Exception("Unexpected case or not implemented."); diff --git a/Main/ResolutionTreeFactory.cs b/Main/ResolutionTreeFactory.cs index fd9528c8..909964d0 100644 --- a/Main/ResolutionTreeFactory.cs +++ b/Main/ResolutionTreeFactory.cs @@ -30,7 +30,7 @@ public ResolutionBase Create(INamedTypeSymbol type) .Map(type) .FirstOrDefault() ?? throw new NotImplementedException("What if several possible implementations exist"); return new InterfaceResolution( - $"_{++_id}", + GenerateReference(type.Name), type.FullName(), Create(implementationType)); } @@ -41,14 +41,22 @@ public ResolutionBase Create(INamedTypeSymbol type) .FirstOrDefault() ?? throw new NotImplementedException("What if several possible implementations exist"); var constructor = implementationType.Constructors.FirstOrDefault() ?? throw new NotImplementedException("What if no constructor exists or several possible constructors exist"); + return new ConstructorResolution( - $"_{++_id}", + GenerateReference(implementationType.Name), implementationType.FullName(), - new ReadOnlyCollection( - constructor.Parameters.Select(p => Create(p.Type as INamedTypeSymbol ?? throw new NotImplementedException("What if parameter type is not INamedTypeSymbol?"))).ToList())); + new ReadOnlyCollection<(string Name, ResolutionBase Dependency)>(constructor + .Parameters + .Select(p => ( + p.Name, + Create(p.Type as INamedTypeSymbol + ?? throw new NotImplementedException("What if parameter type is not INamedTypeSymbol?")))) + .ToList())); } throw new NotImplementedException("What if type neither interface nor class"); + + string GenerateReference(string name) => $"{char.ToLower(name[0])}{name.Substring(1)}_0_{++_id}"; } } } \ No newline at end of file diff --git a/Sample/Context.cs b/Sample/Context.cs index dce63b69..653ac179 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -11,7 +11,7 @@ internal interface IContext internal class Context : IContext { public string Text => "Hello, world!"; - public Context(Child child) + public Context(IChild child)//Lazy child) { } diff --git a/Sample/StrongInjectContainer.cs b/Sample/StrongInjectContainer.cs index ab4e37b2..22c7071d 100644 --- a/Sample/StrongInjectContainer.cs +++ b/Sample/StrongInjectContainer.cs @@ -1,11 +1,13 @@ using MrMeeseeks.DIE.SampleChild; using StrongInject; +using StrongInject.Modules; namespace MrMeeseeks.DIE.Sample { [Register(typeof(Context), typeof(IContext))] [Register(typeof(Child), typeof(Child), typeof(IChild))] [Register(typeof(InternalChild), typeof(IInternalChild))] + [RegisterModule(typeof(StandardModule))] internal partial class StrongInjectContainer : StrongInject.IContainer { From 17067678ea811b6c10f4d0ace2b7e2d78f30ece5 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sun, 3 Oct 2021 12:47:35 +0200 Subject: [PATCH 009/162] Implemented support for Lazy --- Main/DependencyWrapper.cs | 5 ++++ Main/GenerateContainer.cs | 38 +++++++++++++++++++------- Main/ReferenceGenerator.cs | 40 +++++++++++++++++++++++++++ Main/ResolutionTreeFactory.cs | 51 +++++++++++++++++++++++++++-------- Main/SourceGenerator.cs | 9 ++++--- Main/WellKnownTypes.cs | 4 +++ Sample/Context.cs | 2 +- Sample/Program.cs | 2 +- 8 files changed, 126 insertions(+), 25 deletions(-) create mode 100644 Main/ReferenceGenerator.cs diff --git a/Main/DependencyWrapper.cs b/Main/DependencyWrapper.cs index 397028aa..a2a49ea7 100644 --- a/Main/DependencyWrapper.cs +++ b/Main/DependencyWrapper.cs @@ -15,4 +15,9 @@ internal record ConstructorResolution( string Reference, string TypeFullName, IReadOnlyList<(string name, ResolutionBase Dependency)> Parameter) : ResolutionBase(Reference, TypeFullName); + + internal record FuncResolution( + string Reference, + string TypeFullName, + ResolutionBase Dependency) : ResolutionBase(Reference, TypeFullName); } diff --git a/Main/GenerateContainer.cs b/Main/GenerateContainer.cs index a38874eb..8dea3056 100644 --- a/Main/GenerateContainer.cs +++ b/Main/GenerateContainer.cs @@ -41,9 +41,7 @@ public void Generate(IContainerInfo containerInfo, ResolutionBase resolutionBase .AppendLine($"public {resolutionBase.TypeFullName} Resolve()") .AppendLine($"{{"); - generatedContainer = GenerateResolveFunctionFields(generatedContainer, resolutionBase); - - generatedContainer = GenerateResolveFunction(generatedContainer, resolutionBase); + generatedContainer = GenerateResolutionFunction(generatedContainer, resolutionBase); generatedContainer = generatedContainer .AppendLine($"return {resolutionBase.Reference};") @@ -62,19 +60,34 @@ public void Generate(IContainerInfo containerInfo, ResolutionBase resolutionBase .GetText(); _context.AddSource($"{containerInfo.Namespace}.{containerInfo.Name}.g.cs", containerSource); - static StringBuilder GenerateResolveFunctionFields( + + + static StringBuilder GenerateResolutionFunction( + StringBuilder stringBuilder, + ResolutionBase resolution) + { + stringBuilder = GenerateFields(stringBuilder, resolution); + stringBuilder = GenerateResolutions(stringBuilder, resolution); + + return stringBuilder; + } + + static StringBuilder GenerateFields( StringBuilder stringBuilder, ResolutionBase resolution) { switch (resolution) { case InterfaceResolution(var reference, var typeFullName, var resolutionBase): - stringBuilder = GenerateResolveFunctionFields(stringBuilder, resolutionBase); + stringBuilder = GenerateFields(stringBuilder, resolutionBase); stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); break; case ConstructorResolution(var reference, var typeFullName, var parameters): stringBuilder = parameters.Aggregate(stringBuilder, - (builder, tuple) => GenerateResolveFunctionFields(builder, tuple.Dependency)); + (builder, tuple) => GenerateFields(builder, tuple.Dependency)); + stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); + break; + case FuncResolution(var reference, var typeFullName, _): stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); break; default: @@ -84,23 +97,30 @@ static StringBuilder GenerateResolveFunctionFields( return stringBuilder; } - static StringBuilder GenerateResolveFunction( + static StringBuilder GenerateResolutions( StringBuilder stringBuilder, ResolutionBase resolution) { switch (resolution) { case InterfaceResolution(var reference, var typeFullName, var resolutionBase): - stringBuilder = GenerateResolveFunction(stringBuilder, resolutionBase); + stringBuilder = GenerateResolutions(stringBuilder, resolutionBase); stringBuilder = stringBuilder.AppendLine( $"{reference} = ({typeFullName}) {resolutionBase.Reference};"); break; case ConstructorResolution(var reference, var typeFullName, var parameters): stringBuilder = parameters.Aggregate(stringBuilder, - (builder, tuple) => GenerateResolveFunction(builder, tuple.Dependency)); + (builder, tuple) => GenerateResolutions(builder, tuple.Dependency)); stringBuilder = stringBuilder.AppendLine( $"{reference} = new {typeFullName}({string.Join(", ", parameters.Select(d => $"{d.name}: {d.Dependency.Reference}"))});"); break; + case FuncResolution(var reference, var typeFullName, var resolutionBase): + stringBuilder = stringBuilder.AppendLine($"{reference} = () =>"); + stringBuilder = stringBuilder.AppendLine($"{{"); + GenerateResolutionFunction(stringBuilder, resolutionBase); + stringBuilder = stringBuilder.AppendLine($"return {resolutionBase.Reference};"); + stringBuilder = stringBuilder.AppendLine($"}};"); + break; default: throw new Exception("Unexpected case or not implemented."); } diff --git a/Main/ReferenceGenerator.cs b/Main/ReferenceGenerator.cs new file mode 100644 index 00000000..d121a497 --- /dev/null +++ b/Main/ReferenceGenerator.cs @@ -0,0 +1,40 @@ +using System; +using Microsoft.CodeAnalysis; + +namespace MrMeeseeks.DIE +{ + public interface IReferenceGenerator + { + string Generate(INamedTypeSymbol type); + string Generate(string hardcodedName); + } + + internal class ReferenceGenerator : IReferenceGenerator + { + private int _i = -1; + private readonly int _j; + + public ReferenceGenerator(int j) => _j = j; + + public string Generate(INamedTypeSymbol type) => + Generate($"{char.ToLower(type.Name[0])}{type.Name.Substring(1)}"); + + public string Generate(string hardcodedName) => + $"{hardcodedName}_{_j}_{++_i}"; + } + + public interface IReferenceGeneratorFactory + { + IReferenceGenerator Create(); + } + + internal class ReferenceGeneratorFactory : IReferenceGeneratorFactory + { + private readonly Func _referenceGeneratorFactory; + private int _j = -1; + + public ReferenceGeneratorFactory(Func referenceGeneratorFactory) => _referenceGeneratorFactory = referenceGeneratorFactory; + + public IReferenceGenerator Create() => _referenceGeneratorFactory(++_j); + } +} \ No newline at end of file diff --git a/Main/ResolutionTreeFactory.cs b/Main/ResolutionTreeFactory.cs index 909964d0..b54a4144 100644 --- a/Main/ResolutionTreeFactory.cs +++ b/Main/ResolutionTreeFactory.cs @@ -14,49 +14,78 @@ internal interface IResolutionTreeFactory internal class ResolutionTreeFactory : IResolutionTreeFactory { private readonly ITypeToImplementationsMapper _typeToImplementationsMapper; - private int _id = -1; + private readonly IReferenceGeneratorFactory _referenceGeneratorFactory; + private readonly WellKnownTypes _wellKnownTypes; public ResolutionTreeFactory( - ITypeToImplementationsMapper typeToImplementationsMapper) + ITypeToImplementationsMapper typeToImplementationsMapper, + IReferenceGeneratorFactory referenceGeneratorFactory, + WellKnownTypes wellKnownTypes) { _typeToImplementationsMapper = typeToImplementationsMapper; + _referenceGeneratorFactory = referenceGeneratorFactory; + _wellKnownTypes = wellKnownTypes; } + + public ResolutionBase Create(INamedTypeSymbol type) => Create(type, _referenceGeneratorFactory.Create()); - public ResolutionBase Create(INamedTypeSymbol type) + private ResolutionBase Create(INamedTypeSymbol type, IReferenceGenerator referenceGenerator) { if (type.TypeKind == TypeKind.Interface) { var implementationType = _typeToImplementationsMapper .Map(type) - .FirstOrDefault() ?? throw new NotImplementedException("What if several possible implementations exist"); + .FirstOrDefault() ?? throw new NotImplementedException($"What if several possible implementations exist (interface;{type.FullName()})"); return new InterfaceResolution( - GenerateReference(type.Name), + referenceGenerator.Generate(type), type.FullName(), - Create(implementationType)); + Create(implementationType, referenceGenerator)); } + + if (type.OriginalDefinition.Equals(_wellKnownTypes.Lazy1, SymbolEqualityComparer.Default)) + { + var genericType = type.TypeArguments.FirstOrDefault() as INamedTypeSymbol ?? + throw new NotImplementedException("What if not castable?"); + + var dependency = Create(genericType, _referenceGeneratorFactory.Create()); + return new ConstructorResolution( + referenceGenerator.Generate(type), + type.FullName(), + new ReadOnlyCollection<(string Name, ResolutionBase Dependency)>( + new List<(string Name, ResolutionBase Dependency)> + { + ( + "valueFactory", + new FuncResolution( + referenceGenerator.Generate("func"), + $"global::System.Func<{genericType.FullName()}>", + dependency) + ) + })); + } + if (type.TypeKind == TypeKind.Class) { var implementationType = _typeToImplementationsMapper .Map(type) - .FirstOrDefault() ?? throw new NotImplementedException("What if several possible implementations exist"); + .FirstOrDefault() ?? throw new NotImplementedException($"What if several possible implementations exist (class;{type.FullName()})"); var constructor = implementationType.Constructors.FirstOrDefault() ?? throw new NotImplementedException("What if no constructor exists or several possible constructors exist"); return new ConstructorResolution( - GenerateReference(implementationType.Name), + referenceGenerator.Generate(implementationType), implementationType.FullName(), new ReadOnlyCollection<(string Name, ResolutionBase Dependency)>(constructor .Parameters .Select(p => ( p.Name, Create(p.Type as INamedTypeSymbol - ?? throw new NotImplementedException("What if parameter type is not INamedTypeSymbol?")))) + ?? throw new NotImplementedException("What if parameter type is not INamedTypeSymbol?"), + referenceGenerator))) .ToList())); } throw new NotImplementedException("What if type neither interface nor class"); - - string GenerateReference(string name) => $"{char.ToLower(name[0])}{name.Substring(1)}_0_{++_id}"; } } } \ No newline at end of file diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index ce1f7e37..4aaa3987 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -8,8 +8,9 @@ public class SourceGenerator : ISourceGenerator { public void Initialize(GeneratorInitializationContext context) { - Func syntaxReceiverFactory = () => new SyntaxReceiver(); - new InitializeImpl(context, syntaxReceiverFactory).Initialize(); + new InitializeImpl(context, SyntaxReceiverFactory).Initialize(); + + ISyntaxReceiver SyntaxReceiverFactory() => new SyntaxReceiver(); } public void Execute(GeneratorExecutionContext context) @@ -20,10 +21,12 @@ public void Execute(GeneratorExecutionContext context) var _ = WellKnownTypes.TryCreate(context.Compilation, out var wellKnownTypes); var typeToImplementationMapper = new TypeToImplementationsMapper(wellKnownTypes, diagLogger, getAllImplementations, getAssemblyAttributes); var containerGenerator = new ContainerGenerator(context, diagLogger); - var resolutionTreeFactory = new ResolutionTreeFactory(typeToImplementationMapper); + var referenceGeneratorFactory = new ReferenceGeneratorFactory(ReferenceGeneratorFactory); + var resolutionTreeFactory = new ResolutionTreeFactory(typeToImplementationMapper, referenceGeneratorFactory, wellKnownTypes); new ExecuteImpl(context, wellKnownTypes, containerGenerator, resolutionTreeFactory, ContainerInfoFactory, diagLogger).Execute(); IContainerInfo ContainerInfoFactory(INamedTypeSymbol type) => new ContainerInfo(type, wellKnownTypes); + IReferenceGenerator ReferenceGeneratorFactory(int j) => new ReferenceGenerator(j); } } } diff --git a/Main/WellKnownTypes.cs b/Main/WellKnownTypes.cs index 87bfcd97..b9600c73 100644 --- a/Main/WellKnownTypes.cs +++ b/Main/WellKnownTypes.cs @@ -7,6 +7,7 @@ internal record WellKnownTypes( INamedTypeSymbol SpyAttribute, INamedTypeSymbol Disposable, INamedTypeSymbol AsyncDisposable, + INamedTypeSymbol Lazy1, INamedTypeSymbol ValueTask, INamedTypeSymbol ValueTask1, INamedTypeSymbol Task1, @@ -17,6 +18,7 @@ public static bool TryCreate(Compilation compilation, out WellKnownTypes wellKno var iContainer = compilation.GetTypeOrReport("MrMeeseeks.DIE.IContainer`1"); var iDisposable = compilation.GetTypeOrReport("System.IDisposable"); var iAsyncDisposable = compilation.GetTypeOrReport("System.IAsyncDisposable"); + var lazy1 = compilation.GetTypeOrReport("System.Lazy`1"); var valueTask = compilation.GetTypeOrReport("System.Threading.Tasks.ValueTask"); var valueTask1 = compilation.GetTypeOrReport("System.Threading.Tasks.ValueTask`1"); var task1 = compilation.GetTypeOrReport("System.Threading.Tasks.Task`1"); @@ -29,6 +31,7 @@ public static bool TryCreate(Compilation compilation, out WellKnownTypes wellKno || spyAttribute is null || iDisposable is null || iAsyncDisposable is null + || lazy1 is null || valueTask is null || valueTask1 is null || task1 is null @@ -43,6 +46,7 @@ public static bool TryCreate(Compilation compilation, out WellKnownTypes wellKno SpyAttribute: spyAttribute, Disposable: iDisposable, AsyncDisposable: iAsyncDisposable, + Lazy1: lazy1, ValueTask: valueTask, ValueTask1: valueTask1, Task1: task1, diff --git a/Sample/Context.cs b/Sample/Context.cs index 653ac179..9fa2a9ef 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -11,7 +11,7 @@ internal interface IContext internal class Context : IContext { public string Text => "Hello, world!"; - public Context(IChild child)//Lazy child) + public Context(Lazy child) { } diff --git a/Sample/Program.cs b/Sample/Program.cs index 4d11aef8..4cbf992d 100644 --- a/Sample/Program.cs +++ b/Sample/Program.cs @@ -2,6 +2,6 @@ using StrongInject; System.Console.WriteLine("Hello, world!"); -System.Console.WriteLine(new Container().Resolve().Text); +//System.Console.WriteLine(new Container().Resolve().Text); System.Console.WriteLine(new StrongInjectContainer().Run(c => c.Text)); From aee31504e37ada20198f156d0677a1570d940c91 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sat, 9 Oct 2021 19:31:37 +0200 Subject: [PATCH 010/162] =?UTF-8?q?Implemented=20global::System.Func<[?= =?UTF-8?q?=E2=80=A6]>=20:)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Main/DependencyWrapper.cs | 5 +++ Main/GenerateContainer.cs | 10 +++-- Main/Main.csproj | 6 +-- Main/Properties/launchSettings.json | 4 ++ Main/ReferenceGenerator.cs | 4 +- Main/ResolutionTreeFactory.cs | 63 +++++++++++++++++++++++------ Main/SourceGenerator.cs | 2 +- Main/TypeToImplementationMapper.cs | 19 ++++----- Sample/Context.cs | 2 +- SampleChild/Child.cs | 10 ++++- SampleChild/InternalChild.cs | 10 +++++ 11 files changed, 99 insertions(+), 36 deletions(-) diff --git a/Main/DependencyWrapper.cs b/Main/DependencyWrapper.cs index a2a49ea7..3754973c 100644 --- a/Main/DependencyWrapper.cs +++ b/Main/DependencyWrapper.cs @@ -16,8 +16,13 @@ internal record ConstructorResolution( string TypeFullName, IReadOnlyList<(string name, ResolutionBase Dependency)> Parameter) : ResolutionBase(Reference, TypeFullName); + internal record FuncParameterResolution( + string Reference, + string TypeFullName) : ResolutionBase(Reference, TypeFullName); + internal record FuncResolution( string Reference, string TypeFullName, + IReadOnlyList Parameter, ResolutionBase Dependency) : ResolutionBase(Reference, TypeFullName); } diff --git a/Main/GenerateContainer.cs b/Main/GenerateContainer.cs index 8dea3056..6af1b724 100644 --- a/Main/GenerateContainer.cs +++ b/Main/GenerateContainer.cs @@ -87,9 +87,11 @@ static StringBuilder GenerateFields( (builder, tuple) => GenerateFields(builder, tuple.Dependency)); stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); break; - case FuncResolution(var reference, var typeFullName, _): + case FuncResolution(var reference, var typeFullName, _, _): stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); break; + case FuncParameterResolution: + break; default: throw new Exception("Unexpected case or not implemented."); } @@ -114,13 +116,15 @@ static StringBuilder GenerateResolutions( stringBuilder = stringBuilder.AppendLine( $"{reference} = new {typeFullName}({string.Join(", ", parameters.Select(d => $"{d.name}: {d.Dependency.Reference}"))});"); break; - case FuncResolution(var reference, var typeFullName, var resolutionBase): - stringBuilder = stringBuilder.AppendLine($"{reference} = () =>"); + case FuncResolution(var reference, var typeFullName, var parameter, var resolutionBase): + stringBuilder = stringBuilder.AppendLine($"{reference} = ({string.Join(", ", parameter.Select(fpr => fpr.Reference))}) =>"); stringBuilder = stringBuilder.AppendLine($"{{"); GenerateResolutionFunction(stringBuilder, resolutionBase); stringBuilder = stringBuilder.AppendLine($"return {resolutionBase.Reference};"); stringBuilder = stringBuilder.AppendLine($"}};"); break; + case FuncParameterResolution: + break; default: throw new Exception("Unexpected case or not implemented."); } diff --git a/Main/Main.csproj b/Main/Main.csproj index fecb057f..608c4fb5 100644 --- a/Main/Main.csproj +++ b/Main/Main.csproj @@ -23,10 +23,10 @@ - - + + - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Main/Properties/launchSettings.json b/Main/Properties/launchSettings.json index 622b6d1b..ae8702f9 100644 --- a/Main/Properties/launchSettings.json +++ b/Main/Properties/launchSettings.json @@ -1,6 +1,10 @@ { "profiles": { "Main": { + "commandName": "DebugRoslynComponent", + "targetProject": "..\\Sample\\Sample.csproj" + }, + "Profile 1": { "commandName": "Executable" } } diff --git a/Main/ReferenceGenerator.cs b/Main/ReferenceGenerator.cs index d121a497..f8f005d9 100644 --- a/Main/ReferenceGenerator.cs +++ b/Main/ReferenceGenerator.cs @@ -5,7 +5,7 @@ namespace MrMeeseeks.DIE { public interface IReferenceGenerator { - string Generate(INamedTypeSymbol type); + string Generate(ITypeSymbol type); string Generate(string hardcodedName); } @@ -16,7 +16,7 @@ internal class ReferenceGenerator : IReferenceGenerator public ReferenceGenerator(int j) => _j = j; - public string Generate(INamedTypeSymbol type) => + public string Generate(ITypeSymbol type) => Generate($"{char.ToLower(type.Name[0])}{type.Name.Substring(1)}"); public string Generate(string hardcodedName) => diff --git a/Main/ResolutionTreeFactory.cs b/Main/ResolutionTreeFactory.cs index b54a4144..c9676613 100644 --- a/Main/ResolutionTreeFactory.cs +++ b/Main/ResolutionTreeFactory.cs @@ -8,7 +8,7 @@ namespace MrMeeseeks.DIE { internal interface IResolutionTreeFactory { - ResolutionBase Create(INamedTypeSymbol root); + ResolutionBase Create(ITypeSymbol root); } internal class ResolutionTreeFactory : IResolutionTreeFactory @@ -27,27 +27,39 @@ public ResolutionTreeFactory( _wellKnownTypes = wellKnownTypes; } - public ResolutionBase Create(INamedTypeSymbol type) => Create(type, _referenceGeneratorFactory.Create()); + public ResolutionBase Create(ITypeSymbol type) => Create( + type, + _referenceGeneratorFactory.Create(), + Array.Empty<(ITypeSymbol Type, FuncParameterResolution Resolution)>()); - private ResolutionBase Create(INamedTypeSymbol type, IReferenceGenerator referenceGenerator) + private ResolutionBase Create(ITypeSymbol type, IReferenceGenerator referenceGenerator, IReadOnlyList<(ITypeSymbol Type, FuncParameterResolution Resolution)> currentFuncParameters) { + if (currentFuncParameters.FirstOrDefault(t => SymbolEqualityComparer.Default.Equals(t.Type.OriginalDefinition, type.OriginalDefinition)) is { Type: not null, Resolution: not null } funcParameter) + { + return funcParameter.Resolution; + } + if (type.TypeKind == TypeKind.Interface) { var implementationType = _typeToImplementationsMapper .Map(type) - .FirstOrDefault() ?? throw new NotImplementedException($"What if several possible implementations exist (interface;{type.FullName()})"); + .SingleOrDefault() ?? throw new NotImplementedException($"What if several possible implementations exist (interface;{type.FullName()})"); return new InterfaceResolution( referenceGenerator.Generate(type), type.FullName(), - Create(implementationType, referenceGenerator)); + Create(implementationType, referenceGenerator, currentFuncParameters)); } - if (type.OriginalDefinition.Equals(_wellKnownTypes.Lazy1, SymbolEqualityComparer.Default)) + if (type.OriginalDefinition.Equals(_wellKnownTypes.Lazy1, SymbolEqualityComparer.Default) + && type is INamedTypeSymbol namedTypeSymbol) { - var genericType = type.TypeArguments.FirstOrDefault() as INamedTypeSymbol ?? - throw new NotImplementedException("What if not castable?"); + var genericType = namedTypeSymbol.TypeArguments.SingleOrDefault() as INamedTypeSymbol ?? + throw new NotImplementedException("What if not castable?"); - var dependency = Create(genericType, _referenceGeneratorFactory.Create()); + var dependency = Create( + genericType, + _referenceGeneratorFactory.Create(), + Array.Empty<(ITypeSymbol Type, FuncParameterResolution Resolution)>()); return new ConstructorResolution( referenceGenerator.Generate(type), type.FullName(), @@ -59,6 +71,7 @@ private ResolutionBase Create(INamedTypeSymbol type, IReferenceGenerator referen new FuncResolution( referenceGenerator.Generate("func"), $"global::System.Func<{genericType.FullName()}>", + Array.Empty(), dependency) ) })); @@ -68,8 +81,8 @@ private ResolutionBase Create(INamedTypeSymbol type, IReferenceGenerator referen { var implementationType = _typeToImplementationsMapper .Map(type) - .FirstOrDefault() ?? throw new NotImplementedException($"What if several possible implementations exist (class;{type.FullName()})"); - var constructor = implementationType.Constructors.FirstOrDefault() + .SingleOrDefault() as INamedTypeSymbol ?? throw new NotImplementedException($"What if several possible implementations exist (class;{type.FullName()})"); + var constructor = implementationType.Constructors.SingleOrDefault() ?? throw new NotImplementedException("What if no constructor exists or several possible constructors exist"); return new ConstructorResolution( @@ -81,11 +94,35 @@ private ResolutionBase Create(INamedTypeSymbol type, IReferenceGenerator referen p.Name, Create(p.Type as INamedTypeSymbol ?? throw new NotImplementedException("What if parameter type is not INamedTypeSymbol?"), - referenceGenerator))) + referenceGenerator, + currentFuncParameters))) .ToList())); } - throw new NotImplementedException("What if type neither interface nor class"); + if (type.TypeKind == TypeKind.Delegate + && type.FullName().StartsWith("global::System.Func<") + && type is INamedTypeSymbol namedTypeSymbol0) + { + var returnType = namedTypeSymbol0.TypeArguments.Last(); + var innerReferenceGenerator = _referenceGeneratorFactory.Create(); + var parameterTypes = namedTypeSymbol0 + .TypeArguments + .Take(namedTypeSymbol0.TypeArguments.Length - 1) + .Select(ts => (Type: ts, Resolution: new FuncParameterResolution(innerReferenceGenerator.Generate(ts), ts.FullName()))) + .ToArray(); + + var dependency = Create( + returnType, + innerReferenceGenerator, + parameterTypes); + return new FuncResolution( + referenceGenerator.Generate(type), + type.FullName(), + parameterTypes.Select(t => t.Resolution).ToArray(), + dependency); + } + + throw new NotImplementedException("What if type neither interface nor class nor delegate"); } } } \ No newline at end of file diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index 4aaa3987..0eaf7e92 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -19,7 +19,7 @@ public void Execute(GeneratorExecutionContext context) var getAllImplementations = new GetAllImplementations(context); var getAssemblyAttributes = new GetAssemblyAttributes(context); var _ = WellKnownTypes.TryCreate(context.Compilation, out var wellKnownTypes); - var typeToImplementationMapper = new TypeToImplementationsMapper(wellKnownTypes, diagLogger, getAllImplementations, getAssemblyAttributes); + var typeToImplementationMapper = new TypeToImplementationsMapper(wellKnownTypes, getAllImplementations, getAssemblyAttributes); var containerGenerator = new ContainerGenerator(context, diagLogger); var referenceGeneratorFactory = new ReferenceGeneratorFactory(ReferenceGeneratorFactory); var resolutionTreeFactory = new ResolutionTreeFactory(typeToImplementationMapper, referenceGeneratorFactory, wellKnownTypes); diff --git a/Main/TypeToImplementationMapper.cs b/Main/TypeToImplementationMapper.cs index 153caec1..410c8b9b 100644 --- a/Main/TypeToImplementationMapper.cs +++ b/Main/TypeToImplementationMapper.cs @@ -1,5 +1,4 @@ -using System; -using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; @@ -8,16 +7,15 @@ namespace MrMeeseeks.DIE { internal interface ITypeToImplementationsMapper { - IList Map(INamedTypeSymbol typeSymbol); + IList Map(ITypeSymbol typeSymbol); } internal class TypeToImplementationsMapper : ITypeToImplementationsMapper { - private readonly Dictionary> _map; + private readonly Dictionary> _map; public TypeToImplementationsMapper( WellKnownTypes wellKnownTypes, - IDiagLogger diagLogger, IGetAllImplementations getAllImplementations, IGetAssemblyAttributes getAssemblyAttributes) { @@ -25,11 +23,11 @@ public TypeToImplementationsMapper( _map = getAllImplementations .AllImplementations .Concat(GetSpiedImplementations()) - .SelectMany(i => { return i.AllInterfaces.Select(ii => (ii, i)).Prepend((i, i)); }) + .SelectMany(i => { return i.AllInterfaces.OfType().Select(ii => (ii, i)).Prepend((i, i)); }) .GroupBy(t => t.Item1, t => t.Item2) .ToDictionary(g => g.Key, g => g.ToList()); - IEnumerable GetSpiedImplementations() => getAssemblyAttributes + IEnumerable GetSpiedImplementations() => getAssemblyAttributes .AllAssemblyAttributes .Where(ad => ad.AttributeClass?.Equals(wellKnownTypes.SpyAttribute, SymbolEqualityComparer.Default) ?? false) @@ -61,8 +59,7 @@ IEnumerable GetSpiedImplementations() => getAssemblyAttributes return type; }) .Where(t => t is not null) - .OfType() - .SelectMany(t => t.GetMembers() + .SelectMany(t => t?.GetMembers() .OfType() .Select(p => p.Type) .OfType()); @@ -84,14 +81,14 @@ bool CheckValidType(TypedConstant typedConstant, out INamedTypeSymbol type) } } - public IList Map(INamedTypeSymbol typeSymbol) + public IList Map(ITypeSymbol typeSymbol) { if(_map.TryGetValue(typeSymbol, out var implementations)) { return implementations; } - return new List(); + return new List(); } } } diff --git a/Sample/Context.cs b/Sample/Context.cs index 9fa2a9ef..c26d8de4 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -11,7 +11,7 @@ internal interface IContext internal class Context : IContext { public string Text => "Hello, world!"; - public Context(Lazy child) + public Context(Func child) { } diff --git a/SampleChild/Child.cs b/SampleChild/Child.cs index 90e7becf..ea5f3c01 100644 --- a/SampleChild/Child.cs +++ b/SampleChild/Child.cs @@ -1,11 +1,17 @@ -namespace MrMeeseeks.DIE.SampleChild +using System; + +namespace MrMeeseeks.DIE.SampleChild { public interface IChild { } - public class Child : IChild + public class Child : IChild, IDisposable { public Child( IInternalChild innerChild){} + + public void Dispose() + { + } } } diff --git a/SampleChild/InternalChild.cs b/SampleChild/InternalChild.cs index b8cbe7d8..8b651758 100644 --- a/SampleChild/InternalChild.cs +++ b/SampleChild/InternalChild.cs @@ -3,6 +3,16 @@ namespace MrMeeseeks.DIE.SampleChild public interface IInternalChild {} internal class InternalChild : IInternalChild + { + public InternalChild(IYetAnotherInternalChild yetAnotherInternalChild) + { + + } + } + + public interface IYetAnotherInternalChild + {} + internal class YetAnotherInternalChild : IYetAnotherInternalChild { } From 7d695b0ee012f8452754701889883ef3edc62c58 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sat, 9 Oct 2021 23:28:42 +0200 Subject: [PATCH 011/162] Implemented collections --- Main/DependencyWrapper.cs | 6 +++++ Main/GenerateContainer.cs | 11 +++++++++- Main/ResolutionTreeFactory.cs | 39 +++++++++++++++++++++++---------- Main/WellKnownTypes.cs | 18 ++++++++++++--- Sample/Context.cs | 4 ++-- Sample/Program.cs | 2 +- Sample/StrongInjectContainer.cs | 3 +++ SampleChild/Child.cs | 16 ++++++++++++++ 8 files changed, 81 insertions(+), 18 deletions(-) diff --git a/Main/DependencyWrapper.cs b/Main/DependencyWrapper.cs index 3754973c..df99cc25 100644 --- a/Main/DependencyWrapper.cs +++ b/Main/DependencyWrapper.cs @@ -25,4 +25,10 @@ internal record FuncResolution( string TypeFullName, IReadOnlyList Parameter, ResolutionBase Dependency) : ResolutionBase(Reference, TypeFullName); + + internal record CollectionResolution( + string Reference, + string TypeFullName, + string ItemFullName, + IReadOnlyList Parameter) : ResolutionBase(Reference, TypeFullName); } diff --git a/Main/GenerateContainer.cs b/Main/GenerateContainer.cs index 6af1b724..2b8c15f6 100644 --- a/Main/GenerateContainer.cs +++ b/Main/GenerateContainer.cs @@ -92,6 +92,10 @@ static StringBuilder GenerateFields( break; case FuncParameterResolution: break; + case CollectionResolution(var reference, var typeFullName, _, var items): + stringBuilder = items.Aggregate(stringBuilder, GenerateFields); + stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); + break; default: throw new Exception("Unexpected case or not implemented."); } @@ -116,7 +120,7 @@ static StringBuilder GenerateResolutions( stringBuilder = stringBuilder.AppendLine( $"{reference} = new {typeFullName}({string.Join(", ", parameters.Select(d => $"{d.name}: {d.Dependency.Reference}"))});"); break; - case FuncResolution(var reference, var typeFullName, var parameter, var resolutionBase): + case FuncResolution(var reference, _, var parameter, var resolutionBase): stringBuilder = stringBuilder.AppendLine($"{reference} = ({string.Join(", ", parameter.Select(fpr => fpr.Reference))}) =>"); stringBuilder = stringBuilder.AppendLine($"{{"); GenerateResolutionFunction(stringBuilder, resolutionBase); @@ -125,6 +129,11 @@ static StringBuilder GenerateResolutions( break; case FuncParameterResolution: break; + case CollectionResolution(var reference, _, var itemFullName, var items): + stringBuilder = items.Aggregate(stringBuilder, GenerateResolutions); + stringBuilder = stringBuilder.AppendLine( + $"{reference} = new {itemFullName}[]{{{string.Join(", ", items.Select(d => $"({itemFullName}) {d.Reference}"))}}};"); + break; default: throw new Exception("Unexpected case or not implemented."); } diff --git a/Main/ResolutionTreeFactory.cs b/Main/ResolutionTreeFactory.cs index c9676613..e6a73a9d 100644 --- a/Main/ResolutionTreeFactory.cs +++ b/Main/ResolutionTreeFactory.cs @@ -38,17 +38,6 @@ private ResolutionBase Create(ITypeSymbol type, IReferenceGenerator referenceGen { return funcParameter.Resolution; } - - if (type.TypeKind == TypeKind.Interface) - { - var implementationType = _typeToImplementationsMapper - .Map(type) - .SingleOrDefault() ?? throw new NotImplementedException($"What if several possible implementations exist (interface;{type.FullName()})"); - return new InterfaceResolution( - referenceGenerator.Generate(type), - type.FullName(), - Create(implementationType, referenceGenerator, currentFuncParameters)); - } if (type.OriginalDefinition.Equals(_wellKnownTypes.Lazy1, SymbolEqualityComparer.Default) && type is INamedTypeSymbol namedTypeSymbol) @@ -77,6 +66,34 @@ private ResolutionBase Create(ITypeSymbol type, IReferenceGenerator referenceGen })); } + if (type.OriginalDefinition.Equals(_wellKnownTypes.Enumerable1, SymbolEqualityComparer.Default) + || type.OriginalDefinition.Equals(_wellKnownTypes.ReadOnlyCollection1, SymbolEqualityComparer.Default) + || type.OriginalDefinition.Equals(_wellKnownTypes.ReadOnlyList1, SymbolEqualityComparer.Default)) + { + var itemType = (type as INamedTypeSymbol)?.TypeArguments.SingleOrDefault() ?? throw new Exception(); + var itemFullName = itemType.FullName(); + var items = _typeToImplementationsMapper + .Map(itemType) + .Select(i => Create(i, referenceGenerator, currentFuncParameters)) + .ToList(); + return new CollectionResolution( + referenceGenerator.Generate(type), + type.FullName(), + itemFullName, + items); + } + + if (type.TypeKind == TypeKind.Interface) + { + var implementationType = _typeToImplementationsMapper + .Map(type) + .SingleOrDefault() ?? throw new NotImplementedException($"What if several possible implementations exist (interface;{type.FullName()})"); + return new InterfaceResolution( + referenceGenerator.Generate(type), + type.FullName(), + Create(implementationType, referenceGenerator, currentFuncParameters)); + } + if (type.TypeKind == TypeKind.Class) { var implementationType = _typeToImplementationsMapper diff --git a/Main/WellKnownTypes.cs b/Main/WellKnownTypes.cs index b9600c73..e28c046d 100644 --- a/Main/WellKnownTypes.cs +++ b/Main/WellKnownTypes.cs @@ -11,7 +11,10 @@ internal record WellKnownTypes( INamedTypeSymbol ValueTask, INamedTypeSymbol ValueTask1, INamedTypeSymbol Task1, - INamedTypeSymbol ObjectDisposedException) + INamedTypeSymbol ObjectDisposedException, + INamedTypeSymbol Enumerable1, + INamedTypeSymbol ReadOnlyCollection1, + INamedTypeSymbol ReadOnlyList1) { public static bool TryCreate(Compilation compilation, out WellKnownTypes wellKnownTypes) { @@ -23,6 +26,9 @@ public static bool TryCreate(Compilation compilation, out WellKnownTypes wellKno var valueTask1 = compilation.GetTypeOrReport("System.Threading.Tasks.ValueTask`1"); var task1 = compilation.GetTypeOrReport("System.Threading.Tasks.Task`1"); var objectDisposedException = compilation.GetTypeOrReport("System.ObjectDisposedException"); + var iEnumerable1 = compilation.GetTypeOrReport("System.Collections.Generic.IEnumerable`1"); + var iReadOnlyCollection1 = compilation.GetTypeOrReport("System.Collections.Generic.IReadOnlyCollection`1"); + var iReadOnlyList1 = compilation.GetTypeOrReport("System.Collections.Generic.IReadOnlyList`1"); var spyAttribute = compilation .GetTypeByMetadataName(typeof(SpyAttribute).FullName ?? ""); @@ -35,7 +41,10 @@ public static bool TryCreate(Compilation compilation, out WellKnownTypes wellKno || valueTask is null || valueTask1 is null || task1 is null - || objectDisposedException is null) + || objectDisposedException is null + || iEnumerable1 is null + || iReadOnlyCollection1 is null + || iReadOnlyList1 is null) { wellKnownTypes = null!; return false; @@ -50,7 +59,10 @@ public static bool TryCreate(Compilation compilation, out WellKnownTypes wellKno ValueTask: valueTask, ValueTask1: valueTask1, Task1: task1, - ObjectDisposedException: objectDisposedException); + ObjectDisposedException: objectDisposedException, + Enumerable1: iEnumerable1, + ReadOnlyCollection1: iReadOnlyCollection1, + ReadOnlyList1: iReadOnlyList1); return true; } diff --git a/Sample/Context.cs b/Sample/Context.cs index c26d8de4..d0e2ad95 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -1,4 +1,4 @@ -using System; +using System.Collections.Generic; using MrMeeseeks.DIE.SampleChild; namespace MrMeeseeks.DIE.Sample @@ -11,7 +11,7 @@ internal interface IContext internal class Context : IContext { public string Text => "Hello, world!"; - public Context(Func child) + public Context(IReadOnlyList child) { } diff --git a/Sample/Program.cs b/Sample/Program.cs index 4cbf992d..4d11aef8 100644 --- a/Sample/Program.cs +++ b/Sample/Program.cs @@ -2,6 +2,6 @@ using StrongInject; System.Console.WriteLine("Hello, world!"); -//System.Console.WriteLine(new Container().Resolve().Text); +System.Console.WriteLine(new Container().Resolve().Text); System.Console.WriteLine(new StrongInjectContainer().Run(c => c.Text)); diff --git a/Sample/StrongInjectContainer.cs b/Sample/StrongInjectContainer.cs index 22c7071d..4ad08380 100644 --- a/Sample/StrongInjectContainer.cs +++ b/Sample/StrongInjectContainer.cs @@ -6,7 +6,10 @@ namespace MrMeeseeks.DIE.Sample { [Register(typeof(Context), typeof(IContext))] [Register(typeof(Child), typeof(Child), typeof(IChild))] + [Register(typeof(Child0), typeof(Child0), typeof(IChild))] + [Register(typeof(Child1), typeof(Child1), typeof(IChild))] [Register(typeof(InternalChild), typeof(IInternalChild))] + [Register(typeof(YetAnotherInternalChild), typeof(IYetAnotherInternalChild))] [RegisterModule(typeof(StandardModule))] internal partial class StrongInjectContainer : StrongInject.IContainer { diff --git a/SampleChild/Child.cs b/SampleChild/Child.cs index ea5f3c01..9a6675fc 100644 --- a/SampleChild/Child.cs +++ b/SampleChild/Child.cs @@ -14,4 +14,20 @@ public void Dispose() { } } + + public class Child0 : IChild, IDisposable + { + public Child0( + IInternalChild innerChild){} + + public void Dispose() + { + } + } + + public class Child1 : IChild + { + public Child1( + IInternalChild innerChild){} + } } From d2222b143da1c8a7299db2d36068bd6aeb226859 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sat, 16 Oct 2021 20:32:44 +0200 Subject: [PATCH 012/162] Spy generates interfaces with functions instead of classes with properties Advantages of interfaces with functions over classes with properties: - easier handling of generic parameters, because they can be handled per function independently - there doesn't have to be an implementation (easier nullability handling and so on) --- Main/ContainerErrorGenerator.cs | 47 ++++++++ ...rateContainer.cs => ContainerGenerator.cs} | 34 +++--- Main/ExecuteImpl.cs | 12 ++- Main/ResolutionTreeCreationErrorHarvester.cs | 52 +++++++++ Main/ResolutionTreeFactory.cs | 98 ++++++++++++----- ...ndencyWrapper.cs => ResolutionTreeItem.cs} | 19 ++-- Main/SourceGenerator.cs | 13 ++- Main/TypeToImplementationMapper.cs | 7 +- Sample/Container.cs | 2 +- Sample/Context.cs | 9 +- Sample/StrongInjectContainer.cs | 2 - SampleChild/Child.cs | 16 --- SampleChild/InternalChild.cs | 16 ++- Spy/ExecuteImpl.cs | 8 +- Spy/GenerateContainer.cs | 72 ------------- Spy/GetAllImplementations.cs | 7 +- Spy/RoslynExtensions.cs | 16 --- Spy/SourceGenerator.cs | 4 +- Spy/TypeReportGenerator.cs | 102 ++++++++++++++++++ 19 files changed, 360 insertions(+), 176 deletions(-) create mode 100644 Main/ContainerErrorGenerator.cs rename Main/{GenerateContainer.cs => ContainerGenerator.cs} (84%) create mode 100644 Main/ResolutionTreeCreationErrorHarvester.cs rename Main/{DependencyWrapper.cs => ResolutionTreeItem.cs} (53%) delete mode 100644 Spy/GenerateContainer.cs delete mode 100644 Spy/RoslynExtensions.cs create mode 100644 Spy/TypeReportGenerator.cs diff --git a/Main/ContainerErrorGenerator.cs b/Main/ContainerErrorGenerator.cs new file mode 100644 index 00000000..8923446e --- /dev/null +++ b/Main/ContainerErrorGenerator.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Text; +using System.Linq; +using System.Text; + +namespace MrMeeseeks.DIE +{ + internal interface IContainerErrorGenerator + { + void Generate(IContainerInfo containerInfo, IReadOnlyList errorTreeItems); + } + + internal class ContainerErrorGenerator : IContainerErrorGenerator + { + private readonly GeneratorExecutionContext _context; + + public ContainerErrorGenerator( + GeneratorExecutionContext context) => + _context = context; + + public void Generate(IContainerInfo containerInfo, IReadOnlyList errorTreeItems) + { + var generatedContainer = new StringBuilder() + .AppendLine($"namespace {containerInfo.Namespace}") + .AppendLine($"{{") + .AppendLine($"partial class {containerInfo.Name}") + .AppendLine($"{{") + .AppendLine($"public object Resolve()") + .AppendLine($"{{") + .AppendLine($"throw new Exception(@\"{string.Join(Environment.NewLine, errorTreeItems.Select(eri => eri.Message))}\");") + .AppendLine($"}}") + .AppendLine($"}}") + .AppendLine($"}}"); + + var containerSource = CSharpSyntaxTree + .ParseText(SourceText.From(generatedContainer.ToString(), Encoding.UTF8)) + .GetRoot() + .NormalizeWhitespace() + .SyntaxTree + .GetText(); + _context.AddSource($"{containerInfo.Namespace}.{containerInfo.Name}.g.cs", containerSource); + } + } +} diff --git a/Main/GenerateContainer.cs b/Main/ContainerGenerator.cs similarity index 84% rename from Main/GenerateContainer.cs rename to Main/ContainerGenerator.cs index 2b8c15f6..169b215a 100644 --- a/Main/GenerateContainer.cs +++ b/Main/ContainerGenerator.cs @@ -9,7 +9,7 @@ namespace MrMeeseeks.DIE { internal interface IContainerGenerator { - void Generate(IContainerInfo containerInfo, ResolutionBase resolutionBase); + void Generate(IContainerInfo containerInfo, Resolvable resolvable); } internal class ContainerGenerator : IContainerGenerator @@ -25,7 +25,7 @@ public ContainerGenerator( _diagLogger = diagLogger; } - public void Generate(IContainerInfo containerInfo, ResolutionBase resolutionBase) + public void Generate(IContainerInfo containerInfo, Resolvable resolvable) { if (!containerInfo.IsValid || containerInfo.ResolutionRootType is null) { @@ -38,13 +38,13 @@ public void Generate(IContainerInfo containerInfo, ResolutionBase resolutionBase .AppendLine($"{{") .AppendLine($"partial class {containerInfo.Name}") .AppendLine($"{{") - .AppendLine($"public {resolutionBase.TypeFullName} Resolve()") + .AppendLine($"public {resolvable.TypeFullName} Resolve()") .AppendLine($"{{"); - generatedContainer = GenerateResolutionFunction(generatedContainer, resolutionBase); + generatedContainer = GenerateResolutionFunction(generatedContainer, resolvable); generatedContainer = generatedContainer - .AppendLine($"return {resolutionBase.Reference};") + .AppendLine($"return {resolvable.Reference};") .AppendLine($"}}"); generatedContainer = generatedContainer @@ -64,7 +64,7 @@ public void Generate(IContainerInfo containerInfo, ResolutionBase resolutionBase static StringBuilder GenerateResolutionFunction( StringBuilder stringBuilder, - ResolutionBase resolution) + Resolvable resolution) { stringBuilder = GenerateFields(stringBuilder, resolution); stringBuilder = GenerateResolutions(stringBuilder, resolution); @@ -74,17 +74,17 @@ static StringBuilder GenerateResolutionFunction( static StringBuilder GenerateFields( StringBuilder stringBuilder, - ResolutionBase resolution) + Resolvable resolution) { switch (resolution) { - case InterfaceResolution(var reference, var typeFullName, var resolutionBase): + case InterfaceResolution(var reference, var typeFullName, Resolvable resolutionBase): stringBuilder = GenerateFields(stringBuilder, resolutionBase); stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); break; case ConstructorResolution(var reference, var typeFullName, var parameters): stringBuilder = parameters.Aggregate(stringBuilder, - (builder, tuple) => GenerateFields(builder, tuple.Dependency)); + (builder, tuple) => GenerateFields(builder, tuple.Dependency as Resolvable ?? throw new Exception())); stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); break; case FuncResolution(var reference, var typeFullName, _, _): @@ -93,7 +93,7 @@ static StringBuilder GenerateFields( case FuncParameterResolution: break; case CollectionResolution(var reference, var typeFullName, _, var items): - stringBuilder = items.Aggregate(stringBuilder, GenerateFields); + stringBuilder = items.OfType().Aggregate(stringBuilder, GenerateFields); stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); break; default: @@ -105,22 +105,22 @@ static StringBuilder GenerateFields( static StringBuilder GenerateResolutions( StringBuilder stringBuilder, - ResolutionBase resolution) + Resolvable resolution) { switch (resolution) { - case InterfaceResolution(var reference, var typeFullName, var resolutionBase): + case InterfaceResolution(var reference, var typeFullName, Resolvable resolutionBase): stringBuilder = GenerateResolutions(stringBuilder, resolutionBase); stringBuilder = stringBuilder.AppendLine( $"{reference} = ({typeFullName}) {resolutionBase.Reference};"); break; case ConstructorResolution(var reference, var typeFullName, var parameters): stringBuilder = parameters.Aggregate(stringBuilder, - (builder, tuple) => GenerateResolutions(builder, tuple.Dependency)); + (builder, tuple) => GenerateResolutions(builder, tuple.Dependency as Resolvable ?? throw new Exception())); stringBuilder = stringBuilder.AppendLine( - $"{reference} = new {typeFullName}({string.Join(", ", parameters.Select(d => $"{d.name}: {d.Dependency.Reference}"))});"); + $"{reference} = new {typeFullName}({string.Join(", ", parameters.Select(d => $"{d.name}: {(d.Dependency as Resolvable)?.Reference}"))});"); break; - case FuncResolution(var reference, _, var parameter, var resolutionBase): + case FuncResolution(var reference, _, var parameter, Resolvable resolutionBase): stringBuilder = stringBuilder.AppendLine($"{reference} = ({string.Join(", ", parameter.Select(fpr => fpr.Reference))}) =>"); stringBuilder = stringBuilder.AppendLine($"{{"); GenerateResolutionFunction(stringBuilder, resolutionBase); @@ -130,9 +130,9 @@ static StringBuilder GenerateResolutions( case FuncParameterResolution: break; case CollectionResolution(var reference, _, var itemFullName, var items): - stringBuilder = items.Aggregate(stringBuilder, GenerateResolutions); + stringBuilder = items.OfType().Aggregate(stringBuilder, GenerateResolutions); stringBuilder = stringBuilder.AppendLine( - $"{reference} = new {itemFullName}[]{{{string.Join(", ", items.Select(d => $"({itemFullName}) {d.Reference}"))}}};"); + $"{reference} = new {itemFullName}[]{{{string.Join(", ", items.Select(d => $"({itemFullName}) {(d as Resolvable)?.Reference}"))}}};"); break; default: throw new Exception("Unexpected case or not implemented."); diff --git a/Main/ExecuteImpl.cs b/Main/ExecuteImpl.cs index 23867cc0..1d030929 100644 --- a/Main/ExecuteImpl.cs +++ b/Main/ExecuteImpl.cs @@ -15,7 +15,9 @@ internal class ExecuteImpl : IExecute private readonly GeneratorExecutionContext _context; private readonly WellKnownTypes _wellKnownTypes; private readonly IContainerGenerator _containerGenerator; + private readonly IContainerErrorGenerator _containerErrorGenerator; private readonly IResolutionTreeFactory _resolutionTreeFactory; + private readonly IResolutionTreeCreationErrorHarvester _resolutionTreeCreationErrorHarvester; private readonly Func _containerInfoFactory; private readonly IDiagLogger _diagLogger; @@ -23,14 +25,18 @@ public ExecuteImpl( GeneratorExecutionContext context, WellKnownTypes wellKnownTypes, IContainerGenerator containerGenerator, + IContainerErrorGenerator containerErrorGenerator, IResolutionTreeFactory resolutionTreeFactory, + IResolutionTreeCreationErrorHarvester resolutionTreeCreationErrorHarvester, Func containerInfoFactory, IDiagLogger diagLogger) { _context = context; _wellKnownTypes = wellKnownTypes; _containerGenerator = containerGenerator; + _containerErrorGenerator = containerErrorGenerator; _resolutionTreeFactory = resolutionTreeFactory; + _resolutionTreeCreationErrorHarvester = resolutionTreeCreationErrorHarvester; _containerInfoFactory = containerInfoFactory; _diagLogger = diagLogger; } @@ -55,7 +61,11 @@ public void Execute() if (containerInfo.IsValid && containerInfo.ResolutionRootType is { }) { var resolutionRoot = _resolutionTreeFactory.Create(containerInfo.ResolutionRootType); - _containerGenerator.Generate(containerInfo, resolutionRoot); + var errorTreeItems = _resolutionTreeCreationErrorHarvester.Harvest(resolutionRoot); + if (errorTreeItems.Any()) + _containerErrorGenerator.Generate(containerInfo, errorTreeItems); + else + _containerGenerator.Generate(containerInfo, resolutionRoot as Resolvable ?? throw new Exception()); } else throw new NotImplementedException("Handle non-valid container information"); } diff --git a/Main/ResolutionTreeCreationErrorHarvester.cs b/Main/ResolutionTreeCreationErrorHarvester.cs new file mode 100644 index 00000000..4271568f --- /dev/null +++ b/Main/ResolutionTreeCreationErrorHarvester.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; + +namespace MrMeeseeks.DIE +{ + internal interface IResolutionTreeCreationErrorHarvester + { + IReadOnlyList Harvest(ResolutionTreeItem root); + } + + internal class ResolutionTreeCreationErrorHarvester : IResolutionTreeCreationErrorHarvester + { + public IReadOnlyList Harvest(ResolutionTreeItem root) + { + var errorTreeItems = new List(); + Inner(root, errorTreeItems); + return errorTreeItems; + + static void Inner(ResolutionTreeItem item, ICollection errorTreeItems) + { + switch (item) + { + case ErrorTreeItem errorTreeItem: + errorTreeItems.Add(errorTreeItem); + break; + case ConstructorResolution constructorResolution: + foreach (var valueTuple in constructorResolution.Parameter) + Inner(valueTuple.Dependency, errorTreeItems); + break; + case CollectionResolution collectionResolution: + foreach (var resolutionTreeItem in collectionResolution.Parameter) + Inner(resolutionTreeItem, errorTreeItems); + break; + case FuncParameterResolution: + break; + case FuncResolution funcResolution: + foreach (var funcParameterResolution in funcResolution.Parameter) + Inner(funcParameterResolution, errorTreeItems); + Inner(funcResolution.Dependency, errorTreeItems); + break; + case InterfaceResolution interfaceResolution: + Inner(interfaceResolution.Dependency, errorTreeItems); + break; + case Resolvable: + throw new ArgumentOutOfRangeException(nameof(item)); + default: + throw new ArgumentOutOfRangeException(nameof(item)); + } + } + } + } +} \ No newline at end of file diff --git a/Main/ResolutionTreeFactory.cs b/Main/ResolutionTreeFactory.cs index e6a73a9d..e0069e52 100644 --- a/Main/ResolutionTreeFactory.cs +++ b/Main/ResolutionTreeFactory.cs @@ -8,7 +8,7 @@ namespace MrMeeseeks.DIE { internal interface IResolutionTreeFactory { - ResolutionBase Create(ITypeSymbol root); + ResolutionTreeItem Create(ITypeSymbol root); } internal class ResolutionTreeFactory : IResolutionTreeFactory @@ -27,12 +27,12 @@ public ResolutionTreeFactory( _wellKnownTypes = wellKnownTypes; } - public ResolutionBase Create(ITypeSymbol type) => Create( + public ResolutionTreeItem Create(ITypeSymbol type) => Create( type, _referenceGeneratorFactory.Create(), Array.Empty<(ITypeSymbol Type, FuncParameterResolution Resolution)>()); - private ResolutionBase Create(ITypeSymbol type, IReferenceGenerator referenceGenerator, IReadOnlyList<(ITypeSymbol Type, FuncParameterResolution Resolution)> currentFuncParameters) + private ResolutionTreeItem Create(ITypeSymbol type, IReferenceGenerator referenceGenerator, IReadOnlyList<(ITypeSymbol Type, FuncParameterResolution Resolution)> currentFuncParameters) { if (currentFuncParameters.FirstOrDefault(t => SymbolEqualityComparer.Default.Equals(t.Type.OriginalDefinition, type.OriginalDefinition)) is { Type: not null, Resolution: not null } funcParameter) { @@ -42,8 +42,15 @@ private ResolutionBase Create(ITypeSymbol type, IReferenceGenerator referenceGen if (type.OriginalDefinition.Equals(_wellKnownTypes.Lazy1, SymbolEqualityComparer.Default) && type is INamedTypeSymbol namedTypeSymbol) { - var genericType = namedTypeSymbol.TypeArguments.SingleOrDefault() as INamedTypeSymbol ?? - throw new NotImplementedException("What if not castable?"); + if (namedTypeSymbol.TypeArguments.SingleOrDefault() is not INamedTypeSymbol genericType) + { + return new ErrorTreeItem(namedTypeSymbol.TypeArguments.Length switch + { + 0 => $"[{type.FullName()}] Lazy: No type argument", + > 1 => $"[{type.FullName()}] Lazy: more than one type argument", + _ => $"[{type.FullName()}] Lazy: {namedTypeSymbol.TypeArguments[0].FullName()} is not a named type symbol" + }); + } var dependency = Create( genericType, @@ -52,8 +59,8 @@ private ResolutionBase Create(ITypeSymbol type, IReferenceGenerator referenceGen return new ConstructorResolution( referenceGenerator.Generate(type), type.FullName(), - new ReadOnlyCollection<(string Name, ResolutionBase Dependency)>( - new List<(string Name, ResolutionBase Dependency)> + new ReadOnlyCollection<(string Name, ResolutionTreeItem Dependency)>( + new List<(string Name, ResolutionTreeItem Dependency)> { ( "valueFactory", @@ -70,7 +77,19 @@ private ResolutionBase Create(ITypeSymbol type, IReferenceGenerator referenceGen || type.OriginalDefinition.Equals(_wellKnownTypes.ReadOnlyCollection1, SymbolEqualityComparer.Default) || type.OriginalDefinition.Equals(_wellKnownTypes.ReadOnlyList1, SymbolEqualityComparer.Default)) { - var itemType = (type as INamedTypeSymbol)?.TypeArguments.SingleOrDefault() ?? throw new Exception(); + if (type is not INamedTypeSymbol collectionType) + { + return new ErrorTreeItem($"[{type.FullName()}] Collection: Collection is not a named type symbol"); + } + if (collectionType.TypeArguments.SingleOrDefault() is not INamedTypeSymbol itemType) + { + return new ErrorTreeItem(collectionType.TypeArguments.Length switch + { + 0 => $"[{type.FullName()}] Collection: No item type argument", + > 1 => $"[{type.FullName()}] Collection: More than one item type argument", + _ => $"[{type.FullName()}] Collection: {collectionType.TypeArguments[0].FullName()} is not a named type symbol" + }); + } var itemFullName = itemType.FullName(); var items = _typeToImplementationsMapper .Map(itemType) @@ -85,9 +104,18 @@ private ResolutionBase Create(ITypeSymbol type, IReferenceGenerator referenceGen if (type.TypeKind == TypeKind.Interface) { - var implementationType = _typeToImplementationsMapper - .Map(type) - .SingleOrDefault() ?? throw new NotImplementedException($"What if several possible implementations exist (interface;{type.FullName()})"); + var implementations = _typeToImplementationsMapper + .Map(type); + if (implementations + .SingleOrDefault() is not INamedTypeSymbol implementationType) + { + return new ErrorTreeItem(implementations.Count switch + { + 0 => $"[{type.FullName()}] Interface: No implementation found", + > 1 => $"[{type.FullName()}] Interface: more than one implementation found", + _ => $"[{type.FullName()}] Interface: Found single implementation {implementations[0].FullName()} is not a named type symbol" + }); + } return new InterfaceResolution( referenceGenerator.Generate(type), type.FullName(), @@ -96,23 +124,45 @@ private ResolutionBase Create(ITypeSymbol type, IReferenceGenerator referenceGen if (type.TypeKind == TypeKind.Class) { - var implementationType = _typeToImplementationsMapper - .Map(type) - .SingleOrDefault() as INamedTypeSymbol ?? throw new NotImplementedException($"What if several possible implementations exist (class;{type.FullName()})"); - var constructor = implementationType.Constructors.SingleOrDefault() - ?? throw new NotImplementedException("What if no constructor exists or several possible constructors exist"); + var implementations = _typeToImplementationsMapper + .Map(type); + if (implementations + .SingleOrDefault() is not INamedTypeSymbol implementationType) + { + return new ErrorTreeItem(implementations.Count switch + { + 0 => $"[{type.FullName()}] Class: No implementation found", + > 1 => $"[{type.FullName()}] Class: more than one implementation found", + _ => $"[{type.FullName()}] Class: Found single implementation{implementations[0].FullName()} is not a named type symbol" + }); + } + if (implementationType.Constructors.SingleOrDefault() is not { } constructor) + { + return new ErrorTreeItem(implementations.Count switch + { + 0 => $"[{type.FullName()}] Class.Constructor: No constructor found for implementation {implementationType.FullName()}", + > 1 => $"[{type.FullName()}] Class.Constructor: More than one constructor found for implementation {implementationType.FullName()}", + _ => $"[{type.FullName()}] Class.Constructor: {implementationType.Constructors[0].Name} is not a method symbol" + }); + } return new ConstructorResolution( referenceGenerator.Generate(implementationType), implementationType.FullName(), - new ReadOnlyCollection<(string Name, ResolutionBase Dependency)>(constructor + new ReadOnlyCollection<(string Name, ResolutionTreeItem Dependency)>(constructor .Parameters - .Select(p => ( - p.Name, - Create(p.Type as INamedTypeSymbol - ?? throw new NotImplementedException("What if parameter type is not INamedTypeSymbol?"), - referenceGenerator, - currentFuncParameters))) + .Select(p => + { + if (p.Type is not INamedTypeSymbol parameterType) + { + return ("", new ErrorTreeItem($"[{type.FullName()}] Class.Constructor.Parameter: Parameter type {p.Type.FullName()} is not a named type symbol")); + } + return ( + p.Name, + Create(parameterType, + referenceGenerator, + currentFuncParameters)); + }) .ToList())); } @@ -139,7 +189,7 @@ private ResolutionBase Create(ITypeSymbol type, IReferenceGenerator referenceGen dependency); } - throw new NotImplementedException("What if type neither interface nor class nor delegate"); + return new ErrorTreeItem($"[{type.FullName()}] Couldn't process in resolution tree creation."); } } } \ No newline at end of file diff --git a/Main/DependencyWrapper.cs b/Main/ResolutionTreeItem.cs similarity index 53% rename from Main/DependencyWrapper.cs rename to Main/ResolutionTreeItem.cs index df99cc25..85ed1b30 100644 --- a/Main/DependencyWrapper.cs +++ b/Main/ResolutionTreeItem.cs @@ -2,33 +2,38 @@ namespace MrMeeseeks.DIE { - internal abstract record ResolutionBase( + internal abstract record ResolutionTreeItem; + + internal record ErrorTreeItem( + string Message) : ResolutionTreeItem; + + internal abstract record Resolvable( string Reference, - string TypeFullName); + string TypeFullName) : ResolutionTreeItem; internal record InterfaceResolution( string Reference, string TypeFullName, - ResolutionBase Dependency) : ResolutionBase(Reference, TypeFullName); + ResolutionTreeItem Dependency) : Resolvable(Reference, TypeFullName); internal record ConstructorResolution( string Reference, string TypeFullName, - IReadOnlyList<(string name, ResolutionBase Dependency)> Parameter) : ResolutionBase(Reference, TypeFullName); + IReadOnlyList<(string name, ResolutionTreeItem Dependency)> Parameter) : Resolvable(Reference, TypeFullName); internal record FuncParameterResolution( string Reference, - string TypeFullName) : ResolutionBase(Reference, TypeFullName); + string TypeFullName) : Resolvable(Reference, TypeFullName); internal record FuncResolution( string Reference, string TypeFullName, IReadOnlyList Parameter, - ResolutionBase Dependency) : ResolutionBase(Reference, TypeFullName); + ResolutionTreeItem Dependency) : Resolvable(Reference, TypeFullName); internal record CollectionResolution( string Reference, string TypeFullName, string ItemFullName, - IReadOnlyList Parameter) : ResolutionBase(Reference, TypeFullName); + IReadOnlyList Parameter) : Resolvable(Reference, TypeFullName); } diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index 0eaf7e92..97b1959c 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -1,5 +1,4 @@ using Microsoft.CodeAnalysis; -using System; namespace MrMeeseeks.DIE { @@ -23,7 +22,17 @@ public void Execute(GeneratorExecutionContext context) var containerGenerator = new ContainerGenerator(context, diagLogger); var referenceGeneratorFactory = new ReferenceGeneratorFactory(ReferenceGeneratorFactory); var resolutionTreeFactory = new ResolutionTreeFactory(typeToImplementationMapper, referenceGeneratorFactory, wellKnownTypes); - new ExecuteImpl(context, wellKnownTypes, containerGenerator, resolutionTreeFactory, ContainerInfoFactory, diagLogger).Execute(); + var containerErrorGenerator = new ContainerErrorGenerator(context); + var resolutionTreeCreationErrorHarvester = new ResolutionTreeCreationErrorHarvester(); + new ExecuteImpl( + context, + wellKnownTypes, + containerGenerator, + containerErrorGenerator, + resolutionTreeFactory, + resolutionTreeCreationErrorHarvester, + ContainerInfoFactory, + diagLogger).Execute(); IContainerInfo ContainerInfoFactory(INamedTypeSymbol type) => new ContainerInfo(type, wellKnownTypes); IReferenceGenerator ReferenceGeneratorFactory(int j) => new ReferenceGenerator(j); diff --git a/Main/TypeToImplementationMapper.cs b/Main/TypeToImplementationMapper.cs index 410c8b9b..34d01edc 100644 --- a/Main/TypeToImplementationMapper.cs +++ b/Main/TypeToImplementationMapper.cs @@ -25,7 +25,7 @@ public TypeToImplementationsMapper( .Concat(GetSpiedImplementations()) .SelectMany(i => { return i.AllInterfaces.OfType().Select(ii => (ii, i)).Prepend((i, i)); }) .GroupBy(t => t.Item1, t => t.Item2) - .ToDictionary(g => g.Key, g => g.ToList()); + .ToDictionary(g => g.Key, g => g.Distinct().ToList()); IEnumerable GetSpiedImplementations() => getAssemblyAttributes .AllAssemblyAttributes @@ -60,8 +60,9 @@ IEnumerable GetSpiedImplementations() => getAssemblyAttributes }) .Where(t => t is not null) .SelectMany(t => t?.GetMembers() - .OfType() - .Select(p => p.Type) + .OfType() + .Where(ms => !ms.ReturnsVoid) + .Select(ms => ms.ReturnType) .OfType()); bool CheckValidType(TypedConstant typedConstant, out INamedTypeSymbol type) diff --git a/Sample/Container.cs b/Sample/Container.cs index 0693e9e9..8111a7f9 100644 --- a/Sample/Container.cs +++ b/Sample/Container.cs @@ -1,7 +1,7 @@ using MrMeeseeks.DIE; using SampleChild; -[assembly:Spy(typeof(PublicTypes), typeof(InternalTypes))] +[assembly:Spy(typeof(IPublicTypeReport), typeof(IInternalTypeReport))] namespace MrMeeseeks.DIE.Sample { diff --git a/Sample/Context.cs b/Sample/Context.cs index d0e2ad95..f687375a 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using MrMeeseeks.DIE.SampleChild; namespace MrMeeseeks.DIE.Sample @@ -8,12 +9,16 @@ internal interface IContext string Text { get; } } - internal class Context : IContext + internal class Context : IContext, IDisposable { public string Text => "Hello, world!"; public Context(IReadOnlyList child) { } + + public void Dispose() + { + } } } diff --git a/Sample/StrongInjectContainer.cs b/Sample/StrongInjectContainer.cs index 4ad08380..bbd7dfd2 100644 --- a/Sample/StrongInjectContainer.cs +++ b/Sample/StrongInjectContainer.cs @@ -6,8 +6,6 @@ namespace MrMeeseeks.DIE.Sample { [Register(typeof(Context), typeof(IContext))] [Register(typeof(Child), typeof(Child), typeof(IChild))] - [Register(typeof(Child0), typeof(Child0), typeof(IChild))] - [Register(typeof(Child1), typeof(Child1), typeof(IChild))] [Register(typeof(InternalChild), typeof(IInternalChild))] [Register(typeof(YetAnotherInternalChild), typeof(IYetAnotherInternalChild))] [RegisterModule(typeof(StandardModule))] diff --git a/SampleChild/Child.cs b/SampleChild/Child.cs index 9a6675fc..ea5f3c01 100644 --- a/SampleChild/Child.cs +++ b/SampleChild/Child.cs @@ -14,20 +14,4 @@ public void Dispose() { } } - - public class Child0 : IChild, IDisposable - { - public Child0( - IInternalChild innerChild){} - - public void Dispose() - { - } - } - - public class Child1 : IChild - { - public Child1( - IInternalChild innerChild){} - } } diff --git a/SampleChild/InternalChild.cs b/SampleChild/InternalChild.cs index 8b651758..f1ed9700 100644 --- a/SampleChild/InternalChild.cs +++ b/SampleChild/InternalChild.cs @@ -1,19 +1,27 @@ +using System; + namespace MrMeeseeks.DIE.SampleChild { public interface IInternalChild {} - internal class InternalChild : IInternalChild + internal class InternalChild : IInternalChild, IDisposable { - public InternalChild(IYetAnotherInternalChild yetAnotherInternalChild) + public InternalChild(Lazy yetAnotherInternalChild) { } + + public void Dispose() + { + } } public interface IYetAnotherInternalChild {} - internal class YetAnotherInternalChild : IYetAnotherInternalChild + internal class YetAnotherInternalChild : IYetAnotherInternalChild, IDisposable { - + public void Dispose() + { + } } } \ No newline at end of file diff --git a/Spy/ExecuteImpl.cs b/Spy/ExecuteImpl.cs index 90da1596..e95b0b7c 100644 --- a/Spy/ExecuteImpl.cs +++ b/Spy/ExecuteImpl.cs @@ -10,16 +10,16 @@ internal interface IExecute internal class ExecuteImpl : IExecute { private readonly GeneratorExecutionContext _context; - private readonly IContainerGenerator _containerGenerator; + private readonly ITypeReportGenerator _typeReportGenerator; private readonly IDiagLogger _diagLogger; public ExecuteImpl( GeneratorExecutionContext context, - IContainerGenerator containerGenerator, + ITypeReportGenerator typeReportGenerator, IDiagLogger diagLogger) { _context = context; - _containerGenerator = containerGenerator; + _typeReportGenerator = typeReportGenerator; _diagLogger = diagLogger; } @@ -27,7 +27,7 @@ public void Execute() { _diagLogger.Log("Start Execute"); - _containerGenerator.Generate( + _typeReportGenerator.Generate( _context.Compilation.Assembly.Name); _diagLogger.Log("End Execute"); diff --git a/Spy/GenerateContainer.cs b/Spy/GenerateContainer.cs deleted file mode 100644 index ca495bcc..00000000 --- a/Spy/GenerateContainer.cs +++ /dev/null @@ -1,72 +0,0 @@ -using System.Linq; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.Text; -using System.Text; - -namespace MrMeeseeks.DIE.Spy -{ - internal interface IContainerGenerator - { - void Generate(string namespaceName); - } - - internal class ContainerGenerator : IContainerGenerator - { - private readonly GeneratorExecutionContext _context; - private readonly IGetAllImplementations _getAllImplementations; - - public ContainerGenerator( - GeneratorExecutionContext context, - IGetAllImplementations getAllImplementations) - { - _context = context; - _getAllImplementations = getAllImplementations; - } - - public void Generate(string namespaceName) - { - var generatedContainer = new StringBuilder() - .AppendLine($"namespace {namespaceName}") - .AppendLine($"{{") - .AppendLine($" public class PublicTypes") - .AppendLine($" {{") - ; - - var i = -1; - foreach (var type in _getAllImplementations.AllImplementations.Where(t => t.DeclaredAccessibility == Accessibility.Public)) - { - generatedContainer = generatedContainer - .AppendLine($" public {type.FullName()} Type{++i} {{ get; }}") - ; - } - - generatedContainer = generatedContainer - .AppendLine($" }}") - .AppendLine($" internal class InternalTypes") - .AppendLine($" {{") - ; - - i = -1; - foreach (var type in _getAllImplementations.AllImplementations.Where(t => t.DeclaredAccessibility == Accessibility.Internal)) - { - generatedContainer = generatedContainer - .AppendLine($" internal {type.FullName()} Type{++i} {{ get; }}") - ; - } - - generatedContainer = generatedContainer - .AppendLine($" }}") - .AppendLine($"}}") - ; - - var containerSource = CSharpSyntaxTree - .ParseText(SourceText.From(generatedContainer.ToString(), Encoding.UTF8)) - .GetRoot() - .NormalizeWhitespace() - .SyntaxTree - .GetText(); - _context.AddSource($"PublicTypes.g.cs", containerSource); - } - } -} diff --git a/Spy/GetAllImplementations.cs b/Spy/GetAllImplementations.cs index 0750365f..58d51464 100644 --- a/Spy/GetAllImplementations.cs +++ b/Spy/GetAllImplementations.cs @@ -8,19 +8,19 @@ namespace MrMeeseeks.DIE.Spy { internal interface IGetAllImplementations { - IReadOnlyList AllImplementations { get; } + IReadOnlyList AllNonStaticImplementations { get; } } internal class GetAllImplementations : IGetAllImplementations { - private GeneratorExecutionContext _context; + private readonly GeneratorExecutionContext _context; public GetAllImplementations(GeneratorExecutionContext context) { _context = context; } - public IReadOnlyList AllImplementations => new ReadOnlyCollection(_context.Compilation.SyntaxTrees + public IReadOnlyList AllNonStaticImplementations => new ReadOnlyCollection(_context.Compilation.SyntaxTrees .Select(st => (st, _context.Compilation.GetSemanticModel(st))) .SelectMany(t => t.st .GetRoot() @@ -29,6 +29,7 @@ public GetAllImplementations(GeneratorExecutionContext context) .Select(c => t.Item2.GetDeclaredSymbol(c)) .Where(c => c is not null) .OfType()) + .Where(nts => !nts.IsStatic) .ToList()); } } diff --git a/Spy/RoslynExtensions.cs b/Spy/RoslynExtensions.cs deleted file mode 100644 index dfb56889..00000000 --- a/Spy/RoslynExtensions.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Microsoft.CodeAnalysis; - -namespace MrMeeseeks.DIE.Spy -{ - internal static class RoslynExtensions - { - // Picked from https://github.com/YairHalberstadt/stronginject Thank you! - public static string FullName(this ITypeSymbol type) => - type.ToDisplayString(new SymbolDisplayFormat( - globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Included, - typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces, - genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters, - parameterOptions: SymbolDisplayParameterOptions.IncludeType | SymbolDisplayParameterOptions.IncludeParamsRefOut, - memberOptions: SymbolDisplayMemberOptions.IncludeRef)); - } -} \ No newline at end of file diff --git a/Spy/SourceGenerator.cs b/Spy/SourceGenerator.cs index 474bdd3e..47e7e68a 100644 --- a/Spy/SourceGenerator.cs +++ b/Spy/SourceGenerator.cs @@ -13,8 +13,8 @@ public void Execute(GeneratorExecutionContext context) { IDiagLogger diagLogger = new DiagLogger(context); IGetAllImplementations getAllImplementations = new GetAllImplementations(context); - IContainerGenerator containerGenerator = new ContainerGenerator(context, getAllImplementations); - IExecute execute = new ExecuteImpl(context, containerGenerator, diagLogger); + ITypeReportGenerator typeReportGenerator = new TypeReportGenerator(context, getAllImplementations); + IExecute execute = new ExecuteImpl(context, typeReportGenerator, diagLogger); execute.Execute(); } diff --git a/Spy/TypeReportGenerator.cs b/Spy/TypeReportGenerator.cs new file mode 100644 index 00000000..5630d698 --- /dev/null +++ b/Spy/TypeReportGenerator.cs @@ -0,0 +1,102 @@ +using System.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Text; +using System.Text; + +namespace MrMeeseeks.DIE.Spy +{ + internal interface ITypeReportGenerator + { + void Generate(string namespaceName); + } + + internal class TypeReportGenerator : ITypeReportGenerator + { + private readonly GeneratorExecutionContext _context; + private readonly IGetAllImplementations _getAllImplementations; + + public TypeReportGenerator( + GeneratorExecutionContext context, + IGetAllImplementations getAllImplementations) + { + _context = context; + _getAllImplementations = getAllImplementations; + } + + public void Generate(string namespaceName) + { + var generatedContainer = new StringBuilder() + .AppendLine($"namespace {namespaceName}") + .AppendLine("{"); + + generatedContainer = GenerateBody(Accessibility.Public, _getAllImplementations, generatedContainer); + + generatedContainer = GenerateBody(Accessibility.Internal, _getAllImplementations, generatedContainer); + + generatedContainer = generatedContainer + .AppendLine("}"); + + var containerSource = CSharpSyntaxTree + .ParseText(SourceText.From(generatedContainer.ToString(), Encoding.UTF8)) + .GetRoot() + .NormalizeWhitespace() + .SyntaxTree + .GetText(); + _context.AddSource("TypeReport.g.cs", containerSource); + + static StringBuilder GenerateBody(Accessibility accessModifier, IGetAllImplementations getAllImplementations, StringBuilder generatedContainer) + { + var lowerCaseAccessModifier = accessModifier.ToString().ToLower(); + var pascalCaseAccessModifier = accessModifier.ToString(); + + var types = getAllImplementations + .AllNonStaticImplementations + .Where(t => t.DeclaredAccessibility == accessModifier) + .ToList(); + + generatedContainer = generatedContainer + .AppendLine($"{lowerCaseAccessModifier} interface I{pascalCaseAccessModifier}TypeReport") + .AppendLine("{"); + + var i = -1; + generatedContainer = types.Aggregate( + generatedContainer, + (current, type) => current.AppendLine( + $"{lowerCaseAccessModifier} {FullName(type)} Type{++i}{(type.TypeArguments.Length > 0 ? $"<{string.Join(", ", type.TypeArguments.Select(t => t.Name))}>" : "")}(){TypeArgumentsConstraintsString(type)};")); + + generatedContainer = generatedContainer + .AppendLine("}"); + + return generatedContainer; + } + + static string FullName(ISymbol type) => + type.ToDisplayString(new SymbolDisplayFormat( + globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Included, + typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces, + parameterOptions: SymbolDisplayParameterOptions.IncludeType | SymbolDisplayParameterOptions.IncludeParamsRefOut, + genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters, + memberOptions: SymbolDisplayMemberOptions.IncludeRef)); + + static string TypeArgumentsConstraintsString(INamedTypeSymbol namedTypeSymbol) + { + var displayStringWithoutConstraints = namedTypeSymbol.ToDisplayString(new SymbolDisplayFormat( + globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Included, + typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces, + parameterOptions: SymbolDisplayParameterOptions.IncludeType | SymbolDisplayParameterOptions.IncludeParamsRefOut, + genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters, + memberOptions: SymbolDisplayMemberOptions.IncludeRef)); + var displayStringWithConstraints = namedTypeSymbol.ToDisplayString(new SymbolDisplayFormat( + globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Included, + typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces, + parameterOptions: SymbolDisplayParameterOptions.IncludeType | SymbolDisplayParameterOptions.IncludeParamsRefOut, + genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters | SymbolDisplayGenericsOptions.IncludeTypeConstraints, + memberOptions: SymbolDisplayMemberOptions.IncludeRef)); + + var ret = displayStringWithConstraints.Remove(0, displayStringWithoutConstraints.Length); + return ret; + } + } + } +} From 04e804a9446d5fee84924803da394b6b4abf449a Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sun, 31 Oct 2021 17:25:56 +0100 Subject: [PATCH 013/162] IDisposable management --- Main/ContainerGenerator.cs | 70 +++++++++++++++----- Main/ExecuteContainer.cs | 35 ++++++++++ Main/ExecuteImpl.cs | 6 +- Main/Main.csproj | 4 +- Main/ResolutionTreeCreationErrorHarvester.cs | 3 + Main/ResolutionTreeFactory.cs | 64 ++++++++++++------ Main/ResolutionTreeItem.cs | 20 ++++-- Main/SourceGenerator.cs | 2 +- Main/WellKnownTypes.cs | 25 ++++++- Sample/Program.cs | 2 +- Sample/Sample.csproj | 2 +- Spy/TypeReportGenerator.cs | 2 +- 12 files changed, 183 insertions(+), 52 deletions(-) create mode 100644 Main/ExecuteContainer.cs diff --git a/Main/ContainerGenerator.cs b/Main/ContainerGenerator.cs index 169b215a..7e52e933 100644 --- a/Main/ContainerGenerator.cs +++ b/Main/ContainerGenerator.cs @@ -9,45 +9,74 @@ namespace MrMeeseeks.DIE { internal interface IContainerGenerator { - void Generate(IContainerInfo containerInfo, Resolvable resolvable); + void Generate(IContainerInfo containerInfo, ContainerResolution resolvable); } internal class ContainerGenerator : IContainerGenerator { private readonly GeneratorExecutionContext _context; + private readonly WellKnownTypes _wellKnownTypes; private readonly IDiagLogger _diagLogger; public ContainerGenerator( GeneratorExecutionContext context, + WellKnownTypes wellKnownTypes, IDiagLogger diagLogger) { _context = context; + _wellKnownTypes = wellKnownTypes; _diagLogger = diagLogger; } - public void Generate(IContainerInfo containerInfo, Resolvable resolvable) + public void Generate(IContainerInfo containerInfo, ContainerResolution containerResolution) { if (!containerInfo.IsValid || containerInfo.ResolutionRootType is null) { _diagLogger.Log($"return generation"); return; } + + var funcName = _wellKnownTypes.Func.ToDisplayString(new SymbolDisplayFormat( + globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Included, + typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces, + parameterOptions: SymbolDisplayParameterOptions.IncludeType | + SymbolDisplayParameterOptions.IncludeParamsRefOut, + memberOptions: SymbolDisplayMemberOptions.IncludeRef)); var generatedContainer = new StringBuilder() .AppendLine($"namespace {containerInfo.Namespace}") .AppendLine($"{{") .AppendLine($"partial class {containerInfo.Name}") .AppendLine($"{{") - .AppendLine($"public {resolvable.TypeFullName} Resolve()") + .AppendLine($"public TResult Run({funcName}<{containerResolution.TypeFullName}, TParam, TResult> func, TParam param)") .AppendLine($"{{"); - - generatedContainer = GenerateResolutionFunction(generatedContainer, resolvable); - + + generatedContainer = GenerateResolutionFunction(generatedContainer, containerResolution.DisposableCollection); + generatedContainer = generatedContainer - .AppendLine($"return {resolvable.Reference};") - .AppendLine($"}}"); + .AppendLine($"try") + .AppendLine($"{{"); + + generatedContainer = GenerateResolutionFunction(generatedContainer, containerResolution); generatedContainer = generatedContainer + .AppendLine($"return func({containerResolution.Reference}, param);") + .AppendLine($"}}") + .AppendLine($"finally") + .AppendLine($"{{") + .AppendLine($"foreach(var disposable in {containerResolution.DisposableCollection.Reference})") + .AppendLine($"{{") + .AppendLine($"try") + .AppendLine($"{{") + .AppendLine($"disposable.Dispose();") + .AppendLine($"}}") + .AppendLine($"catch({_wellKnownTypes.Exception.FullName()})") + .AppendLine($"{{") + .AppendLine($"// catch and ignore exceptions of individual disposals so the other disposals are triggered") + .AppendLine($"}}") + .AppendLine($"}}") + .AppendLine($"}}") + .AppendLine($"}}") .AppendLine($"}}") .AppendLine($"}}") ; @@ -62,7 +91,7 @@ public void Generate(IContainerInfo containerInfo, Resolvable resolvable) - static StringBuilder GenerateResolutionFunction( + StringBuilder GenerateResolutionFunction( StringBuilder stringBuilder, Resolvable resolution) { @@ -72,19 +101,22 @@ static StringBuilder GenerateResolutionFunction( return stringBuilder; } - static StringBuilder GenerateFields( + StringBuilder GenerateFields( StringBuilder stringBuilder, Resolvable resolution) { switch (resolution) { + case ContainerResolution(var rootResolution, _): + stringBuilder = GenerateFields(stringBuilder, rootResolution); + break; case InterfaceResolution(var reference, var typeFullName, Resolvable resolutionBase): stringBuilder = GenerateFields(stringBuilder, resolutionBase); stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); break; - case ConstructorResolution(var reference, var typeFullName, var parameters): + case ConstructorResolution(var reference, var typeFullName, _, var parameters): stringBuilder = parameters.Aggregate(stringBuilder, - (builder, tuple) => GenerateFields(builder, tuple.Dependency as Resolvable ?? throw new Exception())); + (builder, tuple) => GenerateFields(builder, tuple.Dependency)); stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); break; case FuncResolution(var reference, var typeFullName, _, _): @@ -103,22 +135,28 @@ static StringBuilder GenerateFields( return stringBuilder; } - static StringBuilder GenerateResolutions( + StringBuilder GenerateResolutions( StringBuilder stringBuilder, Resolvable resolution) { switch (resolution) { + case ContainerResolution(var rootResolution, var disposableCollectionResolution): + stringBuilder = GenerateResolutions(stringBuilder, rootResolution); + break; case InterfaceResolution(var reference, var typeFullName, Resolvable resolutionBase): stringBuilder = GenerateResolutions(stringBuilder, resolutionBase); stringBuilder = stringBuilder.AppendLine( $"{reference} = ({typeFullName}) {resolutionBase.Reference};"); break; - case ConstructorResolution(var reference, var typeFullName, var parameters): + case ConstructorResolution(var reference, var typeFullName, var disposableCollectionResolution, var parameters): stringBuilder = parameters.Aggregate(stringBuilder, - (builder, tuple) => GenerateResolutions(builder, tuple.Dependency as Resolvable ?? throw new Exception())); + (builder, tuple) => GenerateResolutions(builder, tuple.Dependency ?? throw new Exception())); stringBuilder = stringBuilder.AppendLine( - $"{reference} = new {typeFullName}({string.Join(", ", parameters.Select(d => $"{d.name}: {(d.Dependency as Resolvable)?.Reference}"))});"); + $"{reference} = new {typeFullName}({string.Join(", ", parameters.Select(d => $"{d.name}: {d.Dependency?.Reference}"))});"); + if (disposableCollectionResolution is {}) + stringBuilder = stringBuilder.AppendLine( + $"{disposableCollectionResolution.Reference}.Add(({_wellKnownTypes.Disposable.FullName()}) {reference});"); break; case FuncResolution(var reference, _, var parameter, Resolvable resolutionBase): stringBuilder = stringBuilder.AppendLine($"{reference} = ({string.Join(", ", parameter.Select(fpr => fpr.Reference))}) =>"); diff --git a/Main/ExecuteContainer.cs b/Main/ExecuteContainer.cs new file mode 100644 index 00000000..a558902d --- /dev/null +++ b/Main/ExecuteContainer.cs @@ -0,0 +1,35 @@ +using Microsoft.CodeAnalysis; +using StrongInject; + +namespace MrMeeseeks.DIE +{ + public interface IExecuteContainer + { + + } + + [Register(typeof(ExecuteImpl), typeof(IExecute))] + [Register(typeof(ContainerGenerator), typeof(IContainerGenerator))] + [Register(typeof(ContainerErrorGenerator), typeof(IContainerErrorGenerator))] + [Register(typeof(ResolutionTreeFactory), typeof(IResolutionTreeFactory))] + [Register(typeof(ResolutionTreeCreationErrorHarvester), typeof(IResolutionTreeCreationErrorHarvester))] + [Register(typeof(ContainerInfo), typeof(IContainerInfo))] + [Register(typeof(DiagLogger), typeof(IDiagLogger))] + [Register(typeof(TypeToImplementationsMapper), typeof(ITypeToImplementationsMapper))] + [Register(typeof(ReferenceGeneratorFactory), typeof(IReferenceGeneratorFactory))] + [Register(typeof(GetAllImplementations), typeof(IGetAllImplementations))] + [Register(typeof(GetAssemblyAttributes), typeof(IGetAssemblyAttributes))] + [Register(typeof(ReferenceGenerator), typeof(IReferenceGenerator))] + internal partial class ExecuteContainer : IExecuteContainer, StrongInject.IContainer + { + [Instance] public GeneratorExecutionContext Context { get; } + [Instance] public WellKnownTypes WellKnownTypes { get; } + + public ExecuteContainer(GeneratorExecutionContext context) + { + Context = context; + WellKnownTypes.TryCreate(context.Compilation, out var wellKnownTypes); + WellKnownTypes = wellKnownTypes; + } + } +} \ No newline at end of file diff --git a/Main/ExecuteImpl.cs b/Main/ExecuteImpl.cs index 1d030929..720a72df 100644 --- a/Main/ExecuteImpl.cs +++ b/Main/ExecuteImpl.cs @@ -60,12 +60,12 @@ public void Execute() var containerInfo = _containerInfoFactory(namedTypeSymbol); if (containerInfo.IsValid && containerInfo.ResolutionRootType is { }) { - var resolutionRoot = _resolutionTreeFactory.Create(containerInfo.ResolutionRootType); - var errorTreeItems = _resolutionTreeCreationErrorHarvester.Harvest(resolutionRoot); + var containerResolution = _resolutionTreeFactory.Create(containerInfo.ResolutionRootType); + var errorTreeItems = _resolutionTreeCreationErrorHarvester.Harvest(containerResolution); if (errorTreeItems.Any()) _containerErrorGenerator.Generate(containerInfo, errorTreeItems); else - _containerGenerator.Generate(containerInfo, resolutionRoot as Resolvable ?? throw new Exception()); + _containerGenerator.Generate(containerInfo, containerResolution); } else throw new NotImplementedException("Handle non-valid container information"); } diff --git a/Main/Main.csproj b/Main/Main.csproj index 608c4fb5..90b5dc43 100644 --- a/Main/Main.csproj +++ b/Main/Main.csproj @@ -7,7 +7,9 @@ $(RootNamespace) true - true + true + true + $(BaseIntermediateOutputPath)\GeneratedFiles diff --git a/Main/ResolutionTreeCreationErrorHarvester.cs b/Main/ResolutionTreeCreationErrorHarvester.cs index 4271568f..9c2972d2 100644 --- a/Main/ResolutionTreeCreationErrorHarvester.cs +++ b/Main/ResolutionTreeCreationErrorHarvester.cs @@ -20,6 +20,9 @@ static void Inner(ResolutionTreeItem item, ICollection errorTreeI { switch (item) { + case ContainerResolution containerResolution: + Inner(containerResolution.RootResolution, errorTreeItems); + break; case ErrorTreeItem errorTreeItem: errorTreeItems.Add(errorTreeItem); break; diff --git a/Main/ResolutionTreeFactory.cs b/Main/ResolutionTreeFactory.cs index e0069e52..ab3ad7f0 100644 --- a/Main/ResolutionTreeFactory.cs +++ b/Main/ResolutionTreeFactory.cs @@ -8,7 +8,7 @@ namespace MrMeeseeks.DIE { internal interface IResolutionTreeFactory { - ResolutionTreeItem Create(ITypeSymbol root); + ContainerResolution Create(ITypeSymbol root); } internal class ResolutionTreeFactory : IResolutionTreeFactory @@ -27,12 +27,28 @@ public ResolutionTreeFactory( _wellKnownTypes = wellKnownTypes; } - public ResolutionTreeItem Create(ITypeSymbol type) => Create( - type, - _referenceGeneratorFactory.Create(), - Array.Empty<(ITypeSymbol Type, FuncParameterResolution Resolution)>()); - - private ResolutionTreeItem Create(ITypeSymbol type, IReferenceGenerator referenceGenerator, IReadOnlyList<(ITypeSymbol Type, FuncParameterResolution Resolution)> currentFuncParameters) + public ContainerResolution Create(ITypeSymbol type) + { + var referenceGenerator = _referenceGeneratorFactory.Create(); + var disposableCollectionResolution = new DisposableCollectionResolution( + referenceGenerator.Generate(_wellKnownTypes.ConcurrentBagOfDisposable), + _wellKnownTypes.ConcurrentBagOfDisposable.FullName()); + var rootResolution = Create( + type, + referenceGenerator, + Array.Empty<(ITypeSymbol Type, FuncParameterResolution Resolution)>(), + disposableCollectionResolution); + + return new ContainerResolution( + rootResolution, + disposableCollectionResolution); + } + + private Resolvable Create( + ITypeSymbol type, + IReferenceGenerator referenceGenerator, + IReadOnlyList<(ITypeSymbol Type, FuncParameterResolution Resolution)> currentFuncParameters, + DisposableCollectionResolution disposableCollectionResolution) { if (currentFuncParameters.FirstOrDefault(t => SymbolEqualityComparer.Default.Equals(t.Type.OriginalDefinition, type.OriginalDefinition)) is { Type: not null, Resolution: not null } funcParameter) { @@ -46,21 +62,23 @@ private ResolutionTreeItem Create(ITypeSymbol type, IReferenceGenerator referenc { return new ErrorTreeItem(namedTypeSymbol.TypeArguments.Length switch { - 0 => $"[{type.FullName()}] Lazy: No type argument", - > 1 => $"[{type.FullName()}] Lazy: more than one type argument", - _ => $"[{type.FullName()}] Lazy: {namedTypeSymbol.TypeArguments[0].FullName()} is not a named type symbol" + 0 => $"[{namedTypeSymbol.FullName()}] Lazy: No type argument", + > 1 => $"[{namedTypeSymbol.FullName()}] Lazy: more than one type argument", + _ => $"[{namedTypeSymbol.FullName()}] Lazy: {namedTypeSymbol.TypeArguments[0].FullName()} is not a named type symbol" }); } var dependency = Create( genericType, _referenceGeneratorFactory.Create(), - Array.Empty<(ITypeSymbol Type, FuncParameterResolution Resolution)>()); + Array.Empty<(ITypeSymbol Type, FuncParameterResolution Resolution)>(), + disposableCollectionResolution); return new ConstructorResolution( - referenceGenerator.Generate(type), - type.FullName(), - new ReadOnlyCollection<(string Name, ResolutionTreeItem Dependency)>( - new List<(string Name, ResolutionTreeItem Dependency)> + referenceGenerator.Generate(namedTypeSymbol), + namedTypeSymbol.FullName(), + ImplementsIDisposable(namedTypeSymbol, _wellKnownTypes, disposableCollectionResolution), + new ReadOnlyCollection<(string Name, Resolvable Dependency)>( + new List<(string Name, Resolvable Dependency)> { ( "valueFactory", @@ -93,7 +111,7 @@ private ResolutionTreeItem Create(ITypeSymbol type, IReferenceGenerator referenc var itemFullName = itemType.FullName(); var items = _typeToImplementationsMapper .Map(itemType) - .Select(i => Create(i, referenceGenerator, currentFuncParameters)) + .Select(i => Create(i, referenceGenerator, currentFuncParameters, disposableCollectionResolution)) .ToList(); return new CollectionResolution( referenceGenerator.Generate(type), @@ -119,7 +137,7 @@ private ResolutionTreeItem Create(ITypeSymbol type, IReferenceGenerator referenc return new InterfaceResolution( referenceGenerator.Generate(type), type.FullName(), - Create(implementationType, referenceGenerator, currentFuncParameters)); + Create(implementationType, referenceGenerator, currentFuncParameters, disposableCollectionResolution)); } if (type.TypeKind == TypeKind.Class) @@ -149,7 +167,8 @@ private ResolutionTreeItem Create(ITypeSymbol type, IReferenceGenerator referenc return new ConstructorResolution( referenceGenerator.Generate(implementationType), implementationType.FullName(), - new ReadOnlyCollection<(string Name, ResolutionTreeItem Dependency)>(constructor + ImplementsIDisposable(implementationType, _wellKnownTypes, disposableCollectionResolution), + new ReadOnlyCollection<(string Name, Resolvable Dependency)>(constructor .Parameters .Select(p => { @@ -161,7 +180,8 @@ private ResolutionTreeItem Create(ITypeSymbol type, IReferenceGenerator referenc p.Name, Create(parameterType, referenceGenerator, - currentFuncParameters)); + currentFuncParameters, + disposableCollectionResolution)); }) .ToList())); } @@ -181,7 +201,8 @@ private ResolutionTreeItem Create(ITypeSymbol type, IReferenceGenerator referenc var dependency = Create( returnType, innerReferenceGenerator, - parameterTypes); + parameterTypes, + disposableCollectionResolution); return new FuncResolution( referenceGenerator.Generate(type), type.FullName(), @@ -190,6 +211,9 @@ private ResolutionTreeItem Create(ITypeSymbol type, IReferenceGenerator referenc } return new ErrorTreeItem($"[{type.FullName()}] Couldn't process in resolution tree creation."); + + static DisposableCollectionResolution? ImplementsIDisposable(INamedTypeSymbol type, WellKnownTypes wellKnownTypes, DisposableCollectionResolution disposableCollectionResolution) => + type.AllInterfaces.Contains(wellKnownTypes.Disposable) ? disposableCollectionResolution : null; } } } \ No newline at end of file diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index 85ed1b30..82a4ce6d 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -1,16 +1,17 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; namespace MrMeeseeks.DIE { internal abstract record ResolutionTreeItem; - - internal record ErrorTreeItem( - string Message) : ResolutionTreeItem; internal abstract record Resolvable( string Reference, string TypeFullName) : ResolutionTreeItem; + internal record ErrorTreeItem( + string Message) : Resolvable("error_99_99", "Error"); + internal record InterfaceResolution( string Reference, string TypeFullName, @@ -19,7 +20,8 @@ internal record InterfaceResolution( internal record ConstructorResolution( string Reference, string TypeFullName, - IReadOnlyList<(string name, ResolutionTreeItem Dependency)> Parameter) : Resolvable(Reference, TypeFullName); + DisposableCollectionResolution? DisposableCollectionResolution, + IReadOnlyList<(string name, Resolvable Dependency)> Parameter) : Resolvable(Reference, TypeFullName); internal record FuncParameterResolution( string Reference, @@ -36,4 +38,12 @@ internal record CollectionResolution( string TypeFullName, string ItemFullName, IReadOnlyList Parameter) : Resolvable(Reference, TypeFullName); + + internal record DisposableCollectionResolution( + string Reference, + string TypeFullName) : ConstructorResolution(Reference, TypeFullName, null, Array.Empty<(string name, Resolvable Dependency)>()); + + internal record ContainerResolution( + Resolvable RootResolution, + DisposableCollectionResolution DisposableCollection) : Resolvable(RootResolution.Reference, RootResolution.TypeFullName); } diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index 97b1959c..5eb94ab7 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -19,7 +19,7 @@ public void Execute(GeneratorExecutionContext context) var getAssemblyAttributes = new GetAssemblyAttributes(context); var _ = WellKnownTypes.TryCreate(context.Compilation, out var wellKnownTypes); var typeToImplementationMapper = new TypeToImplementationsMapper(wellKnownTypes, getAllImplementations, getAssemblyAttributes); - var containerGenerator = new ContainerGenerator(context, diagLogger); + var containerGenerator = new ContainerGenerator(context, wellKnownTypes, diagLogger); var referenceGeneratorFactory = new ReferenceGeneratorFactory(ReferenceGeneratorFactory); var resolutionTreeFactory = new ResolutionTreeFactory(typeToImplementationMapper, referenceGeneratorFactory, wellKnownTypes); var containerErrorGenerator = new ContainerErrorGenerator(context); diff --git a/Main/WellKnownTypes.cs b/Main/WellKnownTypes.cs index e28c046d..06da72c6 100644 --- a/Main/WellKnownTypes.cs +++ b/Main/WellKnownTypes.cs @@ -14,7 +14,11 @@ internal record WellKnownTypes( INamedTypeSymbol ObjectDisposedException, INamedTypeSymbol Enumerable1, INamedTypeSymbol ReadOnlyCollection1, - INamedTypeSymbol ReadOnlyList1) + INamedTypeSymbol ReadOnlyList1, + INamedTypeSymbol ConcurrentBagOfDisposable, + INamedTypeSymbol Action, + INamedTypeSymbol Func, + INamedTypeSymbol Exception) { public static bool TryCreate(Compilation compilation, out WellKnownTypes wellKnownTypes) { @@ -29,6 +33,13 @@ public static bool TryCreate(Compilation compilation, out WellKnownTypes wellKno var iEnumerable1 = compilation.GetTypeOrReport("System.Collections.Generic.IEnumerable`1"); var iReadOnlyCollection1 = compilation.GetTypeOrReport("System.Collections.Generic.IReadOnlyCollection`1"); var iReadOnlyList1 = compilation.GetTypeOrReport("System.Collections.Generic.IReadOnlyList`1"); + var concurrentBag = compilation.GetTypeOrReport("System.Collections.Concurrent.ConcurrentBag`1"); + var concurrentBagOfDisposable = iDisposable is null + ? null + : concurrentBag?.Construct(iDisposable); + var action = compilation.GetTypeOrReport("System.Action"); + var func = compilation.GetTypeOrReport("System.Func`3"); + var exception = compilation.GetTypeOrReport("System.Exception"); var spyAttribute = compilation .GetTypeByMetadataName(typeof(SpyAttribute).FullName ?? ""); @@ -44,7 +55,11 @@ public static bool TryCreate(Compilation compilation, out WellKnownTypes wellKno || objectDisposedException is null || iEnumerable1 is null || iReadOnlyCollection1 is null - || iReadOnlyList1 is null) + || iReadOnlyList1 is null + || concurrentBagOfDisposable is null + || action is null + || func is null + || exception is null) { wellKnownTypes = null!; return false; @@ -62,7 +77,11 @@ public static bool TryCreate(Compilation compilation, out WellKnownTypes wellKno ObjectDisposedException: objectDisposedException, Enumerable1: iEnumerable1, ReadOnlyCollection1: iReadOnlyCollection1, - ReadOnlyList1: iReadOnlyList1); + ReadOnlyList1: iReadOnlyList1, + ConcurrentBagOfDisposable: concurrentBagOfDisposable, + Action: action, + Func: func, + Exception: exception); return true; } diff --git a/Sample/Program.cs b/Sample/Program.cs index 4d11aef8..a82396ab 100644 --- a/Sample/Program.cs +++ b/Sample/Program.cs @@ -2,6 +2,6 @@ using StrongInject; System.Console.WriteLine("Hello, world!"); -System.Console.WriteLine(new Container().Resolve().Text); +System.Console.WriteLine(new Container().Run((c, _) => c.Text, new object())); System.Console.WriteLine(new StrongInjectContainer().Run(c => c.Text)); diff --git a/Sample/Sample.csproj b/Sample/Sample.csproj index 0f8770f7..9876144f 100644 --- a/Sample/Sample.csproj +++ b/Sample/Sample.csproj @@ -14,7 +14,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/Spy/TypeReportGenerator.cs b/Spy/TypeReportGenerator.cs index 5630d698..db6e74e2 100644 --- a/Spy/TypeReportGenerator.cs +++ b/Spy/TypeReportGenerator.cs @@ -63,7 +63,7 @@ static StringBuilder GenerateBody(Accessibility accessModifier, IGetAllImplement generatedContainer = types.Aggregate( generatedContainer, (current, type) => current.AppendLine( - $"{lowerCaseAccessModifier} {FullName(type)} Type{++i}{(type.TypeArguments.Length > 0 ? $"<{string.Join(", ", type.TypeArguments.Select(t => t.Name))}>" : "")}(){TypeArgumentsConstraintsString(type)};")); + $"{FullName(type)} Type{++i}{(type.TypeArguments.Length > 0 ? $"<{string.Join(", ", type.TypeArguments.Select(t => t.Name))}>" : "")}(){TypeArgumentsConstraintsString(type)};")); generatedContainer = generatedContainer .AppendLine("}"); From b0976b24b4b3e26994982bc845af655a358da998 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sun, 31 Oct 2021 20:59:44 +0100 Subject: [PATCH 014/162] Option to declare types transient --- Main/CheckDisposalManagement.cs | 48 ++++++++++++++++++ Main/ExecuteContainer.cs | 35 ------------- Main/GetAllImplementations.cs | 30 +++++++---- Main/ResolutionTreeFactory.cs | 17 +++++-- Main/SourceGenerator.cs | 10 ++-- Main/SpyAttribute.cs | 7 +++ Main/TypeToImplementationMapper.cs | 80 +++--------------------------- Main/TypesFromAttributes.cs | 61 +++++++++++++++++++++++ Main/WellKnownTypes.cs | 6 +++ Sample/Container.cs | 3 ++ 10 files changed, 170 insertions(+), 127 deletions(-) create mode 100644 Main/CheckDisposalManagement.cs delete mode 100644 Main/ExecuteContainer.cs create mode 100644 Main/TypesFromAttributes.cs diff --git a/Main/CheckDisposalManagement.cs b/Main/CheckDisposalManagement.cs new file mode 100644 index 00000000..a3cacca7 --- /dev/null +++ b/Main/CheckDisposalManagement.cs @@ -0,0 +1,48 @@ +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using Microsoft.CodeAnalysis; + +namespace MrMeeseeks.DIE +{ + public interface ICheckDisposalManagement + { + bool ShouldBeManaged(INamedTypeSymbol type); + } + + internal class CheckDisposalManagement : ICheckDisposalManagement + { + private readonly ImmutableHashSet _transientTypes; + + public CheckDisposalManagement( + IGetAllImplementations getAllImplementations, + ITypesFromAttributes typesFromAttributes) + { + _transientTypes = getAllImplementations + .AllImplementations + .Where(i => + { + var derivedTypes = AllDerivedTypes(i); + return typesFromAttributes.Transient.Any(t => derivedTypes.Contains(t, SymbolEqualityComparer.Default)); + }) + .ToImmutableHashSet(SymbolEqualityComparer.Default); + + IEnumerable AllDerivedTypes(INamedTypeSymbol type) + { + var concreteTypes = new List(); + var temp = type; + while (temp is {}) + { + concreteTypes.Add(temp); + temp = temp.BaseType; + } + return type + .AllInterfaces + .Append(type) + .Concat(concreteTypes); + } + } + + public bool ShouldBeManaged(INamedTypeSymbol type) => !_transientTypes.Contains(type); + } +} \ No newline at end of file diff --git a/Main/ExecuteContainer.cs b/Main/ExecuteContainer.cs deleted file mode 100644 index a558902d..00000000 --- a/Main/ExecuteContainer.cs +++ /dev/null @@ -1,35 +0,0 @@ -using Microsoft.CodeAnalysis; -using StrongInject; - -namespace MrMeeseeks.DIE -{ - public interface IExecuteContainer - { - - } - - [Register(typeof(ExecuteImpl), typeof(IExecute))] - [Register(typeof(ContainerGenerator), typeof(IContainerGenerator))] - [Register(typeof(ContainerErrorGenerator), typeof(IContainerErrorGenerator))] - [Register(typeof(ResolutionTreeFactory), typeof(IResolutionTreeFactory))] - [Register(typeof(ResolutionTreeCreationErrorHarvester), typeof(IResolutionTreeCreationErrorHarvester))] - [Register(typeof(ContainerInfo), typeof(IContainerInfo))] - [Register(typeof(DiagLogger), typeof(IDiagLogger))] - [Register(typeof(TypeToImplementationsMapper), typeof(ITypeToImplementationsMapper))] - [Register(typeof(ReferenceGeneratorFactory), typeof(IReferenceGeneratorFactory))] - [Register(typeof(GetAllImplementations), typeof(IGetAllImplementations))] - [Register(typeof(GetAssemblyAttributes), typeof(IGetAssemblyAttributes))] - [Register(typeof(ReferenceGenerator), typeof(IReferenceGenerator))] - internal partial class ExecuteContainer : IExecuteContainer, StrongInject.IContainer - { - [Instance] public GeneratorExecutionContext Context { get; } - [Instance] public WellKnownTypes WellKnownTypes { get; } - - public ExecuteContainer(GeneratorExecutionContext context) - { - Context = context; - WellKnownTypes.TryCreate(context.Compilation, out var wellKnownTypes); - WellKnownTypes = wellKnownTypes; - } - } -} \ No newline at end of file diff --git a/Main/GetAllImplementations.cs b/Main/GetAllImplementations.cs index c19d0c06..6b06e9cb 100644 --- a/Main/GetAllImplementations.cs +++ b/Main/GetAllImplementations.cs @@ -1,7 +1,6 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using System.Collections.Generic; -using System.Collections.ObjectModel; using System.Linq; namespace MrMeeseeks.DIE @@ -13,22 +12,31 @@ internal interface IGetAllImplementations internal class GetAllImplementations : IGetAllImplementations { - private readonly GeneratorExecutionContext _context; - - public GetAllImplementations(GeneratorExecutionContext context) + public GetAllImplementations( + GeneratorExecutionContext context, + ITypesFromAttributes typesFromAttributes) { - _context = context; - } - - public IReadOnlyList AllImplementations => new ReadOnlyCollection(_context.Compilation.SyntaxTrees - .Select(st => (st, _context.Compilation.GetSemanticModel(st))) + var implementationsOfThisAssembly = context.Compilation.SyntaxTrees + .Select(st => (st, context.Compilation.GetSemanticModel(st))) .SelectMany(t => t.st .GetRoot() .DescendantNodesAndSelf() .OfType() .Select(c => t.Item2.GetDeclaredSymbol(c)) .Where(c => c is not null) - .OfType()) - .ToList()); + .OfType()); + + var spiedImplementations = typesFromAttributes + .Spy + .SelectMany(t => t?.GetMembers() + .OfType() + .Where(ms => !ms.ReturnsVoid) + .Select(ms => ms.ReturnType) + .OfType()); + + AllImplementations = implementationsOfThisAssembly.Concat(spiedImplementations).ToList(); + } + + public IReadOnlyList AllImplementations { get; } } } diff --git a/Main/ResolutionTreeFactory.cs b/Main/ResolutionTreeFactory.cs index ab3ad7f0..6e49cb5d 100644 --- a/Main/ResolutionTreeFactory.cs +++ b/Main/ResolutionTreeFactory.cs @@ -15,15 +15,18 @@ internal class ResolutionTreeFactory : IResolutionTreeFactory { private readonly ITypeToImplementationsMapper _typeToImplementationsMapper; private readonly IReferenceGeneratorFactory _referenceGeneratorFactory; + private readonly ICheckDisposalManagement _checkDisposalManagement; private readonly WellKnownTypes _wellKnownTypes; public ResolutionTreeFactory( ITypeToImplementationsMapper typeToImplementationsMapper, IReferenceGeneratorFactory referenceGeneratorFactory, + ICheckDisposalManagement checkDisposalManagement, WellKnownTypes wellKnownTypes) { _typeToImplementationsMapper = typeToImplementationsMapper; _referenceGeneratorFactory = referenceGeneratorFactory; + _checkDisposalManagement = checkDisposalManagement; _wellKnownTypes = wellKnownTypes; } @@ -76,7 +79,7 @@ private Resolvable Create( return new ConstructorResolution( referenceGenerator.Generate(namedTypeSymbol), namedTypeSymbol.FullName(), - ImplementsIDisposable(namedTypeSymbol, _wellKnownTypes, disposableCollectionResolution), + ImplementsIDisposable(namedTypeSymbol, _wellKnownTypes, disposableCollectionResolution, _checkDisposalManagement), new ReadOnlyCollection<(string Name, Resolvable Dependency)>( new List<(string Name, Resolvable Dependency)> { @@ -167,7 +170,7 @@ private Resolvable Create( return new ConstructorResolution( referenceGenerator.Generate(implementationType), implementationType.FullName(), - ImplementsIDisposable(implementationType, _wellKnownTypes, disposableCollectionResolution), + ImplementsIDisposable(implementationType, _wellKnownTypes, disposableCollectionResolution, _checkDisposalManagement), new ReadOnlyCollection<(string Name, Resolvable Dependency)>(constructor .Parameters .Select(p => @@ -212,8 +215,14 @@ private Resolvable Create( return new ErrorTreeItem($"[{type.FullName()}] Couldn't process in resolution tree creation."); - static DisposableCollectionResolution? ImplementsIDisposable(INamedTypeSymbol type, WellKnownTypes wellKnownTypes, DisposableCollectionResolution disposableCollectionResolution) => - type.AllInterfaces.Contains(wellKnownTypes.Disposable) ? disposableCollectionResolution : null; + static DisposableCollectionResolution? ImplementsIDisposable( + INamedTypeSymbol type, + WellKnownTypes wellKnownTypes, + DisposableCollectionResolution disposableCollectionResolution, + ICheckDisposalManagement checkDisposalManagement) => + type.AllInterfaces.Contains(wellKnownTypes.Disposable) && checkDisposalManagement.ShouldBeManaged(type) + ? disposableCollectionResolution + : null; } } } \ No newline at end of file diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index 5eb94ab7..a1b4ad64 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -15,13 +15,15 @@ public void Initialize(GeneratorInitializationContext context) public void Execute(GeneratorExecutionContext context) { var diagLogger = new DiagLogger(context); - var getAllImplementations = new GetAllImplementations(context); - var getAssemblyAttributes = new GetAssemblyAttributes(context); var _ = WellKnownTypes.TryCreate(context.Compilation, out var wellKnownTypes); - var typeToImplementationMapper = new TypeToImplementationsMapper(wellKnownTypes, getAllImplementations, getAssemblyAttributes); + var getAssemblyAttributes = new GetAssemblyAttributes(context); + var typesFromAttributes = new TypesFromAttributes(wellKnownTypes, getAssemblyAttributes); + var getAllImplementations = new GetAllImplementations(context, typesFromAttributes); + var typeToImplementationMapper = new TypeToImplementationsMapper(getAllImplementations); var containerGenerator = new ContainerGenerator(context, wellKnownTypes, diagLogger); var referenceGeneratorFactory = new ReferenceGeneratorFactory(ReferenceGeneratorFactory); - var resolutionTreeFactory = new ResolutionTreeFactory(typeToImplementationMapper, referenceGeneratorFactory, wellKnownTypes); + var checkDisposalManagement = new CheckDisposalManagement(getAllImplementations, typesFromAttributes); + var resolutionTreeFactory = new ResolutionTreeFactory(typeToImplementationMapper, referenceGeneratorFactory, checkDisposalManagement, wellKnownTypes); var containerErrorGenerator = new ContainerErrorGenerator(context); var resolutionTreeCreationErrorHarvester = new ResolutionTreeCreationErrorHarvester(); new ExecuteImpl( diff --git a/Main/SpyAttribute.cs b/Main/SpyAttribute.cs index 01675cc5..937a330c 100644 --- a/Main/SpyAttribute.cs +++ b/Main/SpyAttribute.cs @@ -8,4 +8,11 @@ public class SpyAttribute : Attribute // ReSharper disable once UnusedParameter.Local *** Is used in the generator public SpyAttribute(params Type[] type) {} } + + [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] + public class TransientAttribute : Attribute + { + // ReSharper disable once UnusedParameter.Local *** Is used in the generator + public TransientAttribute(params Type[] type) {} + } } \ No newline at end of file diff --git a/Main/TypeToImplementationMapper.cs b/Main/TypeToImplementationMapper.cs index 34d01edc..1f7ea865 100644 --- a/Main/TypeToImplementationMapper.cs +++ b/Main/TypeToImplementationMapper.cs @@ -1,95 +1,29 @@ using Microsoft.CodeAnalysis; using System.Collections.Generic; -using System.Collections.Immutable; using System.Linq; namespace MrMeeseeks.DIE { internal interface ITypeToImplementationsMapper { - IList Map(ITypeSymbol typeSymbol); + IList Map(ITypeSymbol typeSymbol); } internal class TypeToImplementationsMapper : ITypeToImplementationsMapper { - private readonly Dictionary> _map; + private readonly Dictionary> _map; public TypeToImplementationsMapper( - WellKnownTypes wellKnownTypes, - IGetAllImplementations getAllImplementations, - IGetAssemblyAttributes getAssemblyAttributes) - { - + IGetAllImplementations getAllImplementations) => _map = getAllImplementations .AllImplementations - .Concat(GetSpiedImplementations()) .SelectMany(i => { return i.AllInterfaces.OfType().Select(ii => (ii, i)).Prepend((i, i)); }) .GroupBy(t => t.Item1, t => t.Item2) .ToDictionary(g => g.Key, g => g.Distinct().ToList()); - IEnumerable GetSpiedImplementations() => getAssemblyAttributes - .AllAssemblyAttributes - .Where(ad => - ad.AttributeClass?.Equals(wellKnownTypes.SpyAttribute, SymbolEqualityComparer.Default) ?? false) - .SelectMany(ad => - { - var countConstructorArguments = ad.ConstructorArguments.Length; - if (countConstructorArguments is not 1) - { - // Invalid code, ignore - return ImmutableArray.Create(); - } - - var typeConstant = ad.ConstructorArguments[0]; - if (typeConstant.Kind != TypedConstantKind.Array) - { - // Invalid code, ignore - return ImmutableArray.Create(); - } - - return typeConstant.Values; - }) - .Select(tc => - { - if (!CheckValidType(tc, out var type)) - { - return null; - } - - return type; - }) - .Where(t => t is not null) - .SelectMany(t => t?.GetMembers() - .OfType() - .Where(ms => !ms.ReturnsVoid) - .Select(ms => ms.ReturnType) - .OfType()); - - bool CheckValidType(TypedConstant typedConstant, out INamedTypeSymbol type) - { - type = (typedConstant.Value as INamedTypeSymbol)!; - if (typedConstant.Value is null) - return false; - if (type.IsOrReferencesErrorType()) - // we will report an error for this case anyway. - return false; - if (type.IsUnboundGenericType) - return false; - if (!type.IsAccessibleInternally()) - return false; - - return true; - } - } - - public IList Map(ITypeSymbol typeSymbol) - { - if(_map.TryGetValue(typeSymbol, out var implementations)) - { - return implementations; - } - - return new List(); - } + public IList Map(ITypeSymbol typeSymbol) => + _map.TryGetValue(typeSymbol, out var implementations) + ? implementations + : new List(); } } diff --git a/Main/TypesFromAttributes.cs b/Main/TypesFromAttributes.cs new file mode 100644 index 00000000..10659b64 --- /dev/null +++ b/Main/TypesFromAttributes.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using Microsoft.CodeAnalysis; + +namespace MrMeeseeks.DIE +{ + public interface ITypesFromAttributes + { + IReadOnlyList Spy { get; } + IReadOnlyList Transient { get; } + } + + internal class TypesFromAttributes : ITypesFromAttributes + { + public TypesFromAttributes( + WellKnownTypes wellKnownTypes, + IGetAssemblyAttributes getAssemblyAttributes) + { + Spy = GetTypesFromAttribute(wellKnownTypes.SpyAttribute).ToList(); + Transient = GetTypesFromAttribute(wellKnownTypes.TransientAttribute).ToList(); + + IEnumerable GetTypesFromAttribute(INamedTypeSymbol attribute) => getAssemblyAttributes + .AllAssemblyAttributes + .Where(ad => + ad.AttributeClass?.Equals(attribute, SymbolEqualityComparer.Default) ?? false) + .SelectMany(ad => ad.ConstructorArguments + .Where(tc => tc.Kind == TypedConstantKind.Type) + .OfType() + .Concat(ad.ConstructorArguments.SelectMany(ca => ca.Kind is TypedConstantKind.Array + ? (IEnumerable)ca.Values + : Array.Empty()))) + .Select(tc => + { + if (!CheckValidType(tc, out var type)) + { + return null; + } + + return type; + }) + .Where(t => t is not null) + .OfType(); + + bool CheckValidType(TypedConstant typedConstant, out INamedTypeSymbol type) + { + type = (typedConstant.Value as INamedTypeSymbol)!; + if (typedConstant.Value is null) + return false; + if (type.IsUnboundGenericType) + return false; + + return true; + } + } + + public IReadOnlyList Spy { get; } + public IReadOnlyList Transient { get; } + } +} \ No newline at end of file diff --git a/Main/WellKnownTypes.cs b/Main/WellKnownTypes.cs index 06da72c6..48ce0734 100644 --- a/Main/WellKnownTypes.cs +++ b/Main/WellKnownTypes.cs @@ -5,6 +5,7 @@ namespace MrMeeseeks.DIE internal record WellKnownTypes( INamedTypeSymbol Container, INamedTypeSymbol SpyAttribute, + INamedTypeSymbol TransientAttribute, INamedTypeSymbol Disposable, INamedTypeSymbol AsyncDisposable, INamedTypeSymbol Lazy1, @@ -44,8 +45,12 @@ public static bool TryCreate(Compilation compilation, out WellKnownTypes wellKno var spyAttribute = compilation .GetTypeByMetadataName(typeof(SpyAttribute).FullName ?? ""); + var transientAttribute = compilation + .GetTypeByMetadataName(typeof(TransientAttribute).FullName ?? ""); + if (iContainer is null || spyAttribute is null + || transientAttribute is null || iDisposable is null || iAsyncDisposable is null || lazy1 is null @@ -68,6 +73,7 @@ public static bool TryCreate(Compilation compilation, out WellKnownTypes wellKno wellKnownTypes = new WellKnownTypes( Container: iContainer, SpyAttribute: spyAttribute, + TransientAttribute: transientAttribute, Disposable: iDisposable, AsyncDisposable: iAsyncDisposable, Lazy1: lazy1, diff --git a/Sample/Container.cs b/Sample/Container.cs index 8111a7f9..4e2bd524 100644 --- a/Sample/Container.cs +++ b/Sample/Container.cs @@ -1,7 +1,10 @@ using MrMeeseeks.DIE; +using MrMeeseeks.DIE.Sample; +using MrMeeseeks.DIE.SampleChild; using SampleChild; [assembly:Spy(typeof(IPublicTypeReport), typeof(IInternalTypeReport))] +[assembly:Transient(typeof(IChild), typeof(Context), typeof(IInternalChild), typeof(IYetAnotherInternalChild))] namespace MrMeeseeks.DIE.Sample { From a97c4fd25992d757273ce6b5aaf9574ea14dd847 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sun, 31 Oct 2021 22:42:06 +0100 Subject: [PATCH 015/162] Returning after disposal --- Main/ContainerGenerator.cs | 6 ++++-- Sample/Container.cs | 3 --- Sample/StrongInjectContainer.cs | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/Main/ContainerGenerator.cs b/Main/ContainerGenerator.cs index 7e52e933..45a1c2b8 100644 --- a/Main/ContainerGenerator.cs +++ b/Main/ContainerGenerator.cs @@ -49,7 +49,8 @@ public void Generate(IContainerInfo containerInfo, ContainerResolution container .AppendLine($"partial class {containerInfo.Name}") .AppendLine($"{{") .AppendLine($"public TResult Run({funcName}<{containerResolution.TypeFullName}, TParam, TResult> func, TParam param)") - .AppendLine($"{{"); + .AppendLine($"{{") + .AppendLine($"TResult ret;"); generatedContainer = GenerateResolutionFunction(generatedContainer, containerResolution.DisposableCollection); @@ -60,7 +61,7 @@ public void Generate(IContainerInfo containerInfo, ContainerResolution container generatedContainer = GenerateResolutionFunction(generatedContainer, containerResolution); generatedContainer = generatedContainer - .AppendLine($"return func({containerResolution.Reference}, param);") + .AppendLine($"ret = func({containerResolution.Reference}, param);") .AppendLine($"}}") .AppendLine($"finally") .AppendLine($"{{") @@ -76,6 +77,7 @@ public void Generate(IContainerInfo containerInfo, ContainerResolution container .AppendLine($"}}") .AppendLine($"}}") .AppendLine($"}}") + .AppendLine($"return ret;") .AppendLine($"}}") .AppendLine($"}}") .AppendLine($"}}") diff --git a/Sample/Container.cs b/Sample/Container.cs index 4e2bd524..8111a7f9 100644 --- a/Sample/Container.cs +++ b/Sample/Container.cs @@ -1,10 +1,7 @@ using MrMeeseeks.DIE; -using MrMeeseeks.DIE.Sample; -using MrMeeseeks.DIE.SampleChild; using SampleChild; [assembly:Spy(typeof(IPublicTypeReport), typeof(IInternalTypeReport))] -[assembly:Transient(typeof(IChild), typeof(Context), typeof(IInternalChild), typeof(IYetAnotherInternalChild))] namespace MrMeeseeks.DIE.Sample { diff --git a/Sample/StrongInjectContainer.cs b/Sample/StrongInjectContainer.cs index bbd7dfd2..4f1ee64b 100644 --- a/Sample/StrongInjectContainer.cs +++ b/Sample/StrongInjectContainer.cs @@ -5,7 +5,7 @@ namespace MrMeeseeks.DIE.Sample { [Register(typeof(Context), typeof(IContext))] - [Register(typeof(Child), typeof(Child), typeof(IChild))] + [Register(typeof(Child), Scope.SingleInstance, typeof(Child), typeof(IChild))] [Register(typeof(InternalChild), typeof(IInternalChild))] [Register(typeof(YetAnotherInternalChild), typeof(IYetAnotherInternalChild))] [RegisterModule(typeof(StandardModule))] From 8a10b2a92de6c5195fa7708797bbadc1ab3a7aa8 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sat, 6 Nov 2021 21:43:52 +0100 Subject: [PATCH 016/162] SingleInstance feature --- Main/{SpyAttribute.cs => Attributes.cs} | 7 + ...alManagement.cs => CheckTypeProperties.cs} | 18 +- Main/ContainerGenerator.cs | 104 +++++++---- Main/ReferenceGenerator.cs | 4 + Main/ResolutionTreeCreationErrorHarvester.cs | 2 + Main/ResolutionTreeFactory.cs | 172 ++++++++++++------ Main/ResolutionTreeItem.cs | 26 ++- Main/SourceGenerator.cs | 2 +- Main/TypesFromAttributes.cs | 4 +- Main/WellKnownTypes.cs | 16 +- Sample/Container.cs | 3 + Sample/Context.cs | 2 +- Sample/Program.cs | 11 +- Sample/StrongInjectContainer.cs | 2 +- SampleChild/Child.cs | 2 +- SampleChild/MarkerInterfaces.cs | 5 + 16 files changed, 275 insertions(+), 105 deletions(-) rename Main/{SpyAttribute.cs => Attributes.cs} (66%) rename Main/{CheckDisposalManagement.cs => CheckTypeProperties.cs} (56%) create mode 100644 SampleChild/MarkerInterfaces.cs diff --git a/Main/SpyAttribute.cs b/Main/Attributes.cs similarity index 66% rename from Main/SpyAttribute.cs rename to Main/Attributes.cs index 937a330c..e7cffd9a 100644 --- a/Main/SpyAttribute.cs +++ b/Main/Attributes.cs @@ -15,4 +15,11 @@ public class TransientAttribute : Attribute // ReSharper disable once UnusedParameter.Local *** Is used in the generator public TransientAttribute(params Type[] type) {} } + + [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] + public class SingleInstanceAttribute : Attribute + { + // ReSharper disable once UnusedParameter.Local *** Is used in the generator + public SingleInstanceAttribute(params Type[] type) {} + } } \ No newline at end of file diff --git a/Main/CheckDisposalManagement.cs b/Main/CheckTypeProperties.cs similarity index 56% rename from Main/CheckDisposalManagement.cs rename to Main/CheckTypeProperties.cs index a3cacca7..3e64b181 100644 --- a/Main/CheckDisposalManagement.cs +++ b/Main/CheckTypeProperties.cs @@ -5,25 +5,30 @@ namespace MrMeeseeks.DIE { - public interface ICheckDisposalManagement + public interface ICheckTypeProperties { bool ShouldBeManaged(INamedTypeSymbol type); + bool ShouldBeSingleInstance(INamedTypeSymbol type); } - internal class CheckDisposalManagement : ICheckDisposalManagement + internal class CheckTypeProperties : ICheckTypeProperties { - private readonly ImmutableHashSet _transientTypes; + private readonly IImmutableSet _transientTypes; + private readonly IImmutableSet _singleInstanceTypes; - public CheckDisposalManagement( + public CheckTypeProperties( IGetAllImplementations getAllImplementations, ITypesFromAttributes typesFromAttributes) { - _transientTypes = getAllImplementations + _transientTypes = GetSetOfTypesWithProperties(typesFromAttributes.Transient); + _singleInstanceTypes = GetSetOfTypesWithProperties(typesFromAttributes.SingleInstance); + + IImmutableSet GetSetOfTypesWithProperties(IReadOnlyList propertyGivingTypes) => getAllImplementations .AllImplementations .Where(i => { var derivedTypes = AllDerivedTypes(i); - return typesFromAttributes.Transient.Any(t => derivedTypes.Contains(t, SymbolEqualityComparer.Default)); + return propertyGivingTypes.Any(t => derivedTypes.Contains(t, SymbolEqualityComparer.Default)); }) .ToImmutableHashSet(SymbolEqualityComparer.Default); @@ -44,5 +49,6 @@ IEnumerable AllDerivedTypes(INamedTypeSymbol type) } public bool ShouldBeManaged(INamedTypeSymbol type) => !_transientTypes.Contains(type); + public bool ShouldBeSingleInstance(INamedTypeSymbol type) => _singleInstanceTypes.Contains(type); } } \ No newline at end of file diff --git a/Main/ContainerGenerator.cs b/Main/ContainerGenerator.cs index 45a1c2b8..9a690be6 100644 --- a/Main/ContainerGenerator.cs +++ b/Main/ContainerGenerator.cs @@ -36,48 +36,51 @@ public void Generate(IContainerInfo containerInfo, ContainerResolution container return; } - var funcName = _wellKnownTypes.Func.ToDisplayString(new SymbolDisplayFormat( - globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Included, - typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces, - parameterOptions: SymbolDisplayParameterOptions.IncludeType | - SymbolDisplayParameterOptions.IncludeParamsRefOut, - memberOptions: SymbolDisplayMemberOptions.IncludeRef)); - var generatedContainer = new StringBuilder() .AppendLine($"namespace {containerInfo.Namespace}") .AppendLine($"{{") - .AppendLine($"partial class {containerInfo.Name}") - .AppendLine($"{{") - .AppendLine($"public TResult Run({funcName}<{containerResolution.TypeFullName}, TParam, TResult> func, TParam param)") - .AppendLine($"{{") - .AppendLine($"TResult ret;"); + .AppendLine($"partial class {containerInfo.Name} : {_wellKnownTypes.Disposable.FullName()}") + .AppendLine($"{{"); + + generatedContainer = GenerateContainerDisposalFunction( + generatedContainer, + containerResolution.DisposalHandling); + + foreach (var singleInstanceResolution in containerResolution.SingleInstanceResolutions) + { + generatedContainer = generatedContainer + .AppendLine($"private {singleInstanceResolution.Function.TypeFullName} {singleInstanceResolution.Function.FieldReference};") + .AppendLine($"private {_wellKnownTypes.SemaphoreSlim.FullName()} {singleInstanceResolution.Function.LockReference} = new {_wellKnownTypes.SemaphoreSlim.FullName()}(1);") + .AppendLine($"public {singleInstanceResolution.Function.TypeFullName} {singleInstanceResolution.Function.Reference}()") + .AppendLine($"{{") + .AppendLine($"if (!object.ReferenceEquals({singleInstanceResolution.Function.FieldReference}, null)) return {singleInstanceResolution.Function.FieldReference};") + .AppendLine($"this.{singleInstanceResolution.Function.LockReference}.Wait();") + .AppendLine($"try") + .AppendLine($"{{") + .AppendLine($"if (this.{containerResolution.DisposalHandling.DisposedPropertyReference}) throw new {_wellKnownTypes.ObjectDisposedException}(nameof({containerInfo.Name}));"); + + generatedContainer = GenerateResolutionFunction(generatedContainer, singleInstanceResolution.Dependency); + + generatedContainer = generatedContainer + .AppendLine($"this.{singleInstanceResolution.Function.FieldReference} = {singleInstanceResolution.Dependency.Reference};") + .AppendLine($"}}") + .AppendLine($"finally") + .AppendLine($"{{") + .AppendLine($"this.{singleInstanceResolution.Function.LockReference}.Release();") + .AppendLine($"}}") + .AppendLine($"return this.{singleInstanceResolution.Function.FieldReference};") + .AppendLine($"}}"); + } - generatedContainer = GenerateResolutionFunction(generatedContainer, containerResolution.DisposableCollection); - generatedContainer = generatedContainer - .AppendLine($"try") - .AppendLine($"{{"); + .AppendLine($"public {containerResolution.TypeFullName} Resolve()") + .AppendLine($"{{") + .AppendLine($"if (this.{containerResolution.DisposalHandling.DisposedPropertyReference}) throw new {_wellKnownTypes.ObjectDisposedException}(nameof({containerInfo.Name}));"); generatedContainer = GenerateResolutionFunction(generatedContainer, containerResolution); generatedContainer = generatedContainer - .AppendLine($"ret = func({containerResolution.Reference}, param);") - .AppendLine($"}}") - .AppendLine($"finally") - .AppendLine($"{{") - .AppendLine($"foreach(var disposable in {containerResolution.DisposableCollection.Reference})") - .AppendLine($"{{") - .AppendLine($"try") - .AppendLine($"{{") - .AppendLine($"disposable.Dispose();") - .AppendLine($"}}") - .AppendLine($"catch({_wellKnownTypes.Exception.FullName()})") - .AppendLine($"{{") - .AppendLine($"// catch and ignore exceptions of individual disposals so the other disposals are triggered") - .AppendLine($"}}") - .AppendLine($"}}") - .AppendLine($"}}") - .AppendLine($"return ret;") + .AppendLine($"return {containerResolution.Reference};") .AppendLine($"}}") .AppendLine($"}}") .AppendLine($"}}") @@ -91,7 +94,30 @@ public void Generate(IContainerInfo containerInfo, ContainerResolution container .GetText(); _context.AddSource($"{containerInfo.Namespace}.{containerInfo.Name}.g.cs", containerSource); - + + StringBuilder GenerateContainerDisposalFunction( + StringBuilder stringBuilder, + ContainerResolutionDisposalHandling disposalHandling) => + stringBuilder + .AppendLine($"private {disposalHandling.DisposableCollection.TypeFullName} {disposalHandling.DisposableCollection.Reference} = new {disposalHandling.DisposableCollection.TypeFullName}();") + .AppendLine($"private int {disposalHandling.DisposedFieldReference} = 0;") + .AppendLine($"private bool {disposalHandling.DisposedPropertyReference} => {disposalHandling.DisposedFieldReference} != 0;") + .AppendLine($"public void Dispose()") + .AppendLine($"{{") + .AppendLine($"var {disposalHandling.DisposedLocalReference} = global::System.Threading.Interlocked.Exchange(ref this.{disposalHandling.DisposedFieldReference}, 1);") + .AppendLine($"if ({disposalHandling.DisposedLocalReference} != 0) return;") + .AppendLine($"foreach(var {disposalHandling.DisposableLocalReference} in {disposalHandling.DisposableCollection.Reference})") + .AppendLine($"{{") + .AppendLine($"try") + .AppendLine($"{{") + .AppendLine($"{disposalHandling.DisposableLocalReference}.Dispose();") + .AppendLine($"}}") + .AppendLine($"catch({_wellKnownTypes.Exception.FullName()})") + .AppendLine($"{{") + .AppendLine($"// catch and ignore exceptions of individual disposals so the other disposals are triggered") + .AppendLine($"}}") + .AppendLine($"}}") + .AppendLine($"}}"); StringBuilder GenerateResolutionFunction( StringBuilder stringBuilder, @@ -109,7 +135,10 @@ StringBuilder GenerateFields( { switch (resolution) { - case ContainerResolution(var rootResolution, _): + case SingleInstanceReferenceResolution(var reference, { TypeFullName: {} typeFullName}): + stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); + break; + case ContainerResolution(var rootResolution, _, _): stringBuilder = GenerateFields(stringBuilder, rootResolution); break; case InterfaceResolution(var reference, var typeFullName, Resolvable resolutionBase): @@ -143,7 +172,10 @@ StringBuilder GenerateResolutions( { switch (resolution) { - case ContainerResolution(var rootResolution, var disposableCollectionResolution): + case SingleInstanceReferenceResolution(var reference, { Reference: {} functionReference}): + stringBuilder = stringBuilder.AppendLine($"{reference} = {functionReference}();"); + break; + case ContainerResolution(var rootResolution, _, _): stringBuilder = GenerateResolutions(stringBuilder, rootResolution); break; case InterfaceResolution(var reference, var typeFullName, Resolvable resolutionBase): diff --git a/Main/ReferenceGenerator.cs b/Main/ReferenceGenerator.cs index f8f005d9..f3b6ad00 100644 --- a/Main/ReferenceGenerator.cs +++ b/Main/ReferenceGenerator.cs @@ -6,6 +6,7 @@ namespace MrMeeseeks.DIE public interface IReferenceGenerator { string Generate(ITypeSymbol type); + string Generate(string prefix, ITypeSymbol type); string Generate(string hardcodedName); } @@ -19,6 +20,9 @@ internal class ReferenceGenerator : IReferenceGenerator public string Generate(ITypeSymbol type) => Generate($"{char.ToLower(type.Name[0])}{type.Name.Substring(1)}"); + public string Generate(string prefix, ITypeSymbol type) => + Generate($"{prefix}{type.Name}"); + public string Generate(string hardcodedName) => $"{hardcodedName}_{_j}_{++_i}"; } diff --git a/Main/ResolutionTreeCreationErrorHarvester.cs b/Main/ResolutionTreeCreationErrorHarvester.cs index 9c2972d2..dea90970 100644 --- a/Main/ResolutionTreeCreationErrorHarvester.cs +++ b/Main/ResolutionTreeCreationErrorHarvester.cs @@ -20,6 +20,8 @@ static void Inner(ResolutionTreeItem item, ICollection errorTreeI { switch (item) { + case SingleInstanceReferenceResolution: + break; case ContainerResolution containerResolution: Inner(containerResolution.RootResolution, errorTreeItems); break; diff --git a/Main/ResolutionTreeFactory.cs b/Main/ResolutionTreeFactory.cs index 6e49cb5d..10dc0c16 100644 --- a/Main/ResolutionTreeFactory.cs +++ b/Main/ResolutionTreeFactory.cs @@ -15,36 +15,62 @@ internal class ResolutionTreeFactory : IResolutionTreeFactory { private readonly ITypeToImplementationsMapper _typeToImplementationsMapper; private readonly IReferenceGeneratorFactory _referenceGeneratorFactory; - private readonly ICheckDisposalManagement _checkDisposalManagement; + private readonly ICheckTypeProperties _checkTypeProperties; private readonly WellKnownTypes _wellKnownTypes; + private readonly IDictionary _singleInstanceReferenceResolutions = + new Dictionary(SymbolEqualityComparer.Default); + private readonly Queue _singleInstanceResolutionsQueue = new(); + + private readonly IReferenceGenerator _singleInstanceReferenceGenerator; + public ResolutionTreeFactory( ITypeToImplementationsMapper typeToImplementationsMapper, IReferenceGeneratorFactory referenceGeneratorFactory, - ICheckDisposalManagement checkDisposalManagement, + ICheckTypeProperties checkTypeProperties, WellKnownTypes wellKnownTypes) { _typeToImplementationsMapper = typeToImplementationsMapper; _referenceGeneratorFactory = referenceGeneratorFactory; - _checkDisposalManagement = checkDisposalManagement; + _checkTypeProperties = checkTypeProperties; _wellKnownTypes = wellKnownTypes; + _singleInstanceReferenceGenerator = referenceGeneratorFactory.Create(); } public ContainerResolution Create(ITypeSymbol type) { - var referenceGenerator = _referenceGeneratorFactory.Create(); var disposableCollectionResolution = new DisposableCollectionResolution( - referenceGenerator.Generate(_wellKnownTypes.ConcurrentBagOfDisposable), + _singleInstanceReferenceGenerator.Generate(_wellKnownTypes.ConcurrentBagOfDisposable), _wellKnownTypes.ConcurrentBagOfDisposable.FullName()); + var referenceGenerator = _referenceGeneratorFactory.Create(); var rootResolution = Create( type, referenceGenerator, Array.Empty<(ITypeSymbol Type, FuncParameterResolution Resolution)>(), disposableCollectionResolution); + var singleInstances = new List(); + + while (_singleInstanceResolutionsQueue.Any()) + { + var singleInstanceFunction = _singleInstanceResolutionsQueue.Dequeue(); + var resolvable = CreateConstructorResolution( + singleInstanceFunction.Type, + _referenceGeneratorFactory.Create(), + Array.Empty<(ITypeSymbol Type, FuncParameterResolution Resolution)>(), + disposableCollectionResolution, + true); + singleInstances.Add(new SingleInstance(singleInstanceFunction, resolvable)); + } return new ContainerResolution( rootResolution, - disposableCollectionResolution); + new ContainerResolutionDisposalHandling( + disposableCollectionResolution, + _singleInstanceReferenceGenerator.Generate("_disposed"), + _singleInstanceReferenceGenerator.Generate("disposed"), + _singleInstanceReferenceGenerator.Generate("Disposed"), + _singleInstanceReferenceGenerator.Generate("disposable")), + singleInstances); } private Resolvable Create( @@ -79,7 +105,7 @@ private Resolvable Create( return new ConstructorResolution( referenceGenerator.Generate(namedTypeSymbol), namedTypeSymbol.FullName(), - ImplementsIDisposable(namedTypeSymbol, _wellKnownTypes, disposableCollectionResolution, _checkDisposalManagement), + ImplementsIDisposable(namedTypeSymbol, _wellKnownTypes, disposableCollectionResolution, _checkTypeProperties), new ReadOnlyCollection<(string Name, Resolvable Dependency)>( new List<(string Name, Resolvable Dependency)> { @@ -128,7 +154,7 @@ private Resolvable Create( var implementations = _typeToImplementationsMapper .Map(type); if (implementations - .SingleOrDefault() is not INamedTypeSymbol implementationType) + .SingleOrDefault() is not { } implementationType) { return new ErrorTreeItem(implementations.Count switch { @@ -144,85 +170,127 @@ private Resolvable Create( } if (type.TypeKind == TypeKind.Class) + return CreateConstructorResolution(type, referenceGenerator, currentFuncParameters, disposableCollectionResolution); + + if (type.TypeKind == TypeKind.Delegate + && type.FullName().StartsWith("global::System.Func<") + && type is INamedTypeSymbol namedTypeSymbol0) + { + var returnType = namedTypeSymbol0.TypeArguments.Last(); + var innerReferenceGenerator = _referenceGeneratorFactory.Create(); + var parameterTypes = namedTypeSymbol0 + .TypeArguments + .Take(namedTypeSymbol0.TypeArguments.Length - 1) + .Select(ts => (Type: ts, Resolution: new FuncParameterResolution(innerReferenceGenerator.Generate(ts), ts.FullName()))) + .ToArray(); + + var dependency = Create( + returnType, + innerReferenceGenerator, + parameterTypes, + disposableCollectionResolution); + return new FuncResolution( + referenceGenerator.Generate(type), + type.FullName(), + parameterTypes.Select(t => t.Resolution).ToArray(), + dependency); + } + + return new ErrorTreeItem($"[{type.FullName()}] Couldn't process in resolution tree creation."); + } + + private Resolvable CreateConstructorResolution( + ITypeSymbol typeSymbol, + IReferenceGenerator referenceGenerator, + IReadOnlyList<(ITypeSymbol Type, FuncParameterResolution Resolution)> readOnlyList, + DisposableCollectionResolution disposableCollectionResolution, + bool skipSingleInstanceCheck = false) { var implementations = _typeToImplementationsMapper - .Map(type); + .Map(typeSymbol); if (implementations - .SingleOrDefault() is not INamedTypeSymbol implementationType) + .SingleOrDefault() is not { } implementationType) { return new ErrorTreeItem(implementations.Count switch { - 0 => $"[{type.FullName()}] Class: No implementation found", - > 1 => $"[{type.FullName()}] Class: more than one implementation found", - _ => $"[{type.FullName()}] Class: Found single implementation{implementations[0].FullName()} is not a named type symbol" + 0 => $"[{typeSymbol.FullName()}] Class: No implementation found", + > 1 => $"[{typeSymbol.FullName()}] Class: more than one implementation found", + _ => + $"[{typeSymbol.FullName()}] Class: Found single implementation{implementations[0].FullName()} is not a named type symbol" }); } + + if (!skipSingleInstanceCheck && _checkTypeProperties.ShouldBeSingleInstance(implementationType)) + return CreateSingleInstanceReferenceResolution(implementationType, referenceGenerator); + if (implementationType.Constructors.SingleOrDefault() is not { } constructor) { return new ErrorTreeItem(implementations.Count switch { - 0 => $"[{type.FullName()}] Class.Constructor: No constructor found for implementation {implementationType.FullName()}", - > 1 => $"[{type.FullName()}] Class.Constructor: More than one constructor found for implementation {implementationType.FullName()}", - _ => $"[{type.FullName()}] Class.Constructor: {implementationType.Constructors[0].Name} is not a method symbol" + 0 => + $"[{typeSymbol.FullName()}] Class.Constructor: No constructor found for implementation {implementationType.FullName()}", + > 1 => + $"[{typeSymbol.FullName()}] Class.Constructor: More than one constructor found for implementation {implementationType.FullName()}", + _ => + $"[{typeSymbol.FullName()}] Class.Constructor: {implementationType.Constructors[0].Name} is not a method symbol" }); } - + return new ConstructorResolution( referenceGenerator.Generate(implementationType), implementationType.FullName(), - ImplementsIDisposable(implementationType, _wellKnownTypes, disposableCollectionResolution, _checkDisposalManagement), + ImplementsIDisposable(implementationType, _wellKnownTypes, disposableCollectionResolution, + _checkTypeProperties), new ReadOnlyCollection<(string Name, Resolvable Dependency)>(constructor .Parameters .Select(p => { if (p.Type is not INamedTypeSymbol parameterType) { - return ("", new ErrorTreeItem($"[{type.FullName()}] Class.Constructor.Parameter: Parameter type {p.Type.FullName()} is not a named type symbol")); + return ("", + new ErrorTreeItem( + $"[{typeSymbol.FullName()}] Class.Constructor.Parameter: Parameter type {p.Type.FullName()} is not a named type symbol")); } + return ( p.Name, Create(parameterType, referenceGenerator, - currentFuncParameters, + readOnlyList, disposableCollectionResolution)); }) .ToList())); } - if (type.TypeKind == TypeKind.Delegate - && type.FullName().StartsWith("global::System.Func<") - && type is INamedTypeSymbol namedTypeSymbol0) + private SingleInstanceReferenceResolution CreateSingleInstanceReferenceResolution( + INamedTypeSymbol implementationType, + IReferenceGenerator referenceGenerator) + { + if (!_singleInstanceReferenceResolutions.TryGetValue( + implementationType, + out SingleInstanceFunction function)) { - var returnType = namedTypeSymbol0.TypeArguments.Last(); - var innerReferenceGenerator = _referenceGeneratorFactory.Create(); - var parameterTypes = namedTypeSymbol0 - .TypeArguments - .Take(namedTypeSymbol0.TypeArguments.Length - 1) - .Select(ts => (Type: ts, Resolution: new FuncParameterResolution(innerReferenceGenerator.Generate(ts), ts.FullName()))) - .ToArray(); - - var dependency = Create( - returnType, - innerReferenceGenerator, - parameterTypes, - disposableCollectionResolution); - return new FuncResolution( - referenceGenerator.Generate(type), - type.FullName(), - parameterTypes.Select(t => t.Resolution).ToArray(), - dependency); + function = new SingleInstanceFunction( + _singleInstanceReferenceGenerator.Generate("GetSingleInstance", implementationType), + implementationType.FullName(), + implementationType, + _singleInstanceReferenceGenerator.Generate("_singleInstanceField", implementationType), + _singleInstanceReferenceGenerator.Generate("_singleInstanceLock")); + _singleInstanceReferenceResolutions[implementationType] = function; + _singleInstanceResolutionsQueue.Enqueue(function); } - - return new ErrorTreeItem($"[{type.FullName()}] Couldn't process in resolution tree creation."); - - static DisposableCollectionResolution? ImplementsIDisposable( - INamedTypeSymbol type, - WellKnownTypes wellKnownTypes, - DisposableCollectionResolution disposableCollectionResolution, - ICheckDisposalManagement checkDisposalManagement) => - type.AllInterfaces.Contains(wellKnownTypes.Disposable) && checkDisposalManagement.ShouldBeManaged(type) - ? disposableCollectionResolution - : null; + return new SingleInstanceReferenceResolution( + referenceGenerator.Generate(implementationType), + function); } + + private static DisposableCollectionResolution? ImplementsIDisposable( + INamedTypeSymbol type, + WellKnownTypes wellKnownTypes, + DisposableCollectionResolution disposableCollectionResolution, + ICheckTypeProperties checkDisposalManagement) => + type.AllInterfaces.Contains(wellKnownTypes.Disposable) && checkDisposalManagement.ShouldBeManaged(type) + ? disposableCollectionResolution + : null; } } \ No newline at end of file diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index 82a4ce6d..55ae023d 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using Microsoft.CodeAnalysis; namespace MrMeeseeks.DIE { @@ -23,10 +24,25 @@ internal record ConstructorResolution( DisposableCollectionResolution? DisposableCollectionResolution, IReadOnlyList<(string name, Resolvable Dependency)> Parameter) : Resolvable(Reference, TypeFullName); + internal record SingleInstance( + SingleInstanceFunction Function, + Resolvable Dependency); + internal record FuncParameterResolution( string Reference, string TypeFullName) : Resolvable(Reference, TypeFullName); + internal record SingleInstanceFunction( + string Reference, + string TypeFullName, + INamedTypeSymbol Type, + string FieldReference, + string LockReference); + + internal record SingleInstanceReferenceResolution( + string Reference, + SingleInstanceFunction Function) : Resolvable(Reference, Function.TypeFullName); + internal record FuncResolution( string Reference, string TypeFullName, @@ -45,5 +61,13 @@ internal record DisposableCollectionResolution( internal record ContainerResolution( Resolvable RootResolution, - DisposableCollectionResolution DisposableCollection) : Resolvable(RootResolution.Reference, RootResolution.TypeFullName); + ContainerResolutionDisposalHandling DisposalHandling, + IReadOnlyList SingleInstanceResolutions) : Resolvable(RootResolution.Reference, RootResolution.TypeFullName); + + internal record ContainerResolutionDisposalHandling( + DisposableCollectionResolution DisposableCollection, + string DisposedFieldReference, + string DisposedLocalReference, + string DisposedPropertyReference, + string DisposableLocalReference); } diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index a1b4ad64..3cfa6ad6 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -22,7 +22,7 @@ public void Execute(GeneratorExecutionContext context) var typeToImplementationMapper = new TypeToImplementationsMapper(getAllImplementations); var containerGenerator = new ContainerGenerator(context, wellKnownTypes, diagLogger); var referenceGeneratorFactory = new ReferenceGeneratorFactory(ReferenceGeneratorFactory); - var checkDisposalManagement = new CheckDisposalManagement(getAllImplementations, typesFromAttributes); + var checkDisposalManagement = new CheckTypeProperties(getAllImplementations, typesFromAttributes); var resolutionTreeFactory = new ResolutionTreeFactory(typeToImplementationMapper, referenceGeneratorFactory, checkDisposalManagement, wellKnownTypes); var containerErrorGenerator = new ContainerErrorGenerator(context); var resolutionTreeCreationErrorHarvester = new ResolutionTreeCreationErrorHarvester(); diff --git a/Main/TypesFromAttributes.cs b/Main/TypesFromAttributes.cs index 10659b64..a84c849d 100644 --- a/Main/TypesFromAttributes.cs +++ b/Main/TypesFromAttributes.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.Linq; using Microsoft.CodeAnalysis; @@ -10,6 +9,7 @@ public interface ITypesFromAttributes { IReadOnlyList Spy { get; } IReadOnlyList Transient { get; } + IReadOnlyList SingleInstance { get; } } internal class TypesFromAttributes : ITypesFromAttributes @@ -20,6 +20,7 @@ public TypesFromAttributes( { Spy = GetTypesFromAttribute(wellKnownTypes.SpyAttribute).ToList(); Transient = GetTypesFromAttribute(wellKnownTypes.TransientAttribute).ToList(); + SingleInstance = GetTypesFromAttribute(wellKnownTypes.SingleInstanceAttribute).ToList(); IEnumerable GetTypesFromAttribute(INamedTypeSymbol attribute) => getAssemblyAttributes .AllAssemblyAttributes @@ -57,5 +58,6 @@ bool CheckValidType(TypedConstant typedConstant, out INamedTypeSymbol type) public IReadOnlyList Spy { get; } public IReadOnlyList Transient { get; } + public IReadOnlyList SingleInstance { get; } } } \ No newline at end of file diff --git a/Main/WellKnownTypes.cs b/Main/WellKnownTypes.cs index 48ce0734..ef4234c9 100644 --- a/Main/WellKnownTypes.cs +++ b/Main/WellKnownTypes.cs @@ -6,6 +6,7 @@ internal record WellKnownTypes( INamedTypeSymbol Container, INamedTypeSymbol SpyAttribute, INamedTypeSymbol TransientAttribute, + INamedTypeSymbol SingleInstanceAttribute, INamedTypeSymbol Disposable, INamedTypeSymbol AsyncDisposable, INamedTypeSymbol Lazy1, @@ -19,7 +20,8 @@ internal record WellKnownTypes( INamedTypeSymbol ConcurrentBagOfDisposable, INamedTypeSymbol Action, INamedTypeSymbol Func, - INamedTypeSymbol Exception) + INamedTypeSymbol Exception, + INamedTypeSymbol SemaphoreSlim) { public static bool TryCreate(Compilation compilation, out WellKnownTypes wellKnownTypes) { @@ -41,6 +43,7 @@ public static bool TryCreate(Compilation compilation, out WellKnownTypes wellKno var action = compilation.GetTypeOrReport("System.Action"); var func = compilation.GetTypeOrReport("System.Func`3"); var exception = compilation.GetTypeOrReport("System.Exception"); + var semaphoreSlim = compilation.GetTypeOrReport("System.Threading.SemaphoreSlim"); var spyAttribute = compilation .GetTypeByMetadataName(typeof(SpyAttribute).FullName ?? ""); @@ -48,9 +51,13 @@ public static bool TryCreate(Compilation compilation, out WellKnownTypes wellKno var transientAttribute = compilation .GetTypeByMetadataName(typeof(TransientAttribute).FullName ?? ""); + var singleInstanceAttribute = compilation + .GetTypeByMetadataName(typeof(SingleInstanceAttribute).FullName ?? ""); + if (iContainer is null || spyAttribute is null || transientAttribute is null + || singleInstanceAttribute is null || iDisposable is null || iAsyncDisposable is null || lazy1 is null @@ -64,7 +71,8 @@ public static bool TryCreate(Compilation compilation, out WellKnownTypes wellKno || concurrentBagOfDisposable is null || action is null || func is null - || exception is null) + || exception is null + || semaphoreSlim is null) { wellKnownTypes = null!; return false; @@ -74,6 +82,7 @@ public static bool TryCreate(Compilation compilation, out WellKnownTypes wellKno Container: iContainer, SpyAttribute: spyAttribute, TransientAttribute: transientAttribute, + SingleInstanceAttribute: singleInstanceAttribute, Disposable: iDisposable, AsyncDisposable: iAsyncDisposable, Lazy1: lazy1, @@ -87,7 +96,8 @@ public static bool TryCreate(Compilation compilation, out WellKnownTypes wellKno ConcurrentBagOfDisposable: concurrentBagOfDisposable, Action: action, Func: func, - Exception: exception); + Exception: exception, + SemaphoreSlim: semaphoreSlim); return true; } diff --git a/Sample/Container.cs b/Sample/Container.cs index 8111a7f9..ac144ef3 100644 --- a/Sample/Container.cs +++ b/Sample/Container.cs @@ -1,7 +1,10 @@ using MrMeeseeks.DIE; +using MrMeeseeks.DIE.SampleChild; using SampleChild; [assembly:Spy(typeof(IPublicTypeReport), typeof(IInternalTypeReport))] +[assembly:SingleInstance(typeof(ISingleInstance))] +[assembly:Transient(typeof(ITransient))] namespace MrMeeseeks.DIE.Sample { diff --git a/Sample/Context.cs b/Sample/Context.cs index f687375a..6b1a2eb8 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -9,7 +9,7 @@ internal interface IContext string Text { get; } } - internal class Context : IContext, IDisposable + internal class Context : IContext, IDisposable, ISingleInstance { public string Text => "Hello, world!"; public Context(IReadOnlyList child) diff --git a/Sample/Program.cs b/Sample/Program.cs index a82396ab..e41f5e7f 100644 --- a/Sample/Program.cs +++ b/Sample/Program.cs @@ -2,6 +2,13 @@ using StrongInject; System.Console.WriteLine("Hello, world!"); -System.Console.WriteLine(new Container().Run((c, _) => c.Text, new object())); -System.Console.WriteLine(new StrongInjectContainer().Run(c => c.Text)); +{ + using var container = new Container(); + System.Console.WriteLine(container.Resolve().Text); +} +{ + using var strongInjectContainer = new StrongInjectContainer(); + using var owned = strongInjectContainer.Resolve(); + System.Console.WriteLine(owned.Value.Text); +} diff --git a/Sample/StrongInjectContainer.cs b/Sample/StrongInjectContainer.cs index 4f1ee64b..9986e014 100644 --- a/Sample/StrongInjectContainer.cs +++ b/Sample/StrongInjectContainer.cs @@ -4,7 +4,7 @@ namespace MrMeeseeks.DIE.Sample { - [Register(typeof(Context), typeof(IContext))] + [Register(typeof(Context), Scope.SingleInstance, typeof(Context), typeof(IContext))] [Register(typeof(Child), Scope.SingleInstance, typeof(Child), typeof(IChild))] [Register(typeof(InternalChild), typeof(IInternalChild))] [Register(typeof(YetAnotherInternalChild), typeof(IYetAnotherInternalChild))] diff --git a/SampleChild/Child.cs b/SampleChild/Child.cs index ea5f3c01..080b74df 100644 --- a/SampleChild/Child.cs +++ b/SampleChild/Child.cs @@ -5,7 +5,7 @@ namespace MrMeeseeks.DIE.SampleChild public interface IChild { } - public class Child : IChild, IDisposable + public class Child : IChild, IDisposable, ISingleInstance { public Child( IInternalChild innerChild){} diff --git a/SampleChild/MarkerInterfaces.cs b/SampleChild/MarkerInterfaces.cs new file mode 100644 index 00000000..33d5c0ff --- /dev/null +++ b/SampleChild/MarkerInterfaces.cs @@ -0,0 +1,5 @@ +namespace MrMeeseeks.DIE.SampleChild +{ + public interface ISingleInstance { } + public interface ITransient { } +} \ No newline at end of file From c508730b4cc1a447b34c18343789322fdf749a15 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sat, 6 Nov 2021 21:56:11 +0100 Subject: [PATCH 017/162] Adjusted disposal for SingleInstances --- Main/ContainerGenerator.cs | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/Main/ContainerGenerator.cs b/Main/ContainerGenerator.cs index 9a690be6..52d0b020 100644 --- a/Main/ContainerGenerator.cs +++ b/Main/ContainerGenerator.cs @@ -44,7 +44,8 @@ public void Generate(IContainerInfo containerInfo, ContainerResolution container generatedContainer = GenerateContainerDisposalFunction( generatedContainer, - containerResolution.DisposalHandling); + containerResolution.DisposalHandling, + containerResolution); foreach (var singleInstanceResolution in containerResolution.SingleInstanceResolutions) { @@ -97,15 +98,28 @@ public void Generate(IContainerInfo containerInfo, ContainerResolution container StringBuilder GenerateContainerDisposalFunction( StringBuilder stringBuilder, - ContainerResolutionDisposalHandling disposalHandling) => - stringBuilder + ContainerResolutionDisposalHandling disposalHandling, + ContainerResolution containerResolution) + { + stringBuilder = stringBuilder .AppendLine($"private {disposalHandling.DisposableCollection.TypeFullName} {disposalHandling.DisposableCollection.Reference} = new {disposalHandling.DisposableCollection.TypeFullName}();") .AppendLine($"private int {disposalHandling.DisposedFieldReference} = 0;") .AppendLine($"private bool {disposalHandling.DisposedPropertyReference} => {disposalHandling.DisposedFieldReference} != 0;") .AppendLine($"public void Dispose()") .AppendLine($"{{") .AppendLine($"var {disposalHandling.DisposedLocalReference} = global::System.Threading.Interlocked.Exchange(ref this.{disposalHandling.DisposedFieldReference}, 1);") - .AppendLine($"if ({disposalHandling.DisposedLocalReference} != 0) return;") + .AppendLine($"if ({disposalHandling.DisposedLocalReference} != 0) return;"); + + foreach (var singleInstanceResolution in containerResolution.SingleInstanceResolutions) + { + stringBuilder = stringBuilder + .AppendLine($"this.{singleInstanceResolution.Function.LockReference}.Wait();"); + + } + + stringBuilder = stringBuilder + .AppendLine($"try") + .AppendLine($"{{") .AppendLine($"foreach(var {disposalHandling.DisposableLocalReference} in {disposalHandling.DisposableCollection.Reference})") .AppendLine($"{{") .AppendLine($"try") @@ -116,9 +130,24 @@ StringBuilder GenerateContainerDisposalFunction( .AppendLine($"{{") .AppendLine($"// catch and ignore exceptions of individual disposals so the other disposals are triggered") .AppendLine($"}}") + .AppendLine($"}}") + .AppendLine($"}}") + .AppendLine($"finally") + .AppendLine($"{{"); + + foreach (var singleInstanceResolution in containerResolution.SingleInstanceResolutions) + { + stringBuilder = stringBuilder + .AppendLine($"this.{singleInstanceResolution.Function.LockReference}.Release();"); + } + + stringBuilder = stringBuilder .AppendLine($"}}") .AppendLine($"}}"); + return stringBuilder; + } + StringBuilder GenerateResolutionFunction( StringBuilder stringBuilder, Resolvable resolution) From 85c02aac38f5458981dcdeefa3ed369cac876f10 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Mon, 8 Nov 2021 22:01:34 +0100 Subject: [PATCH 018/162] C#10 --- Directory.build.props | 2 +- Main/AssemblyInfo.cs | 14 + Main/Attributes.cs | 37 +- Main/CheckTypeProperties.cs | 80 ++- Main/ContainerErrorGenerator.cs | 72 ++- Main/ContainerGenerator.cs | 403 ++++++++------- Main/ContainerInfo.cs | 66 ++- Main/DiagLogger.cs | 45 +- Main/ExecuteImpl.cs | 124 +++-- Main/GetAllImplementations.cs | 66 ++- Main/GetAssemblyAttributes.cs | 31 +- Main/IContainer.cs | 9 +- Main/InitializeImpl.cs | 38 +- Main/IsExternalInit.cs | 9 +- Main/ReferenceGenerator.cs | 62 ++- Main/ResolutionTreeCreationErrorHarvester.cs | 90 ++-- Main/ResolutionTreeFactory.cs | 495 +++++++++---------- Main/ResolutionTreeItem.cs | 113 ++--- Main/RoslynExtensions.cs | 95 ++-- Main/SourceGenerator.cs | 69 ++- Main/SyntaxReceiver.cs | 23 +- Main/TypeToImplementationMapper.cs | 43 +- Main/TypesFromAttributes.cs | 96 ++-- Main/WellKnownTypes.cs | 185 ++++--- Sample/Container.cs | 9 +- Sample/Context.cs | 27 +- Sample/StrongInjectContainer.cs | 17 +- SampleChild/Child.cs | 21 +- SampleChild/InternalChild.cs | 31 +- SampleChild/MarkerInterfaces.cs | 9 +- Spy/AssemblyInfo.cs | 12 + Spy/DiagLogger.cs | 39 +- Spy/ExecuteImpl.cs | 51 +- Spy/GetAllImplementations.cs | 55 +-- Spy/SourceGenerator.cs | 29 +- Spy/TypeReportGenerator.cs | 156 +++--- 36 files changed, 1317 insertions(+), 1406 deletions(-) create mode 100644 Main/AssemblyInfo.cs create mode 100644 Spy/AssemblyInfo.cs diff --git a/Directory.build.props b/Directory.build.props index 61a4f322..4b3e8df4 100644 --- a/Directory.build.props +++ b/Directory.build.props @@ -4,7 +4,7 @@ v $(MinVerVersion) true - 9 + 10 enable nullable Yeah69 diff --git a/Main/AssemblyInfo.cs b/Main/AssemblyInfo.cs new file mode 100644 index 00000000..009379e7 --- /dev/null +++ b/Main/AssemblyInfo.cs @@ -0,0 +1,14 @@ +global using Microsoft.CodeAnalysis; +global using System; +global using System.Collections.Generic; +global using System.Collections.Immutable; +global using System.Collections.ObjectModel; +global using System.Linq; +global using System.Text; + +namespace MrMeeseeks.DIE; + +public class AssemblyInfo +{ + +} \ No newline at end of file diff --git a/Main/Attributes.cs b/Main/Attributes.cs index e7cffd9a..4d9eef2b 100644 --- a/Main/Attributes.cs +++ b/Main/Attributes.cs @@ -1,25 +1,22 @@ -using System; +namespace MrMeeseeks.DIE; -namespace MrMeeseeks.DIE +[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] +public class SpyAttribute : Attribute { - [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] - public class SpyAttribute : Attribute - { - // ReSharper disable once UnusedParameter.Local *** Is used in the generator - public SpyAttribute(params Type[] type) {} - } + // ReSharper disable once UnusedParameter.Local *** Is used in the generator + public SpyAttribute(params Type[] type) {} +} - [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] - public class TransientAttribute : Attribute - { - // ReSharper disable once UnusedParameter.Local *** Is used in the generator - public TransientAttribute(params Type[] type) {} - } +[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] +public class TransientAttribute : Attribute +{ + // ReSharper disable once UnusedParameter.Local *** Is used in the generator + public TransientAttribute(params Type[] type) {} +} - [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] - public class SingleInstanceAttribute : Attribute - { - // ReSharper disable once UnusedParameter.Local *** Is used in the generator - public SingleInstanceAttribute(params Type[] type) {} - } +[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] +public class SingleInstanceAttribute : Attribute +{ + // ReSharper disable once UnusedParameter.Local *** Is used in the generator + public SingleInstanceAttribute(params Type[] type) {} } \ No newline at end of file diff --git a/Main/CheckTypeProperties.cs b/Main/CheckTypeProperties.cs index 3e64b181..1ba63589 100644 --- a/Main/CheckTypeProperties.cs +++ b/Main/CheckTypeProperties.cs @@ -1,54 +1,48 @@ -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; -using Microsoft.CodeAnalysis; +namespace MrMeeseeks.DIE; -namespace MrMeeseeks.DIE +public interface ICheckTypeProperties { - public interface ICheckTypeProperties - { - bool ShouldBeManaged(INamedTypeSymbol type); - bool ShouldBeSingleInstance(INamedTypeSymbol type); - } + bool ShouldBeManaged(INamedTypeSymbol type); + bool ShouldBeSingleInstance(INamedTypeSymbol type); +} - internal class CheckTypeProperties : ICheckTypeProperties - { - private readonly IImmutableSet _transientTypes; - private readonly IImmutableSet _singleInstanceTypes; +internal class CheckTypeProperties : ICheckTypeProperties +{ + private readonly IImmutableSet _transientTypes; + private readonly IImmutableSet _singleInstanceTypes; - public CheckTypeProperties( - IGetAllImplementations getAllImplementations, - ITypesFromAttributes typesFromAttributes) - { - _transientTypes = GetSetOfTypesWithProperties(typesFromAttributes.Transient); - _singleInstanceTypes = GetSetOfTypesWithProperties(typesFromAttributes.SingleInstance); + public CheckTypeProperties( + IGetAllImplementations getAllImplementations, + ITypesFromAttributes typesFromAttributes) + { + _transientTypes = GetSetOfTypesWithProperties(typesFromAttributes.Transient); + _singleInstanceTypes = GetSetOfTypesWithProperties(typesFromAttributes.SingleInstance); - IImmutableSet GetSetOfTypesWithProperties(IReadOnlyList propertyGivingTypes) => getAllImplementations - .AllImplementations - .Where(i => - { - var derivedTypes = AllDerivedTypes(i); - return propertyGivingTypes.Any(t => derivedTypes.Contains(t, SymbolEqualityComparer.Default)); - }) - .ToImmutableHashSet(SymbolEqualityComparer.Default); + IImmutableSet GetSetOfTypesWithProperties(IReadOnlyList propertyGivingTypes) => getAllImplementations + .AllImplementations + .Where(i => + { + var derivedTypes = AllDerivedTypes(i); + return propertyGivingTypes.Any(t => derivedTypes.Contains(t, SymbolEqualityComparer.Default)); + }) + .ToImmutableHashSet(SymbolEqualityComparer.Default); - IEnumerable AllDerivedTypes(INamedTypeSymbol type) + IEnumerable AllDerivedTypes(INamedTypeSymbol type) + { + var concreteTypes = new List(); + var temp = type; + while (temp is {}) { - var concreteTypes = new List(); - var temp = type; - while (temp is {}) - { - concreteTypes.Add(temp); - temp = temp.BaseType; - } - return type - .AllInterfaces - .Append(type) - .Concat(concreteTypes); + concreteTypes.Add(temp); + temp = temp.BaseType; } + return type + .AllInterfaces + .Append(type) + .Concat(concreteTypes); } - - public bool ShouldBeManaged(INamedTypeSymbol type) => !_transientTypes.Contains(type); - public bool ShouldBeSingleInstance(INamedTypeSymbol type) => _singleInstanceTypes.Contains(type); } + + public bool ShouldBeManaged(INamedTypeSymbol type) => !_transientTypes.Contains(type); + public bool ShouldBeSingleInstance(INamedTypeSymbol type) => _singleInstanceTypes.Contains(type); } \ No newline at end of file diff --git a/Main/ContainerErrorGenerator.cs b/Main/ContainerErrorGenerator.cs index 8923446e..1f26a30a 100644 --- a/Main/ContainerErrorGenerator.cs +++ b/Main/ContainerErrorGenerator.cs @@ -1,47 +1,41 @@ -using System; -using System.Collections.Generic; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Text; -using System.Linq; -using System.Text; -namespace MrMeeseeks.DIE +namespace MrMeeseeks.DIE; + +internal interface IContainerErrorGenerator { - internal interface IContainerErrorGenerator - { - void Generate(IContainerInfo containerInfo, IReadOnlyList errorTreeItems); - } + void Generate(IContainerInfo containerInfo, IReadOnlyList errorTreeItems); +} - internal class ContainerErrorGenerator : IContainerErrorGenerator - { - private readonly GeneratorExecutionContext _context; +internal class ContainerErrorGenerator : IContainerErrorGenerator +{ + private readonly GeneratorExecutionContext _context; - public ContainerErrorGenerator( - GeneratorExecutionContext context) => - _context = context; + public ContainerErrorGenerator( + GeneratorExecutionContext context) => + _context = context; - public void Generate(IContainerInfo containerInfo, IReadOnlyList errorTreeItems) - { - var generatedContainer = new StringBuilder() - .AppendLine($"namespace {containerInfo.Namespace}") - .AppendLine($"{{") - .AppendLine($"partial class {containerInfo.Name}") - .AppendLine($"{{") - .AppendLine($"public object Resolve()") - .AppendLine($"{{") - .AppendLine($"throw new Exception(@\"{string.Join(Environment.NewLine, errorTreeItems.Select(eri => eri.Message))}\");") - .AppendLine($"}}") - .AppendLine($"}}") - .AppendLine($"}}"); + public void Generate(IContainerInfo containerInfo, IReadOnlyList errorTreeItems) + { + var generatedContainer = new StringBuilder() + .AppendLine($"namespace {containerInfo.Namespace}") + .AppendLine($"{{") + .AppendLine($"partial class {containerInfo.Name}") + .AppendLine($"{{") + .AppendLine($"public object Resolve()") + .AppendLine($"{{") + .AppendLine($"throw new Exception(@\"{string.Join(Environment.NewLine, errorTreeItems.Select(eri => eri.Message))}\");") + .AppendLine($"}}") + .AppendLine($"}}") + .AppendLine($"}}"); - var containerSource = CSharpSyntaxTree - .ParseText(SourceText.From(generatedContainer.ToString(), Encoding.UTF8)) - .GetRoot() - .NormalizeWhitespace() - .SyntaxTree - .GetText(); - _context.AddSource($"{containerInfo.Namespace}.{containerInfo.Name}.g.cs", containerSource); - } + var containerSource = CSharpSyntaxTree + .ParseText(SourceText.From(generatedContainer.ToString(), Encoding.UTF8)) + .GetRoot() + .NormalizeWhitespace() + .SyntaxTree + .GetText(); + _context.AddSource($"{containerInfo.Namespace}.{containerInfo.Name}.g.cs", containerSource); } -} +} \ No newline at end of file diff --git a/Main/ContainerGenerator.cs b/Main/ContainerGenerator.cs index 52d0b020..74d06b82 100644 --- a/Main/ContainerGenerator.cs +++ b/Main/ContainerGenerator.cs @@ -1,246 +1,241 @@ -using System; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Text; -using System.Linq; -using System.Text; -namespace MrMeeseeks.DIE +namespace MrMeeseeks.DIE; + +internal interface IContainerGenerator +{ + void Generate(IContainerInfo containerInfo, ContainerResolution resolvable); +} + +internal class ContainerGenerator : IContainerGenerator { - internal interface IContainerGenerator + private readonly GeneratorExecutionContext _context; + private readonly WellKnownTypes _wellKnownTypes; + private readonly IDiagLogger _diagLogger; + + public ContainerGenerator( + GeneratorExecutionContext context, + WellKnownTypes wellKnownTypes, + IDiagLogger diagLogger) { - void Generate(IContainerInfo containerInfo, ContainerResolution resolvable); + _context = context; + _wellKnownTypes = wellKnownTypes; + _diagLogger = diagLogger; } - internal class ContainerGenerator : IContainerGenerator + public void Generate(IContainerInfo containerInfo, ContainerResolution containerResolution) { - private readonly GeneratorExecutionContext _context; - private readonly WellKnownTypes _wellKnownTypes; - private readonly IDiagLogger _diagLogger; - - public ContainerGenerator( - GeneratorExecutionContext context, - WellKnownTypes wellKnownTypes, - IDiagLogger diagLogger) + if (!containerInfo.IsValid || containerInfo.ResolutionRootType is null) { - _context = context; - _wellKnownTypes = wellKnownTypes; - _diagLogger = diagLogger; + _diagLogger.Log($"return generation"); + return; } - public void Generate(IContainerInfo containerInfo, ContainerResolution containerResolution) - { - if (!containerInfo.IsValid || containerInfo.ResolutionRootType is null) - { - _diagLogger.Log($"return generation"); - return; - } + var generatedContainer = new StringBuilder() + .AppendLine($"namespace {containerInfo.Namespace}") + .AppendLine($"{{") + .AppendLine($"partial class {containerInfo.Name} : {_wellKnownTypes.Disposable.FullName()}") + .AppendLine($"{{"); - var generatedContainer = new StringBuilder() - .AppendLine($"namespace {containerInfo.Namespace}") - .AppendLine($"{{") - .AppendLine($"partial class {containerInfo.Name} : {_wellKnownTypes.Disposable.FullName()}") - .AppendLine($"{{"); - - generatedContainer = GenerateContainerDisposalFunction( - generatedContainer, - containerResolution.DisposalHandling, - containerResolution); - - foreach (var singleInstanceResolution in containerResolution.SingleInstanceResolutions) - { - generatedContainer = generatedContainer - .AppendLine($"private {singleInstanceResolution.Function.TypeFullName} {singleInstanceResolution.Function.FieldReference};") - .AppendLine($"private {_wellKnownTypes.SemaphoreSlim.FullName()} {singleInstanceResolution.Function.LockReference} = new {_wellKnownTypes.SemaphoreSlim.FullName()}(1);") - .AppendLine($"public {singleInstanceResolution.Function.TypeFullName} {singleInstanceResolution.Function.Reference}()") - .AppendLine($"{{") - .AppendLine($"if (!object.ReferenceEquals({singleInstanceResolution.Function.FieldReference}, null)) return {singleInstanceResolution.Function.FieldReference};") - .AppendLine($"this.{singleInstanceResolution.Function.LockReference}.Wait();") - .AppendLine($"try") - .AppendLine($"{{") - .AppendLine($"if (this.{containerResolution.DisposalHandling.DisposedPropertyReference}) throw new {_wellKnownTypes.ObjectDisposedException}(nameof({containerInfo.Name}));"); - - generatedContainer = GenerateResolutionFunction(generatedContainer, singleInstanceResolution.Dependency); - - generatedContainer = generatedContainer - .AppendLine($"this.{singleInstanceResolution.Function.FieldReference} = {singleInstanceResolution.Dependency.Reference};") - .AppendLine($"}}") - .AppendLine($"finally") - .AppendLine($"{{") - .AppendLine($"this.{singleInstanceResolution.Function.LockReference}.Release();") - .AppendLine($"}}") - .AppendLine($"return this.{singleInstanceResolution.Function.FieldReference};") - .AppendLine($"}}"); - } + generatedContainer = GenerateContainerDisposalFunction( + generatedContainer, + containerResolution.DisposalHandling, + containerResolution); + foreach (var singleInstanceResolution in containerResolution.SingleInstanceResolutions) + { generatedContainer = generatedContainer - .AppendLine($"public {containerResolution.TypeFullName} Resolve()") + .AppendLine($"private {singleInstanceResolution.Function.TypeFullName} {singleInstanceResolution.Function.FieldReference};") + .AppendLine($"private {_wellKnownTypes.SemaphoreSlim.FullName()} {singleInstanceResolution.Function.LockReference} = new {_wellKnownTypes.SemaphoreSlim.FullName()}(1);") + .AppendLine($"public {singleInstanceResolution.Function.TypeFullName} {singleInstanceResolution.Function.Reference}()") + .AppendLine($"{{") + .AppendLine($"if (!object.ReferenceEquals({singleInstanceResolution.Function.FieldReference}, null)) return {singleInstanceResolution.Function.FieldReference};") + .AppendLine($"this.{singleInstanceResolution.Function.LockReference}.Wait();") + .AppendLine($"try") .AppendLine($"{{") .AppendLine($"if (this.{containerResolution.DisposalHandling.DisposedPropertyReference}) throw new {_wellKnownTypes.ObjectDisposedException}(nameof({containerInfo.Name}));"); - generatedContainer = GenerateResolutionFunction(generatedContainer, containerResolution); + generatedContainer = GenerateResolutionFunction(generatedContainer, singleInstanceResolution.Dependency); generatedContainer = generatedContainer + .AppendLine($"this.{singleInstanceResolution.Function.FieldReference} = {singleInstanceResolution.Dependency.Reference};") + .AppendLine($"}}") + .AppendLine($"finally") + .AppendLine($"{{") + .AppendLine($"this.{singleInstanceResolution.Function.LockReference}.Release();") + .AppendLine($"}}") + .AppendLine($"return this.{singleInstanceResolution.Function.FieldReference};") + .AppendLine($"}}"); + } + + generatedContainer = generatedContainer + .AppendLine($"public {containerResolution.TypeFullName} Resolve()") + .AppendLine($"{{") + .AppendLine($"if (this.{containerResolution.DisposalHandling.DisposedPropertyReference}) throw new {_wellKnownTypes.ObjectDisposedException}(nameof({containerInfo.Name}));"); + + generatedContainer = GenerateResolutionFunction(generatedContainer, containerResolution); + + generatedContainer = generatedContainer .AppendLine($"return {containerResolution.Reference};") .AppendLine($"}}") .AppendLine($"}}") .AppendLine($"}}") - ; + ; - var containerSource = CSharpSyntaxTree - .ParseText(SourceText.From(generatedContainer.ToString(), Encoding.UTF8)) - .GetRoot() - .NormalizeWhitespace() - .SyntaxTree - .GetText(); - _context.AddSource($"{containerInfo.Namespace}.{containerInfo.Name}.g.cs", containerSource); + var containerSource = CSharpSyntaxTree + .ParseText(SourceText.From(generatedContainer.ToString(), Encoding.UTF8)) + .GetRoot() + .NormalizeWhitespace() + .SyntaxTree + .GetText(); + _context.AddSource($"{containerInfo.Namespace}.{containerInfo.Name}.g.cs", containerSource); - StringBuilder GenerateContainerDisposalFunction( - StringBuilder stringBuilder, - ContainerResolutionDisposalHandling disposalHandling, - ContainerResolution containerResolution) + StringBuilder GenerateContainerDisposalFunction( + StringBuilder stringBuilder, + ContainerResolutionDisposalHandling disposalHandling, + ContainerResolution containerResolution) + { + stringBuilder = stringBuilder + .AppendLine($"private {disposalHandling.DisposableCollection.TypeFullName} {disposalHandling.DisposableCollection.Reference} = new {disposalHandling.DisposableCollection.TypeFullName}();") + .AppendLine($"private int {disposalHandling.DisposedFieldReference} = 0;") + .AppendLine($"private bool {disposalHandling.DisposedPropertyReference} => {disposalHandling.DisposedFieldReference} != 0;") + .AppendLine($"public void Dispose()") + .AppendLine($"{{") + .AppendLine($"var {disposalHandling.DisposedLocalReference} = global::System.Threading.Interlocked.Exchange(ref this.{disposalHandling.DisposedFieldReference}, 1);") + .AppendLine($"if ({disposalHandling.DisposedLocalReference} != 0) return;"); + + foreach (var singleInstanceResolution in containerResolution.SingleInstanceResolutions) { stringBuilder = stringBuilder - .AppendLine($"private {disposalHandling.DisposableCollection.TypeFullName} {disposalHandling.DisposableCollection.Reference} = new {disposalHandling.DisposableCollection.TypeFullName}();") - .AppendLine($"private int {disposalHandling.DisposedFieldReference} = 0;") - .AppendLine($"private bool {disposalHandling.DisposedPropertyReference} => {disposalHandling.DisposedFieldReference} != 0;") - .AppendLine($"public void Dispose()") - .AppendLine($"{{") - .AppendLine($"var {disposalHandling.DisposedLocalReference} = global::System.Threading.Interlocked.Exchange(ref this.{disposalHandling.DisposedFieldReference}, 1);") - .AppendLine($"if ({disposalHandling.DisposedLocalReference} != 0) return;"); - - foreach (var singleInstanceResolution in containerResolution.SingleInstanceResolutions) - { - stringBuilder = stringBuilder - .AppendLine($"this.{singleInstanceResolution.Function.LockReference}.Wait();"); - - } + .AppendLine($"this.{singleInstanceResolution.Function.LockReference}.Wait();"); + + } + stringBuilder = stringBuilder + .AppendLine($"try") + .AppendLine($"{{") + .AppendLine($"foreach(var {disposalHandling.DisposableLocalReference} in {disposalHandling.DisposableCollection.Reference})") + .AppendLine($"{{") + .AppendLine($"try") + .AppendLine($"{{") + .AppendLine($"{disposalHandling.DisposableLocalReference}.Dispose();") + .AppendLine($"}}") + .AppendLine($"catch({_wellKnownTypes.Exception.FullName()})") + .AppendLine($"{{") + .AppendLine($"// catch and ignore exceptions of individual disposals so the other disposals are triggered") + .AppendLine($"}}") + .AppendLine($"}}") + .AppendLine($"}}") + .AppendLine($"finally") + .AppendLine($"{{"); + + foreach (var singleInstanceResolution in containerResolution.SingleInstanceResolutions) + { stringBuilder = stringBuilder - .AppendLine($"try") - .AppendLine($"{{") - .AppendLine($"foreach(var {disposalHandling.DisposableLocalReference} in {disposalHandling.DisposableCollection.Reference})") - .AppendLine($"{{") - .AppendLine($"try") - .AppendLine($"{{") - .AppendLine($"{disposalHandling.DisposableLocalReference}.Dispose();") - .AppendLine($"}}") - .AppendLine($"catch({_wellKnownTypes.Exception.FullName()})") - .AppendLine($"{{") - .AppendLine($"// catch and ignore exceptions of individual disposals so the other disposals are triggered") - .AppendLine($"}}") - .AppendLine($"}}") - .AppendLine($"}}") - .AppendLine($"finally") - .AppendLine($"{{"); - - foreach (var singleInstanceResolution in containerResolution.SingleInstanceResolutions) - { - stringBuilder = stringBuilder - .AppendLine($"this.{singleInstanceResolution.Function.LockReference}.Release();"); - } + .AppendLine($"this.{singleInstanceResolution.Function.LockReference}.Release();"); + } - stringBuilder = stringBuilder - .AppendLine($"}}") - .AppendLine($"}}"); + stringBuilder = stringBuilder + .AppendLine($"}}") + .AppendLine($"}}"); - return stringBuilder; - } + return stringBuilder; + } - StringBuilder GenerateResolutionFunction( - StringBuilder stringBuilder, - Resolvable resolution) - { - stringBuilder = GenerateFields(stringBuilder, resolution); - stringBuilder = GenerateResolutions(stringBuilder, resolution); + StringBuilder GenerateResolutionFunction( + StringBuilder stringBuilder, + Resolvable resolution) + { + stringBuilder = GenerateFields(stringBuilder, resolution); + stringBuilder = GenerateResolutions(stringBuilder, resolution); - return stringBuilder; - } + return stringBuilder; + } - StringBuilder GenerateFields( - StringBuilder stringBuilder, - Resolvable resolution) + StringBuilder GenerateFields( + StringBuilder stringBuilder, + Resolvable resolution) + { + switch (resolution) { - switch (resolution) - { - case SingleInstanceReferenceResolution(var reference, { TypeFullName: {} typeFullName}): - stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); - break; - case ContainerResolution(var rootResolution, _, _): - stringBuilder = GenerateFields(stringBuilder, rootResolution); - break; - case InterfaceResolution(var reference, var typeFullName, Resolvable resolutionBase): - stringBuilder = GenerateFields(stringBuilder, resolutionBase); - stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); - break; - case ConstructorResolution(var reference, var typeFullName, _, var parameters): - stringBuilder = parameters.Aggregate(stringBuilder, - (builder, tuple) => GenerateFields(builder, tuple.Dependency)); - stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); - break; - case FuncResolution(var reference, var typeFullName, _, _): - stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); - break; - case FuncParameterResolution: - break; - case CollectionResolution(var reference, var typeFullName, _, var items): - stringBuilder = items.OfType().Aggregate(stringBuilder, GenerateFields); - stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); - break; - default: - throw new Exception("Unexpected case or not implemented."); - } - - return stringBuilder; + case SingleInstanceReferenceResolution(var reference, { TypeFullName: {} typeFullName}): + stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); + break; + case ContainerResolution(var rootResolution, _, _): + stringBuilder = GenerateFields(stringBuilder, rootResolution); + break; + case InterfaceResolution(var reference, var typeFullName, Resolvable resolutionBase): + stringBuilder = GenerateFields(stringBuilder, resolutionBase); + stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); + break; + case ConstructorResolution(var reference, var typeFullName, _, var parameters): + stringBuilder = parameters.Aggregate(stringBuilder, + (builder, tuple) => GenerateFields(builder, tuple.Dependency)); + stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); + break; + case FuncResolution(var reference, var typeFullName, _, _): + stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); + break; + case FuncParameterResolution: + break; + case CollectionResolution(var reference, var typeFullName, _, var items): + stringBuilder = items.OfType().Aggregate(stringBuilder, GenerateFields); + stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); + break; + default: + throw new Exception("Unexpected case or not implemented."); } - StringBuilder GenerateResolutions( - StringBuilder stringBuilder, - Resolvable resolution) + return stringBuilder; + } + + StringBuilder GenerateResolutions( + StringBuilder stringBuilder, + Resolvable resolution) + { + switch (resolution) { - switch (resolution) - { - case SingleInstanceReferenceResolution(var reference, { Reference: {} functionReference}): - stringBuilder = stringBuilder.AppendLine($"{reference} = {functionReference}();"); - break; - case ContainerResolution(var rootResolution, _, _): - stringBuilder = GenerateResolutions(stringBuilder, rootResolution); - break; - case InterfaceResolution(var reference, var typeFullName, Resolvable resolutionBase): - stringBuilder = GenerateResolutions(stringBuilder, resolutionBase); - stringBuilder = stringBuilder.AppendLine( - $"{reference} = ({typeFullName}) {resolutionBase.Reference};"); - break; - case ConstructorResolution(var reference, var typeFullName, var disposableCollectionResolution, var parameters): - stringBuilder = parameters.Aggregate(stringBuilder, - (builder, tuple) => GenerateResolutions(builder, tuple.Dependency ?? throw new Exception())); - stringBuilder = stringBuilder.AppendLine( - $"{reference} = new {typeFullName}({string.Join(", ", parameters.Select(d => $"{d.name}: {d.Dependency?.Reference}"))});"); - if (disposableCollectionResolution is {}) - stringBuilder = stringBuilder.AppendLine( - $"{disposableCollectionResolution.Reference}.Add(({_wellKnownTypes.Disposable.FullName()}) {reference});"); - break; - case FuncResolution(var reference, _, var parameter, Resolvable resolutionBase): - stringBuilder = stringBuilder.AppendLine($"{reference} = ({string.Join(", ", parameter.Select(fpr => fpr.Reference))}) =>"); - stringBuilder = stringBuilder.AppendLine($"{{"); - GenerateResolutionFunction(stringBuilder, resolutionBase); - stringBuilder = stringBuilder.AppendLine($"return {resolutionBase.Reference};"); - stringBuilder = stringBuilder.AppendLine($"}};"); - break; - case FuncParameterResolution: - break; - case CollectionResolution(var reference, _, var itemFullName, var items): - stringBuilder = items.OfType().Aggregate(stringBuilder, GenerateResolutions); + case SingleInstanceReferenceResolution(var reference, { Reference: {} functionReference}): + stringBuilder = stringBuilder.AppendLine($"{reference} = {functionReference}();"); + break; + case ContainerResolution(var rootResolution, _, _): + stringBuilder = GenerateResolutions(stringBuilder, rootResolution); + break; + case InterfaceResolution(var reference, var typeFullName, Resolvable resolutionBase): + stringBuilder = GenerateResolutions(stringBuilder, resolutionBase); + stringBuilder = stringBuilder.AppendLine( + $"{reference} = ({typeFullName}) {resolutionBase.Reference};"); + break; + case ConstructorResolution(var reference, var typeFullName, var disposableCollectionResolution, var parameters): + stringBuilder = parameters.Aggregate(stringBuilder, + (builder, tuple) => GenerateResolutions(builder, tuple.Dependency ?? throw new Exception())); + stringBuilder = stringBuilder.AppendLine( + $"{reference} = new {typeFullName}({string.Join(", ", parameters.Select(d => $"{d.name}: {d.Dependency?.Reference}"))});"); + if (disposableCollectionResolution is {}) stringBuilder = stringBuilder.AppendLine( - $"{reference} = new {itemFullName}[]{{{string.Join(", ", items.Select(d => $"({itemFullName}) {(d as Resolvable)?.Reference}"))}}};"); - break; - default: - throw new Exception("Unexpected case or not implemented."); - } - - return stringBuilder; + $"{disposableCollectionResolution.Reference}.Add(({_wellKnownTypes.Disposable.FullName()}) {reference});"); + break; + case FuncResolution(var reference, _, var parameter, Resolvable resolutionBase): + stringBuilder = stringBuilder.AppendLine($"{reference} = ({string.Join(", ", parameter.Select(fpr => fpr.Reference))}) =>"); + stringBuilder = stringBuilder.AppendLine($"{{"); + GenerateResolutionFunction(stringBuilder, resolutionBase); + stringBuilder = stringBuilder.AppendLine($"return {resolutionBase.Reference};"); + stringBuilder = stringBuilder.AppendLine($"}};"); + break; + case FuncParameterResolution: + break; + case CollectionResolution(var reference, _, var itemFullName, var items): + stringBuilder = items.OfType().Aggregate(stringBuilder, GenerateResolutions); + stringBuilder = stringBuilder.AppendLine( + $"{reference} = new {itemFullName}[]{{{string.Join(", ", items.Select(d => $"({itemFullName}) {(d as Resolvable)?.Reference}"))}}};"); + break; + default: + throw new Exception("Unexpected case or not implemented."); } + + return stringBuilder; } } -} +} \ No newline at end of file diff --git a/Main/ContainerInfo.cs b/Main/ContainerInfo.cs index 945f773b..95d9dc8f 100644 --- a/Main/ContainerInfo.cs +++ b/Main/ContainerInfo.cs @@ -1,44 +1,40 @@ -using System.Linq; -using Microsoft.CodeAnalysis; +namespace MrMeeseeks.DIE; -namespace MrMeeseeks.DIE +public interface IContainerInfo { - public interface IContainerInfo - { - string Name { get; } - string Namespace { get; } - bool IsValid { get; } - INamedTypeSymbol? ResolutionRootType { get; } - } + string Name { get; } + string Namespace { get; } + bool IsValid { get; } + INamedTypeSymbol? ResolutionRootType { get; } +} - internal class ContainerInfo : IContainerInfo +internal class ContainerInfo : IContainerInfo +{ + public ContainerInfo( + // parameters + INamedTypeSymbol containerClass, + + // dependencies + WellKnownTypes wellKnowTypes) { - public ContainerInfo( - // parameters - INamedTypeSymbol containerClass, + Name = containerClass.Name; + Namespace = containerClass.ContainingNamespace.FullName(); - // dependencies - WellKnownTypes wellKnowTypes) + var namedTypeSymbol = containerClass.AllInterfaces.Single(x => x.OriginalDefinition.Equals(wellKnowTypes.Container, SymbolEqualityComparer.Default)); + var typeParameterSymbol = namedTypeSymbol.TypeArguments.Single(); + if (typeParameterSymbol is INamedTypeSymbol { IsUnboundGenericType: false } type && type.IsAccessibleInternally()) { - Name = containerClass.Name; - Namespace = containerClass.ContainingNamespace.FullName(); - - var namedTypeSymbol = containerClass.AllInterfaces.Single(x => x.OriginalDefinition.Equals(wellKnowTypes.Container, SymbolEqualityComparer.Default)); - var typeParameterSymbol = namedTypeSymbol.TypeArguments.Single(); - if (typeParameterSymbol is INamedTypeSymbol { IsUnboundGenericType: false } type && type.IsAccessibleInternally()) - { - ResolutionRootType = type; - IsValid = true; - } - else - { - IsValid = false; - } + ResolutionRootType = type; + IsValid = true; + } + else + { + IsValid = false; } - - public string Name { get; } - public string Namespace { get; } - public bool IsValid { get; } - public INamedTypeSymbol? ResolutionRootType { get; } } + + public string Name { get; } + public string Namespace { get; } + public bool IsValid { get; } + public INamedTypeSymbol? ResolutionRootType { get; } } \ No newline at end of file diff --git a/Main/DiagLogger.cs b/Main/DiagLogger.cs index c44d4893..c5fd3139 100644 --- a/Main/DiagLogger.cs +++ b/Main/DiagLogger.cs @@ -1,31 +1,28 @@ -using Microsoft.CodeAnalysis; +namespace MrMeeseeks.DIE; -namespace MrMeeseeks.DIE +internal interface IDiagLogger { - internal interface IDiagLogger - { - void Log(string message); - - void Log(int id, string title, string message, string category, DiagnosticSeverity diagnosticSeverity); - } + void Log(string message); - internal class DiagLogger : IDiagLogger - { - private readonly GeneratorExecutionContext _context; + void Log(int id, string title, string message, string category, DiagnosticSeverity diagnosticSeverity); +} - public DiagLogger( - GeneratorExecutionContext context) - { - _context = context; - } +internal class DiagLogger : IDiagLogger +{ + private readonly GeneratorExecutionContext _context; - public void Log(int id, string title, string message, string category, DiagnosticSeverity diagnosticSeverity) - { - _context.ReportDiagnostic(Diagnostic.Create( - new DiagnosticDescriptor($"DIE{id.ToString().PadLeft(3, '0')}", title, message, category, diagnosticSeverity, true), - Location.None)); - } + public DiagLogger( + GeneratorExecutionContext context) + { + _context = context; + } - public void Log(string message) => Log(0, "INFO", message, "INFO", DiagnosticSeverity.Warning); + public void Log(int id, string title, string message, string category, DiagnosticSeverity diagnosticSeverity) + { + _context.ReportDiagnostic(Diagnostic.Create( + new DiagnosticDescriptor($"DIE{id.ToString().PadLeft(3, '0')}", title, message, category, diagnosticSeverity, true), + Location.None)); } -} + + public void Log(string message) => Log(0, "INFO", message, "INFO", DiagnosticSeverity.Warning); +} \ No newline at end of file diff --git a/Main/ExecuteImpl.cs b/Main/ExecuteImpl.cs index 720a72df..cf45a030 100644 --- a/Main/ExecuteImpl.cs +++ b/Main/ExecuteImpl.cs @@ -1,77 +1,73 @@ -using System; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using System.Linq; +using Microsoft.CodeAnalysis.CSharp.Syntax; -namespace MrMeeseeks.DIE +namespace MrMeeseeks.DIE; + +internal interface IExecute +{ + void Execute(); +} + +internal class ExecuteImpl : IExecute { - internal interface IExecute + private readonly GeneratorExecutionContext _context; + private readonly WellKnownTypes _wellKnownTypes; + private readonly IContainerGenerator _containerGenerator; + private readonly IContainerErrorGenerator _containerErrorGenerator; + private readonly IResolutionTreeFactory _resolutionTreeFactory; + private readonly IResolutionTreeCreationErrorHarvester _resolutionTreeCreationErrorHarvester; + private readonly Func _containerInfoFactory; + private readonly IDiagLogger _diagLogger; + + public ExecuteImpl( + GeneratorExecutionContext context, + WellKnownTypes wellKnownTypes, + IContainerGenerator containerGenerator, + IContainerErrorGenerator containerErrorGenerator, + IResolutionTreeFactory resolutionTreeFactory, + IResolutionTreeCreationErrorHarvester resolutionTreeCreationErrorHarvester, + Func containerInfoFactory, + IDiagLogger diagLogger) { - void Execute(); + _context = context; + _wellKnownTypes = wellKnownTypes; + _containerGenerator = containerGenerator; + _containerErrorGenerator = containerErrorGenerator; + _resolutionTreeFactory = resolutionTreeFactory; + _resolutionTreeCreationErrorHarvester = resolutionTreeCreationErrorHarvester; + _containerInfoFactory = containerInfoFactory; + _diagLogger = diagLogger; } - internal class ExecuteImpl : IExecute + public void Execute() { - private readonly GeneratorExecutionContext _context; - private readonly WellKnownTypes _wellKnownTypes; - private readonly IContainerGenerator _containerGenerator; - private readonly IContainerErrorGenerator _containerErrorGenerator; - private readonly IResolutionTreeFactory _resolutionTreeFactory; - private readonly IResolutionTreeCreationErrorHarvester _resolutionTreeCreationErrorHarvester; - private readonly Func _containerInfoFactory; - private readonly IDiagLogger _diagLogger; - - public ExecuteImpl( - GeneratorExecutionContext context, - WellKnownTypes wellKnownTypes, - IContainerGenerator containerGenerator, - IContainerErrorGenerator containerErrorGenerator, - IResolutionTreeFactory resolutionTreeFactory, - IResolutionTreeCreationErrorHarvester resolutionTreeCreationErrorHarvester, - Func containerInfoFactory, - IDiagLogger diagLogger) + _diagLogger.Log("Start Execute"); + foreach (var syntaxTree in _context.Compilation.SyntaxTrees) { - _context = context; - _wellKnownTypes = wellKnownTypes; - _containerGenerator = containerGenerator; - _containerErrorGenerator = containerErrorGenerator; - _resolutionTreeFactory = resolutionTreeFactory; - _resolutionTreeCreationErrorHarvester = resolutionTreeCreationErrorHarvester; - _containerInfoFactory = containerInfoFactory; - _diagLogger = diagLogger; - } - - public void Execute() - { - _diagLogger.Log("Start Execute"); - foreach (var syntaxTree in _context.Compilation.SyntaxTrees) + var semanticModel = _context.Compilation.GetSemanticModel(syntaxTree); + var containerClasses = syntaxTree + .GetRoot() + .DescendantNodesAndSelf() + .OfType() + .Select(x => semanticModel.GetDeclaredSymbol(x)) + .Where(x => x != null) + .OfType() + .Where(x => x.AllInterfaces.Any(x => x.OriginalDefinition.Equals(_wellKnownTypes.Container, SymbolEqualityComparer.Default))); + foreach (var namedTypeSymbol in containerClasses) { - var semanticModel = _context.Compilation.GetSemanticModel(syntaxTree); - var containerClasses = syntaxTree - .GetRoot() - .DescendantNodesAndSelf() - .OfType() - .Select(x => semanticModel.GetDeclaredSymbol(x)) - .Where(x => x != null) - .OfType() - .Where(x => x.AllInterfaces.Any(x => x.OriginalDefinition.Equals(_wellKnownTypes.Container, SymbolEqualityComparer.Default))); - foreach (var namedTypeSymbol in containerClasses) + var containerInfo = _containerInfoFactory(namedTypeSymbol); + if (containerInfo.IsValid && containerInfo.ResolutionRootType is { }) { - var containerInfo = _containerInfoFactory(namedTypeSymbol); - if (containerInfo.IsValid && containerInfo.ResolutionRootType is { }) - { - var containerResolution = _resolutionTreeFactory.Create(containerInfo.ResolutionRootType); - var errorTreeItems = _resolutionTreeCreationErrorHarvester.Harvest(containerResolution); - if (errorTreeItems.Any()) - _containerErrorGenerator.Generate(containerInfo, errorTreeItems); - else - _containerGenerator.Generate(containerInfo, containerResolution); - } - else throw new NotImplementedException("Handle non-valid container information"); + var containerResolution = _resolutionTreeFactory.Create(containerInfo.ResolutionRootType); + var errorTreeItems = _resolutionTreeCreationErrorHarvester.Harvest(containerResolution); + if (errorTreeItems.Any()) + _containerErrorGenerator.Generate(containerInfo, errorTreeItems); + else + _containerGenerator.Generate(containerInfo, containerResolution); } + else throw new NotImplementedException("Handle non-valid container information"); } - - _diagLogger.Log("End Execute"); } + + _diagLogger.Log("End Execute"); } -} +} \ No newline at end of file diff --git a/Main/GetAllImplementations.cs b/Main/GetAllImplementations.cs index 6b06e9cb..48560391 100644 --- a/Main/GetAllImplementations.cs +++ b/Main/GetAllImplementations.cs @@ -1,42 +1,38 @@ -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using System.Collections.Generic; -using System.Linq; +using Microsoft.CodeAnalysis.CSharp.Syntax; -namespace MrMeeseeks.DIE +namespace MrMeeseeks.DIE; + +internal interface IGetAllImplementations { - internal interface IGetAllImplementations - { - IReadOnlyList AllImplementations { get; } - } + IReadOnlyList AllImplementations { get; } +} - internal class GetAllImplementations : IGetAllImplementations +internal class GetAllImplementations : IGetAllImplementations +{ + public GetAllImplementations( + GeneratorExecutionContext context, + ITypesFromAttributes typesFromAttributes) { - public GetAllImplementations( - GeneratorExecutionContext context, - ITypesFromAttributes typesFromAttributes) - { - var implementationsOfThisAssembly = context.Compilation.SyntaxTrees - .Select(st => (st, context.Compilation.GetSemanticModel(st))) - .SelectMany(t => t.st - .GetRoot() - .DescendantNodesAndSelf() - .OfType() - .Select(c => t.Item2.GetDeclaredSymbol(c)) - .Where(c => c is not null) - .OfType()); - - var spiedImplementations = typesFromAttributes - .Spy - .SelectMany(t => t?.GetMembers() - .OfType() - .Where(ms => !ms.ReturnsVoid) - .Select(ms => ms.ReturnType) - .OfType()); + var implementationsOfThisAssembly = context.Compilation.SyntaxTrees + .Select(st => (st, context.Compilation.GetSemanticModel(st))) + .SelectMany(t => t.st + .GetRoot() + .DescendantNodesAndSelf() + .OfType() + .Select(c => t.Item2.GetDeclaredSymbol(c)) + .Where(c => c is not null) + .OfType()); - AllImplementations = implementationsOfThisAssembly.Concat(spiedImplementations).ToList(); - } + var spiedImplementations = typesFromAttributes + .Spy + .SelectMany(t => t?.GetMembers() + .OfType() + .Where(ms => !ms.ReturnsVoid) + .Select(ms => ms.ReturnType) + .OfType()); - public IReadOnlyList AllImplementations { get; } + AllImplementations = implementationsOfThisAssembly.Concat(spiedImplementations).ToList(); } -} + + public IReadOnlyList AllImplementations { get; } +} \ No newline at end of file diff --git a/Main/GetAssemblyAttributes.cs b/Main/GetAssemblyAttributes.cs index f45b1eb0..34db54f0 100644 --- a/Main/GetAssemblyAttributes.cs +++ b/Main/GetAssemblyAttributes.cs @@ -1,24 +1,19 @@ -using System.Collections.Generic; -using System.Collections.ObjectModel; -using Microsoft.CodeAnalysis; +namespace MrMeeseeks.DIE; -namespace MrMeeseeks.DIE +public interface IGetAssemblyAttributes { - public interface IGetAssemblyAttributes - { - IReadOnlyList AllAssemblyAttributes { get; } - } - - internal class GetAssemblyAttributes : IGetAssemblyAttributes - { - private readonly GeneratorExecutionContext _context; + IReadOnlyList AllAssemblyAttributes { get; } +} - public GetAssemblyAttributes(GeneratorExecutionContext context) - { - _context = context; - } +internal class GetAssemblyAttributes : IGetAssemblyAttributes +{ + private readonly GeneratorExecutionContext _context; - public IReadOnlyList AllAssemblyAttributes => new ReadOnlyCollection( - _context.Compilation.Assembly.GetAttributes()); + public GetAssemblyAttributes(GeneratorExecutionContext context) + { + _context = context; } + + public IReadOnlyList AllAssemblyAttributes => new ReadOnlyCollection( + _context.Compilation.Assembly.GetAttributes()); } \ No newline at end of file diff --git a/Main/IContainer.cs b/Main/IContainer.cs index f646ccb0..cea31bdf 100644 --- a/Main/IContainer.cs +++ b/Main/IContainer.cs @@ -1,6 +1,5 @@ -namespace MrMeeseeks.DIE +namespace MrMeeseeks.DIE; + +public partial interface IContainer { - public partial interface IContainer - { - } -} +} \ No newline at end of file diff --git a/Main/InitializeImpl.cs b/Main/InitializeImpl.cs index 07e3d2d4..a3f7aeef 100644 --- a/Main/InitializeImpl.cs +++ b/Main/InitializeImpl.cs @@ -1,26 +1,22 @@ -using Microsoft.CodeAnalysis; -using System; +namespace MrMeeseeks.DIE; -namespace MrMeeseeks.DIE +internal interface IInitialize { - internal interface IInitialize - { - void Initialize(); - } - - internal class InitializeImpl : IInitialize - { - private readonly GeneratorInitializationContext _context; - private readonly Func _syntaxReceiverFactory; + void Initialize(); +} - public InitializeImpl( - GeneratorInitializationContext context, - Func syntaxReceiverFactory) - { - _context = context; - _syntaxReceiverFactory = syntaxReceiverFactory; - } +internal class InitializeImpl : IInitialize +{ + private readonly GeneratorInitializationContext _context; + private readonly Func _syntaxReceiverFactory; - public void Initialize() => _context.RegisterForSyntaxNotifications(() => _syntaxReceiverFactory()); + public InitializeImpl( + GeneratorInitializationContext context, + Func syntaxReceiverFactory) + { + _context = context; + _syntaxReceiverFactory = syntaxReceiverFactory; } -} + + public void Initialize() => _context.RegisterForSyntaxNotifications(() => _syntaxReceiverFactory()); +} \ No newline at end of file diff --git a/Main/IsExternalInit.cs b/Main/IsExternalInit.cs index df783a36..550d0b62 100644 --- a/Main/IsExternalInit.cs +++ b/Main/IsExternalInit.cs @@ -1,6 +1,5 @@ -namespace System.Runtime.CompilerServices +namespace System.Runtime.CompilerServices; + +public class IsExternalInit { - public class IsExternalInit - { - } -} +} \ No newline at end of file diff --git a/Main/ReferenceGenerator.cs b/Main/ReferenceGenerator.cs index f3b6ad00..de90089b 100644 --- a/Main/ReferenceGenerator.cs +++ b/Main/ReferenceGenerator.cs @@ -1,44 +1,40 @@ -using System; -using Microsoft.CodeAnalysis; +namespace MrMeeseeks.DIE; -namespace MrMeeseeks.DIE +public interface IReferenceGenerator { - public interface IReferenceGenerator - { - string Generate(ITypeSymbol type); - string Generate(string prefix, ITypeSymbol type); - string Generate(string hardcodedName); - } + string Generate(ITypeSymbol type); + string Generate(string prefix, ITypeSymbol type); + string Generate(string hardcodedName); +} - internal class ReferenceGenerator : IReferenceGenerator - { - private int _i = -1; - private readonly int _j; +internal class ReferenceGenerator : IReferenceGenerator +{ + private int _i = -1; + private readonly int _j; - public ReferenceGenerator(int j) => _j = j; + public ReferenceGenerator(int j) => _j = j; - public string Generate(ITypeSymbol type) => - Generate($"{char.ToLower(type.Name[0])}{type.Name.Substring(1)}"); + public string Generate(ITypeSymbol type) => + Generate($"{char.ToLower(type.Name[0])}{type.Name.Substring(1)}"); - public string Generate(string prefix, ITypeSymbol type) => - Generate($"{prefix}{type.Name}"); + public string Generate(string prefix, ITypeSymbol type) => + Generate($"{prefix}{type.Name}"); - public string Generate(string hardcodedName) => - $"{hardcodedName}_{_j}_{++_i}"; - } + public string Generate(string hardcodedName) => + $"{hardcodedName}_{_j}_{++_i}"; +} - public interface IReferenceGeneratorFactory - { - IReferenceGenerator Create(); - } - - internal class ReferenceGeneratorFactory : IReferenceGeneratorFactory - { - private readonly Func _referenceGeneratorFactory; - private int _j = -1; +public interface IReferenceGeneratorFactory +{ + IReferenceGenerator Create(); +} + +internal class ReferenceGeneratorFactory : IReferenceGeneratorFactory +{ + private readonly Func _referenceGeneratorFactory; + private int _j = -1; - public ReferenceGeneratorFactory(Func referenceGeneratorFactory) => _referenceGeneratorFactory = referenceGeneratorFactory; + public ReferenceGeneratorFactory(Func referenceGeneratorFactory) => _referenceGeneratorFactory = referenceGeneratorFactory; - public IReferenceGenerator Create() => _referenceGeneratorFactory(++_j); - } + public IReferenceGenerator Create() => _referenceGeneratorFactory(++_j); } \ No newline at end of file diff --git a/Main/ResolutionTreeCreationErrorHarvester.cs b/Main/ResolutionTreeCreationErrorHarvester.cs index dea90970..9c4fc81b 100644 --- a/Main/ResolutionTreeCreationErrorHarvester.cs +++ b/Main/ResolutionTreeCreationErrorHarvester.cs @@ -1,56 +1,52 @@ -using System; -using System.Collections.Generic; +namespace MrMeeseeks.DIE; -namespace MrMeeseeks.DIE +internal interface IResolutionTreeCreationErrorHarvester { - internal interface IResolutionTreeCreationErrorHarvester - { - IReadOnlyList Harvest(ResolutionTreeItem root); - } + IReadOnlyList Harvest(ResolutionTreeItem root); +} - internal class ResolutionTreeCreationErrorHarvester : IResolutionTreeCreationErrorHarvester +internal class ResolutionTreeCreationErrorHarvester : IResolutionTreeCreationErrorHarvester +{ + public IReadOnlyList Harvest(ResolutionTreeItem root) { - public IReadOnlyList Harvest(ResolutionTreeItem root) - { - var errorTreeItems = new List(); - Inner(root, errorTreeItems); - return errorTreeItems; + var errorTreeItems = new List(); + Inner(root, errorTreeItems); + return errorTreeItems; - static void Inner(ResolutionTreeItem item, ICollection errorTreeItems) + static void Inner(ResolutionTreeItem item, ICollection errorTreeItems) + { + switch (item) { - switch (item) - { - case SingleInstanceReferenceResolution: - break; - case ContainerResolution containerResolution: - Inner(containerResolution.RootResolution, errorTreeItems); - break; - case ErrorTreeItem errorTreeItem: - errorTreeItems.Add(errorTreeItem); - break; - case ConstructorResolution constructorResolution: - foreach (var valueTuple in constructorResolution.Parameter) - Inner(valueTuple.Dependency, errorTreeItems); - break; - case CollectionResolution collectionResolution: - foreach (var resolutionTreeItem in collectionResolution.Parameter) - Inner(resolutionTreeItem, errorTreeItems); - break; - case FuncParameterResolution: - break; - case FuncResolution funcResolution: - foreach (var funcParameterResolution in funcResolution.Parameter) - Inner(funcParameterResolution, errorTreeItems); - Inner(funcResolution.Dependency, errorTreeItems); - break; - case InterfaceResolution interfaceResolution: - Inner(interfaceResolution.Dependency, errorTreeItems); - break; - case Resolvable: - throw new ArgumentOutOfRangeException(nameof(item)); - default: - throw new ArgumentOutOfRangeException(nameof(item)); - } + case SingleInstanceReferenceResolution: + break; + case ContainerResolution containerResolution: + Inner(containerResolution.RootResolution, errorTreeItems); + break; + case ErrorTreeItem errorTreeItem: + errorTreeItems.Add(errorTreeItem); + break; + case ConstructorResolution constructorResolution: + foreach (var valueTuple in constructorResolution.Parameter) + Inner(valueTuple.Dependency, errorTreeItems); + break; + case CollectionResolution collectionResolution: + foreach (var resolutionTreeItem in collectionResolution.Parameter) + Inner(resolutionTreeItem, errorTreeItems); + break; + case FuncParameterResolution: + break; + case FuncResolution funcResolution: + foreach (var funcParameterResolution in funcResolution.Parameter) + Inner(funcParameterResolution, errorTreeItems); + Inner(funcResolution.Dependency, errorTreeItems); + break; + case InterfaceResolution interfaceResolution: + Inner(interfaceResolution.Dependency, errorTreeItems); + break; + case Resolvable: + throw new ArgumentOutOfRangeException(nameof(item)); + default: + throw new ArgumentOutOfRangeException(nameof(item)); } } } diff --git a/Main/ResolutionTreeFactory.cs b/Main/ResolutionTreeFactory.cs index 10dc0c16..86f3fb3b 100644 --- a/Main/ResolutionTreeFactory.cs +++ b/Main/ResolutionTreeFactory.cs @@ -1,296 +1,289 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using Microsoft.CodeAnalysis; +namespace MrMeeseeks.DIE; -namespace MrMeeseeks.DIE +internal interface IResolutionTreeFactory { - internal interface IResolutionTreeFactory + ContainerResolution Create(ITypeSymbol root); +} + +internal class ResolutionTreeFactory : IResolutionTreeFactory +{ + private readonly ITypeToImplementationsMapper _typeToImplementationsMapper; + private readonly IReferenceGeneratorFactory _referenceGeneratorFactory; + private readonly ICheckTypeProperties _checkTypeProperties; + private readonly WellKnownTypes _wellKnownTypes; + + private readonly IDictionary _singleInstanceReferenceResolutions = + new Dictionary(SymbolEqualityComparer.Default); + private readonly Queue _singleInstanceResolutionsQueue = new(); + + private readonly IReferenceGenerator _singleInstanceReferenceGenerator; + + public ResolutionTreeFactory( + ITypeToImplementationsMapper typeToImplementationsMapper, + IReferenceGeneratorFactory referenceGeneratorFactory, + ICheckTypeProperties checkTypeProperties, + WellKnownTypes wellKnownTypes) { - ContainerResolution Create(ITypeSymbol root); + _typeToImplementationsMapper = typeToImplementationsMapper; + _referenceGeneratorFactory = referenceGeneratorFactory; + _checkTypeProperties = checkTypeProperties; + _wellKnownTypes = wellKnownTypes; + _singleInstanceReferenceGenerator = referenceGeneratorFactory.Create(); } - internal class ResolutionTreeFactory : IResolutionTreeFactory + public ContainerResolution Create(ITypeSymbol type) { - private readonly ITypeToImplementationsMapper _typeToImplementationsMapper; - private readonly IReferenceGeneratorFactory _referenceGeneratorFactory; - private readonly ICheckTypeProperties _checkTypeProperties; - private readonly WellKnownTypes _wellKnownTypes; + var disposableCollectionResolution = new DisposableCollectionResolution( + _singleInstanceReferenceGenerator.Generate(_wellKnownTypes.ConcurrentBagOfDisposable), + _wellKnownTypes.ConcurrentBagOfDisposable.FullName()); + var referenceGenerator = _referenceGeneratorFactory.Create(); + var rootResolution = Create( + type, + referenceGenerator, + Array.Empty<(ITypeSymbol Type, FuncParameterResolution Resolution)>(), + disposableCollectionResolution); + var singleInstances = new List(); - private readonly IDictionary _singleInstanceReferenceResolutions = - new Dictionary(SymbolEqualityComparer.Default); - private readonly Queue _singleInstanceResolutionsQueue = new(); + while (_singleInstanceResolutionsQueue.Any()) + { + var singleInstanceFunction = _singleInstanceResolutionsQueue.Dequeue(); + var resolvable = CreateConstructorResolution( + singleInstanceFunction.Type, + _referenceGeneratorFactory.Create(), + Array.Empty<(ITypeSymbol Type, FuncParameterResolution Resolution)>(), + disposableCollectionResolution, + true); + singleInstances.Add(new SingleInstance(singleInstanceFunction, resolvable)); + } - private readonly IReferenceGenerator _singleInstanceReferenceGenerator; + return new ContainerResolution( + rootResolution, + new ContainerResolutionDisposalHandling( + disposableCollectionResolution, + _singleInstanceReferenceGenerator.Generate("_disposed"), + _singleInstanceReferenceGenerator.Generate("disposed"), + _singleInstanceReferenceGenerator.Generate("Disposed"), + _singleInstanceReferenceGenerator.Generate("disposable")), + singleInstances); + } - public ResolutionTreeFactory( - ITypeToImplementationsMapper typeToImplementationsMapper, - IReferenceGeneratorFactory referenceGeneratorFactory, - ICheckTypeProperties checkTypeProperties, - WellKnownTypes wellKnownTypes) + private Resolvable Create( + ITypeSymbol type, + IReferenceGenerator referenceGenerator, + IReadOnlyList<(ITypeSymbol Type, FuncParameterResolution Resolution)> currentFuncParameters, + DisposableCollectionResolution disposableCollectionResolution) + { + if (currentFuncParameters.FirstOrDefault(t => SymbolEqualityComparer.Default.Equals(t.Type.OriginalDefinition, type.OriginalDefinition)) is { Type: not null, Resolution: not null } funcParameter) { - _typeToImplementationsMapper = typeToImplementationsMapper; - _referenceGeneratorFactory = referenceGeneratorFactory; - _checkTypeProperties = checkTypeProperties; - _wellKnownTypes = wellKnownTypes; - _singleInstanceReferenceGenerator = referenceGeneratorFactory.Create(); + return funcParameter.Resolution; } - public ContainerResolution Create(ITypeSymbol type) + if (type.OriginalDefinition.Equals(_wellKnownTypes.Lazy1, SymbolEqualityComparer.Default) + && type is INamedTypeSymbol namedTypeSymbol) { - var disposableCollectionResolution = new DisposableCollectionResolution( - _singleInstanceReferenceGenerator.Generate(_wellKnownTypes.ConcurrentBagOfDisposable), - _wellKnownTypes.ConcurrentBagOfDisposable.FullName()); - var referenceGenerator = _referenceGeneratorFactory.Create(); - var rootResolution = Create( - type, - referenceGenerator, - Array.Empty<(ITypeSymbol Type, FuncParameterResolution Resolution)>(), - disposableCollectionResolution); - var singleInstances = new List(); - - while (_singleInstanceResolutionsQueue.Any()) + if (namedTypeSymbol.TypeArguments.SingleOrDefault() is not INamedTypeSymbol genericType) { - var singleInstanceFunction = _singleInstanceResolutionsQueue.Dequeue(); - var resolvable = CreateConstructorResolution( - singleInstanceFunction.Type, - _referenceGeneratorFactory.Create(), - Array.Empty<(ITypeSymbol Type, FuncParameterResolution Resolution)>(), - disposableCollectionResolution, - true); - singleInstances.Add(new SingleInstance(singleInstanceFunction, resolvable)); + return new ErrorTreeItem(namedTypeSymbol.TypeArguments.Length switch + { + 0 => $"[{namedTypeSymbol.FullName()}] Lazy: No type argument", + > 1 => $"[{namedTypeSymbol.FullName()}] Lazy: more than one type argument", + _ => $"[{namedTypeSymbol.FullName()}] Lazy: {namedTypeSymbol.TypeArguments[0].FullName()} is not a named type symbol" + }); } - return new ContainerResolution( - rootResolution, - new ContainerResolutionDisposalHandling( - disposableCollectionResolution, - _singleInstanceReferenceGenerator.Generate("_disposed"), - _singleInstanceReferenceGenerator.Generate("disposed"), - _singleInstanceReferenceGenerator.Generate("Disposed"), - _singleInstanceReferenceGenerator.Generate("disposable")), - singleInstances); + var dependency = Create( + genericType, + _referenceGeneratorFactory.Create(), + Array.Empty<(ITypeSymbol Type, FuncParameterResolution Resolution)>(), + disposableCollectionResolution); + return new ConstructorResolution( + referenceGenerator.Generate(namedTypeSymbol), + namedTypeSymbol.FullName(), + ImplementsIDisposable(namedTypeSymbol, _wellKnownTypes, disposableCollectionResolution, _checkTypeProperties), + new ReadOnlyCollection<(string Name, Resolvable Dependency)>( + new List<(string Name, Resolvable Dependency)> + { + ( + "valueFactory", + new FuncResolution( + referenceGenerator.Generate("func"), + $"global::System.Func<{genericType.FullName()}>", + Array.Empty(), + dependency) + ) + })); } - private Resolvable Create( - ITypeSymbol type, - IReferenceGenerator referenceGenerator, - IReadOnlyList<(ITypeSymbol Type, FuncParameterResolution Resolution)> currentFuncParameters, - DisposableCollectionResolution disposableCollectionResolution) + if (type.OriginalDefinition.Equals(_wellKnownTypes.Enumerable1, SymbolEqualityComparer.Default) + || type.OriginalDefinition.Equals(_wellKnownTypes.ReadOnlyCollection1, SymbolEqualityComparer.Default) + || type.OriginalDefinition.Equals(_wellKnownTypes.ReadOnlyList1, SymbolEqualityComparer.Default)) { - if (currentFuncParameters.FirstOrDefault(t => SymbolEqualityComparer.Default.Equals(t.Type.OriginalDefinition, type.OriginalDefinition)) is { Type: not null, Resolution: not null } funcParameter) - { - return funcParameter.Resolution; - } - - if (type.OriginalDefinition.Equals(_wellKnownTypes.Lazy1, SymbolEqualityComparer.Default) - && type is INamedTypeSymbol namedTypeSymbol) + if (type is not INamedTypeSymbol collectionType) { - if (namedTypeSymbol.TypeArguments.SingleOrDefault() is not INamedTypeSymbol genericType) - { - return new ErrorTreeItem(namedTypeSymbol.TypeArguments.Length switch - { - 0 => $"[{namedTypeSymbol.FullName()}] Lazy: No type argument", - > 1 => $"[{namedTypeSymbol.FullName()}] Lazy: more than one type argument", - _ => $"[{namedTypeSymbol.FullName()}] Lazy: {namedTypeSymbol.TypeArguments[0].FullName()} is not a named type symbol" - }); - } - - var dependency = Create( - genericType, - _referenceGeneratorFactory.Create(), - Array.Empty<(ITypeSymbol Type, FuncParameterResolution Resolution)>(), - disposableCollectionResolution); - return new ConstructorResolution( - referenceGenerator.Generate(namedTypeSymbol), - namedTypeSymbol.FullName(), - ImplementsIDisposable(namedTypeSymbol, _wellKnownTypes, disposableCollectionResolution, _checkTypeProperties), - new ReadOnlyCollection<(string Name, Resolvable Dependency)>( - new List<(string Name, Resolvable Dependency)> - { - ( - "valueFactory", - new FuncResolution( - referenceGenerator.Generate("func"), - $"global::System.Func<{genericType.FullName()}>", - Array.Empty(), - dependency) - ) - })); + return new ErrorTreeItem($"[{type.FullName()}] Collection: Collection is not a named type symbol"); } - - if (type.OriginalDefinition.Equals(_wellKnownTypes.Enumerable1, SymbolEqualityComparer.Default) - || type.OriginalDefinition.Equals(_wellKnownTypes.ReadOnlyCollection1, SymbolEqualityComparer.Default) - || type.OriginalDefinition.Equals(_wellKnownTypes.ReadOnlyList1, SymbolEqualityComparer.Default)) + if (collectionType.TypeArguments.SingleOrDefault() is not INamedTypeSymbol itemType) { - if (type is not INamedTypeSymbol collectionType) - { - return new ErrorTreeItem($"[{type.FullName()}] Collection: Collection is not a named type symbol"); - } - if (collectionType.TypeArguments.SingleOrDefault() is not INamedTypeSymbol itemType) + return new ErrorTreeItem(collectionType.TypeArguments.Length switch { - return new ErrorTreeItem(collectionType.TypeArguments.Length switch - { - 0 => $"[{type.FullName()}] Collection: No item type argument", - > 1 => $"[{type.FullName()}] Collection: More than one item type argument", - _ => $"[{type.FullName()}] Collection: {collectionType.TypeArguments[0].FullName()} is not a named type symbol" - }); - } - var itemFullName = itemType.FullName(); - var items = _typeToImplementationsMapper - .Map(itemType) - .Select(i => Create(i, referenceGenerator, currentFuncParameters, disposableCollectionResolution)) - .ToList(); - return new CollectionResolution( - referenceGenerator.Generate(type), - type.FullName(), - itemFullName, - items); + 0 => $"[{type.FullName()}] Collection: No item type argument", + > 1 => $"[{type.FullName()}] Collection: More than one item type argument", + _ => $"[{type.FullName()}] Collection: {collectionType.TypeArguments[0].FullName()} is not a named type symbol" + }); } + var itemFullName = itemType.FullName(); + var items = _typeToImplementationsMapper + .Map(itemType) + .Select(i => Create(i, referenceGenerator, currentFuncParameters, disposableCollectionResolution)) + .ToList(); + return new CollectionResolution( + referenceGenerator.Generate(type), + type.FullName(), + itemFullName, + items); + } - if (type.TypeKind == TypeKind.Interface) - { - var implementations = _typeToImplementationsMapper - .Map(type); - if (implementations + if (type.TypeKind == TypeKind.Interface) + { + var implementations = _typeToImplementationsMapper + .Map(type); + if (implementations .SingleOrDefault() is not { } implementationType) + { + return new ErrorTreeItem(implementations.Count switch { - return new ErrorTreeItem(implementations.Count switch - { - 0 => $"[{type.FullName()}] Interface: No implementation found", - > 1 => $"[{type.FullName()}] Interface: more than one implementation found", - _ => $"[{type.FullName()}] Interface: Found single implementation {implementations[0].FullName()} is not a named type symbol" - }); - } - return new InterfaceResolution( - referenceGenerator.Generate(type), - type.FullName(), - Create(implementationType, referenceGenerator, currentFuncParameters, disposableCollectionResolution)); + 0 => $"[{type.FullName()}] Interface: No implementation found", + > 1 => $"[{type.FullName()}] Interface: more than one implementation found", + _ => $"[{type.FullName()}] Interface: Found single implementation {implementations[0].FullName()} is not a named type symbol" + }); } + return new InterfaceResolution( + referenceGenerator.Generate(type), + type.FullName(), + Create(implementationType, referenceGenerator, currentFuncParameters, disposableCollectionResolution)); + } - if (type.TypeKind == TypeKind.Class) - return CreateConstructorResolution(type, referenceGenerator, currentFuncParameters, disposableCollectionResolution); - - if (type.TypeKind == TypeKind.Delegate - && type.FullName().StartsWith("global::System.Func<") - && type is INamedTypeSymbol namedTypeSymbol0) - { - var returnType = namedTypeSymbol0.TypeArguments.Last(); - var innerReferenceGenerator = _referenceGeneratorFactory.Create(); - var parameterTypes = namedTypeSymbol0 - .TypeArguments - .Take(namedTypeSymbol0.TypeArguments.Length - 1) - .Select(ts => (Type: ts, Resolution: new FuncParameterResolution(innerReferenceGenerator.Generate(ts), ts.FullName()))) - .ToArray(); + if (type.TypeKind == TypeKind.Class) + return CreateConstructorResolution(type, referenceGenerator, currentFuncParameters, disposableCollectionResolution); - var dependency = Create( - returnType, - innerReferenceGenerator, - parameterTypes, - disposableCollectionResolution); - return new FuncResolution( - referenceGenerator.Generate(type), - type.FullName(), - parameterTypes.Select(t => t.Resolution).ToArray(), - dependency); - } + if (type.TypeKind == TypeKind.Delegate + && type.FullName().StartsWith("global::System.Func<") + && type is INamedTypeSymbol namedTypeSymbol0) + { + var returnType = namedTypeSymbol0.TypeArguments.Last(); + var innerReferenceGenerator = _referenceGeneratorFactory.Create(); + var parameterTypes = namedTypeSymbol0 + .TypeArguments + .Take(namedTypeSymbol0.TypeArguments.Length - 1) + .Select(ts => (Type: ts, Resolution: new FuncParameterResolution(innerReferenceGenerator.Generate(ts), ts.FullName()))) + .ToArray(); - return new ErrorTreeItem($"[{type.FullName()}] Couldn't process in resolution tree creation."); + var dependency = Create( + returnType, + innerReferenceGenerator, + parameterTypes, + disposableCollectionResolution); + return new FuncResolution( + referenceGenerator.Generate(type), + type.FullName(), + parameterTypes.Select(t => t.Resolution).ToArray(), + dependency); } + + return new ErrorTreeItem($"[{type.FullName()}] Couldn't process in resolution tree creation."); + } - private Resolvable CreateConstructorResolution( - ITypeSymbol typeSymbol, - IReferenceGenerator referenceGenerator, - IReadOnlyList<(ITypeSymbol Type, FuncParameterResolution Resolution)> readOnlyList, - DisposableCollectionResolution disposableCollectionResolution, - bool skipSingleInstanceCheck = false) + private Resolvable CreateConstructorResolution( + ITypeSymbol typeSymbol, + IReferenceGenerator referenceGenerator, + IReadOnlyList<(ITypeSymbol Type, FuncParameterResolution Resolution)> readOnlyList, + DisposableCollectionResolution disposableCollectionResolution, + bool skipSingleInstanceCheck = false) + { + var implementations = _typeToImplementationsMapper + .Map(typeSymbol); + if (implementations + .SingleOrDefault() is not { } implementationType) + { + return new ErrorTreeItem(implementations.Count switch { - var implementations = _typeToImplementationsMapper - .Map(typeSymbol); - if (implementations - .SingleOrDefault() is not { } implementationType) - { - return new ErrorTreeItem(implementations.Count switch - { - 0 => $"[{typeSymbol.FullName()}] Class: No implementation found", - > 1 => $"[{typeSymbol.FullName()}] Class: more than one implementation found", - _ => - $"[{typeSymbol.FullName()}] Class: Found single implementation{implementations[0].FullName()} is not a named type symbol" - }); - } + 0 => $"[{typeSymbol.FullName()}] Class: No implementation found", + > 1 => $"[{typeSymbol.FullName()}] Class: more than one implementation found", + _ => + $"[{typeSymbol.FullName()}] Class: Found single implementation{implementations[0].FullName()} is not a named type symbol" + }); + } - if (!skipSingleInstanceCheck && _checkTypeProperties.ShouldBeSingleInstance(implementationType)) - return CreateSingleInstanceReferenceResolution(implementationType, referenceGenerator); + if (!skipSingleInstanceCheck && _checkTypeProperties.ShouldBeSingleInstance(implementationType)) + return CreateSingleInstanceReferenceResolution(implementationType, referenceGenerator); - if (implementationType.Constructors.SingleOrDefault() is not { } constructor) + if (implementationType.Constructors.SingleOrDefault() is not { } constructor) + { + return new ErrorTreeItem(implementations.Count switch + { + 0 => + $"[{typeSymbol.FullName()}] Class.Constructor: No constructor found for implementation {implementationType.FullName()}", + > 1 => + $"[{typeSymbol.FullName()}] Class.Constructor: More than one constructor found for implementation {implementationType.FullName()}", + _ => + $"[{typeSymbol.FullName()}] Class.Constructor: {implementationType.Constructors[0].Name} is not a method symbol" + }); + } + + return new ConstructorResolution( + referenceGenerator.Generate(implementationType), + implementationType.FullName(), + ImplementsIDisposable(implementationType, _wellKnownTypes, disposableCollectionResolution, + _checkTypeProperties), + new ReadOnlyCollection<(string Name, Resolvable Dependency)>(constructor + .Parameters + .Select(p => { - return new ErrorTreeItem(implementations.Count switch + if (p.Type is not INamedTypeSymbol parameterType) { - 0 => - $"[{typeSymbol.FullName()}] Class.Constructor: No constructor found for implementation {implementationType.FullName()}", - > 1 => - $"[{typeSymbol.FullName()}] Class.Constructor: More than one constructor found for implementation {implementationType.FullName()}", - _ => - $"[{typeSymbol.FullName()}] Class.Constructor: {implementationType.Constructors[0].Name} is not a method symbol" - }); - } + return ("", + new ErrorTreeItem( + $"[{typeSymbol.FullName()}] Class.Constructor.Parameter: Parameter type {p.Type.FullName()} is not a named type symbol")); + } - return new ConstructorResolution( - referenceGenerator.Generate(implementationType), - implementationType.FullName(), - ImplementsIDisposable(implementationType, _wellKnownTypes, disposableCollectionResolution, - _checkTypeProperties), - new ReadOnlyCollection<(string Name, Resolvable Dependency)>(constructor - .Parameters - .Select(p => - { - if (p.Type is not INamedTypeSymbol parameterType) - { - return ("", - new ErrorTreeItem( - $"[{typeSymbol.FullName()}] Class.Constructor.Parameter: Parameter type {p.Type.FullName()} is not a named type symbol")); - } - - return ( - p.Name, - Create(parameterType, - referenceGenerator, - readOnlyList, - disposableCollectionResolution)); - }) - .ToList())); - } + return ( + p.Name, + Create(parameterType, + referenceGenerator, + readOnlyList, + disposableCollectionResolution)); + }) + .ToList())); + } - private SingleInstanceReferenceResolution CreateSingleInstanceReferenceResolution( - INamedTypeSymbol implementationType, - IReferenceGenerator referenceGenerator) - { - if (!_singleInstanceReferenceResolutions.TryGetValue( + private SingleInstanceReferenceResolution CreateSingleInstanceReferenceResolution( + INamedTypeSymbol implementationType, + IReferenceGenerator referenceGenerator) + { + if (!_singleInstanceReferenceResolutions.TryGetValue( implementationType, out SingleInstanceFunction function)) - { - function = new SingleInstanceFunction( - _singleInstanceReferenceGenerator.Generate("GetSingleInstance", implementationType), - implementationType.FullName(), - implementationType, - _singleInstanceReferenceGenerator.Generate("_singleInstanceField", implementationType), - _singleInstanceReferenceGenerator.Generate("_singleInstanceLock")); - _singleInstanceReferenceResolutions[implementationType] = function; - _singleInstanceResolutionsQueue.Enqueue(function); - } - return new SingleInstanceReferenceResolution( - referenceGenerator.Generate(implementationType), - function); + { + function = new SingleInstanceFunction( + _singleInstanceReferenceGenerator.Generate("GetSingleInstance", implementationType), + implementationType.FullName(), + implementationType, + _singleInstanceReferenceGenerator.Generate("_singleInstanceField", implementationType), + _singleInstanceReferenceGenerator.Generate("_singleInstanceLock")); + _singleInstanceReferenceResolutions[implementationType] = function; + _singleInstanceResolutionsQueue.Enqueue(function); } - - private static DisposableCollectionResolution? ImplementsIDisposable( - INamedTypeSymbol type, - WellKnownTypes wellKnownTypes, - DisposableCollectionResolution disposableCollectionResolution, - ICheckTypeProperties checkDisposalManagement) => - type.AllInterfaces.Contains(wellKnownTypes.Disposable) && checkDisposalManagement.ShouldBeManaged(type) - ? disposableCollectionResolution - : null; + return new SingleInstanceReferenceResolution( + referenceGenerator.Generate(implementationType), + function); } + + private static DisposableCollectionResolution? ImplementsIDisposable( + INamedTypeSymbol type, + WellKnownTypes wellKnownTypes, + DisposableCollectionResolution disposableCollectionResolution, + ICheckTypeProperties checkDisposalManagement) => + type.AllInterfaces.Contains(wellKnownTypes.Disposable) && checkDisposalManagement.ShouldBeManaged(type) + ? disposableCollectionResolution + : null; } \ No newline at end of file diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index 55ae023d..6d333376 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -1,73 +1,68 @@ -using System; -using System.Collections.Generic; -using Microsoft.CodeAnalysis; +namespace MrMeeseeks.DIE; -namespace MrMeeseeks.DIE -{ - internal abstract record ResolutionTreeItem; +internal abstract record ResolutionTreeItem; - internal abstract record Resolvable( - string Reference, - string TypeFullName) : ResolutionTreeItem; +internal abstract record Resolvable( + string Reference, + string TypeFullName) : ResolutionTreeItem; - internal record ErrorTreeItem( - string Message) : Resolvable("error_99_99", "Error"); +internal record ErrorTreeItem( + string Message) : Resolvable("error_99_99", "Error"); - internal record InterfaceResolution( - string Reference, - string TypeFullName, - ResolutionTreeItem Dependency) : Resolvable(Reference, TypeFullName); +internal record InterfaceResolution( + string Reference, + string TypeFullName, + ResolutionTreeItem Dependency) : Resolvable(Reference, TypeFullName); - internal record ConstructorResolution( - string Reference, - string TypeFullName, - DisposableCollectionResolution? DisposableCollectionResolution, - IReadOnlyList<(string name, Resolvable Dependency)> Parameter) : Resolvable(Reference, TypeFullName); +internal record ConstructorResolution( + string Reference, + string TypeFullName, + DisposableCollectionResolution? DisposableCollectionResolution, + IReadOnlyList<(string name, Resolvable Dependency)> Parameter) : Resolvable(Reference, TypeFullName); - internal record SingleInstance( - SingleInstanceFunction Function, - Resolvable Dependency); +internal record SingleInstance( + SingleInstanceFunction Function, + Resolvable Dependency); - internal record FuncParameterResolution( - string Reference, - string TypeFullName) : Resolvable(Reference, TypeFullName); +internal record FuncParameterResolution( + string Reference, + string TypeFullName) : Resolvable(Reference, TypeFullName); - internal record SingleInstanceFunction( - string Reference, - string TypeFullName, - INamedTypeSymbol Type, - string FieldReference, - string LockReference); +internal record SingleInstanceFunction( + string Reference, + string TypeFullName, + INamedTypeSymbol Type, + string FieldReference, + string LockReference); - internal record SingleInstanceReferenceResolution( - string Reference, - SingleInstanceFunction Function) : Resolvable(Reference, Function.TypeFullName); +internal record SingleInstanceReferenceResolution( + string Reference, + SingleInstanceFunction Function) : Resolvable(Reference, Function.TypeFullName); - internal record FuncResolution( - string Reference, - string TypeFullName, - IReadOnlyList Parameter, - ResolutionTreeItem Dependency) : Resolvable(Reference, TypeFullName); +internal record FuncResolution( + string Reference, + string TypeFullName, + IReadOnlyList Parameter, + ResolutionTreeItem Dependency) : Resolvable(Reference, TypeFullName); - internal record CollectionResolution( - string Reference, - string TypeFullName, - string ItemFullName, - IReadOnlyList Parameter) : Resolvable(Reference, TypeFullName); +internal record CollectionResolution( + string Reference, + string TypeFullName, + string ItemFullName, + IReadOnlyList Parameter) : Resolvable(Reference, TypeFullName); - internal record DisposableCollectionResolution( - string Reference, - string TypeFullName) : ConstructorResolution(Reference, TypeFullName, null, Array.Empty<(string name, Resolvable Dependency)>()); +internal record DisposableCollectionResolution( + string Reference, + string TypeFullName) : ConstructorResolution(Reference, TypeFullName, null, Array.Empty<(string name, Resolvable Dependency)>()); - internal record ContainerResolution( - Resolvable RootResolution, - ContainerResolutionDisposalHandling DisposalHandling, - IReadOnlyList SingleInstanceResolutions) : Resolvable(RootResolution.Reference, RootResolution.TypeFullName); +internal record ContainerResolution( + Resolvable RootResolution, + ContainerResolutionDisposalHandling DisposalHandling, + IReadOnlyList SingleInstanceResolutions) : Resolvable(RootResolution.Reference, RootResolution.TypeFullName); - internal record ContainerResolutionDisposalHandling( - DisposableCollectionResolution DisposableCollection, - string DisposedFieldReference, - string DisposedLocalReference, - string DisposedPropertyReference, - string DisposableLocalReference); -} +internal record ContainerResolutionDisposalHandling( + DisposableCollectionResolution DisposableCollection, + string DisposedFieldReference, + string DisposedLocalReference, + string DisposedPropertyReference, + string DisposableLocalReference); \ No newline at end of file diff --git a/Main/RoslynExtensions.cs b/Main/RoslynExtensions.cs index f1fb0ba6..e91dc81d 100644 --- a/Main/RoslynExtensions.cs +++ b/Main/RoslynExtensions.cs @@ -1,59 +1,54 @@ -using System; -using System.Linq; -using Microsoft.CodeAnalysis; +namespace MrMeeseeks.DIE; -namespace MrMeeseeks.DIE +internal static class RoslynExtensions { - internal static class RoslynExtensions + public static INamedTypeSymbol? GetTypeOrReport(this Compilation compilation, string metadataName) { - public static INamedTypeSymbol? GetTypeOrReport(this Compilation compilation, string metadataName) - { - var typeSymbol = compilation.GetTypeByMetadataName(metadataName); - return typeSymbol; - } - // Picked from https://github.com/YairHalberstadt/stronginject Thank you! - public static bool IsOrReferencesErrorType(this ITypeSymbol type) + var typeSymbol = compilation.GetTypeByMetadataName(metadataName); + return typeSymbol; + } + // Picked from https://github.com/YairHalberstadt/stronginject Thank you! + public static bool IsOrReferencesErrorType(this ITypeSymbol type) + { + if (!type.ContainingType?.IsOrReferencesErrorType() ?? false) + return false; + return type switch { - if (!type.ContainingType?.IsOrReferencesErrorType() ?? false) - return false; - return type switch - { - IErrorTypeSymbol => true, - IArrayTypeSymbol array => array.ElementType.IsOrReferencesErrorType(), - IPointerTypeSymbol pointer => pointer.PointedAtType.IsOrReferencesErrorType(), - INamedTypeSymbol named => !named.IsUnboundGenericType && named.TypeArguments.Any(IsOrReferencesErrorType), - _ => false, - }; - } + IErrorTypeSymbol => true, + IArrayTypeSymbol array => array.ElementType.IsOrReferencesErrorType(), + IPointerTypeSymbol pointer => pointer.PointedAtType.IsOrReferencesErrorType(), + INamedTypeSymbol named => !named.IsUnboundGenericType && named.TypeArguments.Any(IsOrReferencesErrorType), + _ => false, + }; + } - // Picked from https://github.com/YairHalberstadt/stronginject Thank you! - public static bool IsAccessibleInternally(this ITypeSymbol type) + // Picked from https://github.com/YairHalberstadt/stronginject Thank you! + public static bool IsAccessibleInternally(this ITypeSymbol type) + { + if (type is ITypeParameterSymbol) + return true; + if (!type.ContainingType?.IsAccessibleInternally() ?? false) + return false; + return type switch { - if (type is ITypeParameterSymbol) - return true; - if (!type.ContainingType?.IsAccessibleInternally() ?? false) - return false; - return type switch - { - IArrayTypeSymbol array => array.ElementType.IsAccessibleInternally(), - IPointerTypeSymbol pointer => pointer.PointedAtType.IsAccessibleInternally(), - INamedTypeSymbol named => named.DeclaredAccessibility is Accessibility.Public or Accessibility.ProtectedOrInternal or Accessibility.Internal - && named.TypeArguments.All(IsAccessibleInternally), - _ => false, - }; - } + IArrayTypeSymbol array => array.ElementType.IsAccessibleInternally(), + IPointerTypeSymbol pointer => pointer.PointedAtType.IsAccessibleInternally(), + INamedTypeSymbol named => named.DeclaredAccessibility is Accessibility.Public or Accessibility.ProtectedOrInternal or Accessibility.Internal + && named.TypeArguments.All(IsAccessibleInternally), + _ => false, + }; + } - // Picked from https://github.com/YairHalberstadt/stronginject Thank you! - public static string FullName(this ITypeSymbol type) => - type.ToDisplayString(new SymbolDisplayFormat( - globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Included, - typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces, - genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters, - parameterOptions: SymbolDisplayParameterOptions.IncludeType | SymbolDisplayParameterOptions.IncludeParamsRefOut, - memberOptions: SymbolDisplayMemberOptions.IncludeRef)); + // Picked from https://github.com/YairHalberstadt/stronginject Thank you! + public static string FullName(this ITypeSymbol type) => + type.ToDisplayString(new SymbolDisplayFormat( + globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Included, + typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces, + genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters, + parameterOptions: SymbolDisplayParameterOptions.IncludeType | SymbolDisplayParameterOptions.IncludeParamsRefOut, + memberOptions: SymbolDisplayMemberOptions.IncludeRef)); - // Picked from https://github.com/YairHalberstadt/stronginject Thank you! - public static string FullName(this INamespaceSymbol @namespace) => - @namespace.ToDisplayString(new SymbolDisplayFormat(typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces)); - } + // Picked from https://github.com/YairHalberstadt/stronginject Thank you! + public static string FullName(this INamespaceSymbol @namespace) => + @namespace.ToDisplayString(new SymbolDisplayFormat(typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces)); } \ No newline at end of file diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index 3cfa6ad6..d4e79789 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -1,43 +1,40 @@ -using Microsoft.CodeAnalysis; +namespace MrMeeseeks.DIE; -namespace MrMeeseeks.DIE +[Generator] +public class SourceGenerator : ISourceGenerator { - [Generator] - public class SourceGenerator : ISourceGenerator + public void Initialize(GeneratorInitializationContext context) { - public void Initialize(GeneratorInitializationContext context) - { - new InitializeImpl(context, SyntaxReceiverFactory).Initialize(); + new InitializeImpl(context, SyntaxReceiverFactory).Initialize(); - ISyntaxReceiver SyntaxReceiverFactory() => new SyntaxReceiver(); - } + ISyntaxReceiver SyntaxReceiverFactory() => new SyntaxReceiver(); + } - public void Execute(GeneratorExecutionContext context) - { - var diagLogger = new DiagLogger(context); - var _ = WellKnownTypes.TryCreate(context.Compilation, out var wellKnownTypes); - var getAssemblyAttributes = new GetAssemblyAttributes(context); - var typesFromAttributes = new TypesFromAttributes(wellKnownTypes, getAssemblyAttributes); - var getAllImplementations = new GetAllImplementations(context, typesFromAttributes); - var typeToImplementationMapper = new TypeToImplementationsMapper(getAllImplementations); - var containerGenerator = new ContainerGenerator(context, wellKnownTypes, diagLogger); - var referenceGeneratorFactory = new ReferenceGeneratorFactory(ReferenceGeneratorFactory); - var checkDisposalManagement = new CheckTypeProperties(getAllImplementations, typesFromAttributes); - var resolutionTreeFactory = new ResolutionTreeFactory(typeToImplementationMapper, referenceGeneratorFactory, checkDisposalManagement, wellKnownTypes); - var containerErrorGenerator = new ContainerErrorGenerator(context); - var resolutionTreeCreationErrorHarvester = new ResolutionTreeCreationErrorHarvester(); - new ExecuteImpl( - context, - wellKnownTypes, - containerGenerator, - containerErrorGenerator, - resolutionTreeFactory, - resolutionTreeCreationErrorHarvester, - ContainerInfoFactory, - diagLogger).Execute(); + public void Execute(GeneratorExecutionContext context) + { + var diagLogger = new DiagLogger(context); + var _ = WellKnownTypes.TryCreate(context.Compilation, out var wellKnownTypes); + var getAssemblyAttributes = new GetAssemblyAttributes(context); + var typesFromAttributes = new TypesFromAttributes(wellKnownTypes, getAssemblyAttributes); + var getAllImplementations = new GetAllImplementations(context, typesFromAttributes); + var typeToImplementationMapper = new TypeToImplementationsMapper(getAllImplementations); + var containerGenerator = new ContainerGenerator(context, wellKnownTypes, diagLogger); + var referenceGeneratorFactory = new ReferenceGeneratorFactory(ReferenceGeneratorFactory); + var checkDisposalManagement = new CheckTypeProperties(getAllImplementations, typesFromAttributes); + var resolutionTreeFactory = new ResolutionTreeFactory(typeToImplementationMapper, referenceGeneratorFactory, checkDisposalManagement, wellKnownTypes); + var containerErrorGenerator = new ContainerErrorGenerator(context); + var resolutionTreeCreationErrorHarvester = new ResolutionTreeCreationErrorHarvester(); + new ExecuteImpl( + context, + wellKnownTypes, + containerGenerator, + containerErrorGenerator, + resolutionTreeFactory, + resolutionTreeCreationErrorHarvester, + ContainerInfoFactory, + diagLogger).Execute(); - IContainerInfo ContainerInfoFactory(INamedTypeSymbol type) => new ContainerInfo(type, wellKnownTypes); - IReferenceGenerator ReferenceGeneratorFactory(int j) => new ReferenceGenerator(j); - } + IContainerInfo ContainerInfoFactory(INamedTypeSymbol type) => new ContainerInfo(type, wellKnownTypes); + IReferenceGenerator ReferenceGeneratorFactory(int j) => new ReferenceGenerator(j); } -} +} \ No newline at end of file diff --git a/Main/SyntaxReceiver.cs b/Main/SyntaxReceiver.cs index 4eee265e..f9f6c53e 100644 --- a/Main/SyntaxReceiver.cs +++ b/Main/SyntaxReceiver.cs @@ -1,19 +1,16 @@ -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using System.Collections.Generic; +using Microsoft.CodeAnalysis.CSharp.Syntax; -namespace MrMeeseeks.DIE +namespace MrMeeseeks.DIE; + +internal class SyntaxReceiver : ISyntaxReceiver { - internal class SyntaxReceiver : ISyntaxReceiver - { - public List Candidates { get; } = new(); + public List Candidates { get; } = new(); - public void OnVisitSyntaxNode(SyntaxNode syntaxNode) + public void OnVisitSyntaxNode(SyntaxNode syntaxNode) + { + if (syntaxNode is ClassDeclarationSyntax classDeclarationSyntax) { - if (syntaxNode is ClassDeclarationSyntax classDeclarationSyntax) - { - Candidates.Add(classDeclarationSyntax); - } + Candidates.Add(classDeclarationSyntax); } } -} +} \ No newline at end of file diff --git a/Main/TypeToImplementationMapper.cs b/Main/TypeToImplementationMapper.cs index 1f7ea865..2586aaa5 100644 --- a/Main/TypeToImplementationMapper.cs +++ b/Main/TypeToImplementationMapper.cs @@ -1,29 +1,24 @@ -using Microsoft.CodeAnalysis; -using System.Collections.Generic; -using System.Linq; +namespace MrMeeseeks.DIE; -namespace MrMeeseeks.DIE +internal interface ITypeToImplementationsMapper { - internal interface ITypeToImplementationsMapper - { - IList Map(ITypeSymbol typeSymbol); - } + IList Map(ITypeSymbol typeSymbol); +} - internal class TypeToImplementationsMapper : ITypeToImplementationsMapper - { - private readonly Dictionary> _map; +internal class TypeToImplementationsMapper : ITypeToImplementationsMapper +{ + private readonly Dictionary> _map; - public TypeToImplementationsMapper( - IGetAllImplementations getAllImplementations) => - _map = getAllImplementations - .AllImplementations - .SelectMany(i => { return i.AllInterfaces.OfType().Select(ii => (ii, i)).Prepend((i, i)); }) - .GroupBy(t => t.Item1, t => t.Item2) - .ToDictionary(g => g.Key, g => g.Distinct().ToList()); + public TypeToImplementationsMapper( + IGetAllImplementations getAllImplementations) => + _map = getAllImplementations + .AllImplementations + .SelectMany(i => { return i.AllInterfaces.OfType().Select(ii => (ii, i)).Prepend((i, i)); }) + .GroupBy(t => t.Item1, t => t.Item2) + .ToDictionary(g => g.Key, g => g.Distinct().ToList()); - public IList Map(ITypeSymbol typeSymbol) => - _map.TryGetValue(typeSymbol, out var implementations) - ? implementations - : new List(); - } -} + public IList Map(ITypeSymbol typeSymbol) => + _map.TryGetValue(typeSymbol, out var implementations) + ? implementations + : new List(); +} \ No newline at end of file diff --git a/Main/TypesFromAttributes.cs b/Main/TypesFromAttributes.cs index a84c849d..2079a8da 100644 --- a/Main/TypesFromAttributes.cs +++ b/Main/TypesFromAttributes.cs @@ -1,63 +1,57 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Microsoft.CodeAnalysis; +namespace MrMeeseeks.DIE; -namespace MrMeeseeks.DIE +public interface ITypesFromAttributes { - public interface ITypesFromAttributes - { - IReadOnlyList Spy { get; } - IReadOnlyList Transient { get; } - IReadOnlyList SingleInstance { get; } - } + IReadOnlyList Spy { get; } + IReadOnlyList Transient { get; } + IReadOnlyList SingleInstance { get; } +} - internal class TypesFromAttributes : ITypesFromAttributes +internal class TypesFromAttributes : ITypesFromAttributes +{ + public TypesFromAttributes( + WellKnownTypes wellKnownTypes, + IGetAssemblyAttributes getAssemblyAttributes) { - public TypesFromAttributes( - WellKnownTypes wellKnownTypes, - IGetAssemblyAttributes getAssemblyAttributes) - { - Spy = GetTypesFromAttribute(wellKnownTypes.SpyAttribute).ToList(); - Transient = GetTypesFromAttribute(wellKnownTypes.TransientAttribute).ToList(); - SingleInstance = GetTypesFromAttribute(wellKnownTypes.SingleInstanceAttribute).ToList(); + Spy = GetTypesFromAttribute(wellKnownTypes.SpyAttribute).ToList(); + Transient = GetTypesFromAttribute(wellKnownTypes.TransientAttribute).ToList(); + SingleInstance = GetTypesFromAttribute(wellKnownTypes.SingleInstanceAttribute).ToList(); - IEnumerable GetTypesFromAttribute(INamedTypeSymbol attribute) => getAssemblyAttributes - .AllAssemblyAttributes - .Where(ad => - ad.AttributeClass?.Equals(attribute, SymbolEqualityComparer.Default) ?? false) - .SelectMany(ad => ad.ConstructorArguments - .Where(tc => tc.Kind == TypedConstantKind.Type) - .OfType() - .Concat(ad.ConstructorArguments.SelectMany(ca => ca.Kind is TypedConstantKind.Array - ? (IEnumerable)ca.Values - : Array.Empty()))) - .Select(tc => + IEnumerable GetTypesFromAttribute(INamedTypeSymbol attribute) => getAssemblyAttributes + .AllAssemblyAttributes + .Where(ad => + ad.AttributeClass?.Equals(attribute, SymbolEqualityComparer.Default) ?? false) + .SelectMany(ad => ad.ConstructorArguments + .Where(tc => tc.Kind == TypedConstantKind.Type) + .OfType() + .Concat(ad.ConstructorArguments.SelectMany(ca => ca.Kind is TypedConstantKind.Array + ? (IEnumerable)ca.Values + : Array.Empty()))) + .Select(tc => + { + if (!CheckValidType(tc, out var type)) { - if (!CheckValidType(tc, out var type)) - { - return null; - } + return null; + } - return type; - }) - .Where(t => t is not null) - .OfType(); + return type; + }) + .Where(t => t is not null) + .OfType(); - bool CheckValidType(TypedConstant typedConstant, out INamedTypeSymbol type) - { - type = (typedConstant.Value as INamedTypeSymbol)!; - if (typedConstant.Value is null) - return false; - if (type.IsUnboundGenericType) - return false; + bool CheckValidType(TypedConstant typedConstant, out INamedTypeSymbol type) + { + type = (typedConstant.Value as INamedTypeSymbol)!; + if (typedConstant.Value is null) + return false; + if (type.IsUnboundGenericType) + return false; - return true; - } + return true; } - - public IReadOnlyList Spy { get; } - public IReadOnlyList Transient { get; } - public IReadOnlyList SingleInstance { get; } } + + public IReadOnlyList Spy { get; } + public IReadOnlyList Transient { get; } + public IReadOnlyList SingleInstance { get; } } \ No newline at end of file diff --git a/Main/WellKnownTypes.cs b/Main/WellKnownTypes.cs index ef4234c9..8f172d9c 100644 --- a/Main/WellKnownTypes.cs +++ b/Main/WellKnownTypes.cs @@ -1,105 +1,102 @@ -using Microsoft.CodeAnalysis; +namespace MrMeeseeks.DIE; -namespace MrMeeseeks.DIE +internal record WellKnownTypes( + INamedTypeSymbol Container, + INamedTypeSymbol SpyAttribute, + INamedTypeSymbol TransientAttribute, + INamedTypeSymbol SingleInstanceAttribute, + INamedTypeSymbol Disposable, + INamedTypeSymbol AsyncDisposable, + INamedTypeSymbol Lazy1, + INamedTypeSymbol ValueTask, + INamedTypeSymbol ValueTask1, + INamedTypeSymbol Task1, + INamedTypeSymbol ObjectDisposedException, + INamedTypeSymbol Enumerable1, + INamedTypeSymbol ReadOnlyCollection1, + INamedTypeSymbol ReadOnlyList1, + INamedTypeSymbol ConcurrentBagOfDisposable, + INamedTypeSymbol Action, + INamedTypeSymbol Func, + INamedTypeSymbol Exception, + INamedTypeSymbol SemaphoreSlim) { - internal record WellKnownTypes( - INamedTypeSymbol Container, - INamedTypeSymbol SpyAttribute, - INamedTypeSymbol TransientAttribute, - INamedTypeSymbol SingleInstanceAttribute, - INamedTypeSymbol Disposable, - INamedTypeSymbol AsyncDisposable, - INamedTypeSymbol Lazy1, - INamedTypeSymbol ValueTask, - INamedTypeSymbol ValueTask1, - INamedTypeSymbol Task1, - INamedTypeSymbol ObjectDisposedException, - INamedTypeSymbol Enumerable1, - INamedTypeSymbol ReadOnlyCollection1, - INamedTypeSymbol ReadOnlyList1, - INamedTypeSymbol ConcurrentBagOfDisposable, - INamedTypeSymbol Action, - INamedTypeSymbol Func, - INamedTypeSymbol Exception, - INamedTypeSymbol SemaphoreSlim) + public static bool TryCreate(Compilation compilation, out WellKnownTypes wellKnownTypes) { - public static bool TryCreate(Compilation compilation, out WellKnownTypes wellKnownTypes) - { - var iContainer = compilation.GetTypeOrReport("MrMeeseeks.DIE.IContainer`1"); - var iDisposable = compilation.GetTypeOrReport("System.IDisposable"); - var iAsyncDisposable = compilation.GetTypeOrReport("System.IAsyncDisposable"); - var lazy1 = compilation.GetTypeOrReport("System.Lazy`1"); - var valueTask = compilation.GetTypeOrReport("System.Threading.Tasks.ValueTask"); - var valueTask1 = compilation.GetTypeOrReport("System.Threading.Tasks.ValueTask`1"); - var task1 = compilation.GetTypeOrReport("System.Threading.Tasks.Task`1"); - var objectDisposedException = compilation.GetTypeOrReport("System.ObjectDisposedException"); - var iEnumerable1 = compilation.GetTypeOrReport("System.Collections.Generic.IEnumerable`1"); - var iReadOnlyCollection1 = compilation.GetTypeOrReport("System.Collections.Generic.IReadOnlyCollection`1"); - var iReadOnlyList1 = compilation.GetTypeOrReport("System.Collections.Generic.IReadOnlyList`1"); - var concurrentBag = compilation.GetTypeOrReport("System.Collections.Concurrent.ConcurrentBag`1"); - var concurrentBagOfDisposable = iDisposable is null - ? null - : concurrentBag?.Construct(iDisposable); - var action = compilation.GetTypeOrReport("System.Action"); - var func = compilation.GetTypeOrReport("System.Func`3"); - var exception = compilation.GetTypeOrReport("System.Exception"); - var semaphoreSlim = compilation.GetTypeOrReport("System.Threading.SemaphoreSlim"); + var iContainer = compilation.GetTypeOrReport("MrMeeseeks.DIE.IContainer`1"); + var iDisposable = compilation.GetTypeOrReport("System.IDisposable"); + var iAsyncDisposable = compilation.GetTypeOrReport("System.IAsyncDisposable"); + var lazy1 = compilation.GetTypeOrReport("System.Lazy`1"); + var valueTask = compilation.GetTypeOrReport("System.Threading.Tasks.ValueTask"); + var valueTask1 = compilation.GetTypeOrReport("System.Threading.Tasks.ValueTask`1"); + var task1 = compilation.GetTypeOrReport("System.Threading.Tasks.Task`1"); + var objectDisposedException = compilation.GetTypeOrReport("System.ObjectDisposedException"); + var iEnumerable1 = compilation.GetTypeOrReport("System.Collections.Generic.IEnumerable`1"); + var iReadOnlyCollection1 = compilation.GetTypeOrReport("System.Collections.Generic.IReadOnlyCollection`1"); + var iReadOnlyList1 = compilation.GetTypeOrReport("System.Collections.Generic.IReadOnlyList`1"); + var concurrentBag = compilation.GetTypeOrReport("System.Collections.Concurrent.ConcurrentBag`1"); + var concurrentBagOfDisposable = iDisposable is null + ? null + : concurrentBag?.Construct(iDisposable); + var action = compilation.GetTypeOrReport("System.Action"); + var func = compilation.GetTypeOrReport("System.Func`3"); + var exception = compilation.GetTypeOrReport("System.Exception"); + var semaphoreSlim = compilation.GetTypeOrReport("System.Threading.SemaphoreSlim"); - var spyAttribute = compilation - .GetTypeByMetadataName(typeof(SpyAttribute).FullName ?? ""); + var spyAttribute = compilation + .GetTypeByMetadataName(typeof(SpyAttribute).FullName ?? ""); - var transientAttribute = compilation - .GetTypeByMetadataName(typeof(TransientAttribute).FullName ?? ""); + var transientAttribute = compilation + .GetTypeByMetadataName(typeof(TransientAttribute).FullName ?? ""); - var singleInstanceAttribute = compilation - .GetTypeByMetadataName(typeof(SingleInstanceAttribute).FullName ?? ""); + var singleInstanceAttribute = compilation + .GetTypeByMetadataName(typeof(SingleInstanceAttribute).FullName ?? ""); - if (iContainer is null - || spyAttribute is null - || transientAttribute is null - || singleInstanceAttribute is null - || iDisposable is null - || iAsyncDisposable is null - || lazy1 is null - || valueTask is null - || valueTask1 is null - || task1 is null - || objectDisposedException is null - || iEnumerable1 is null - || iReadOnlyCollection1 is null - || iReadOnlyList1 is null - || concurrentBagOfDisposable is null - || action is null - || func is null - || exception is null - || semaphoreSlim is null) - { - wellKnownTypes = null!; - return false; - } + if (iContainer is null + || spyAttribute is null + || transientAttribute is null + || singleInstanceAttribute is null + || iDisposable is null + || iAsyncDisposable is null + || lazy1 is null + || valueTask is null + || valueTask1 is null + || task1 is null + || objectDisposedException is null + || iEnumerable1 is null + || iReadOnlyCollection1 is null + || iReadOnlyList1 is null + || concurrentBagOfDisposable is null + || action is null + || func is null + || exception is null + || semaphoreSlim is null) + { + wellKnownTypes = null!; + return false; + } - wellKnownTypes = new WellKnownTypes( - Container: iContainer, - SpyAttribute: spyAttribute, - TransientAttribute: transientAttribute, - SingleInstanceAttribute: singleInstanceAttribute, - Disposable: iDisposable, - AsyncDisposable: iAsyncDisposable, - Lazy1: lazy1, - ValueTask: valueTask, - ValueTask1: valueTask1, - Task1: task1, - ObjectDisposedException: objectDisposedException, - Enumerable1: iEnumerable1, - ReadOnlyCollection1: iReadOnlyCollection1, - ReadOnlyList1: iReadOnlyList1, - ConcurrentBagOfDisposable: concurrentBagOfDisposable, - Action: action, - Func: func, - Exception: exception, - SemaphoreSlim: semaphoreSlim); + wellKnownTypes = new WellKnownTypes( + Container: iContainer, + SpyAttribute: spyAttribute, + TransientAttribute: transientAttribute, + SingleInstanceAttribute: singleInstanceAttribute, + Disposable: iDisposable, + AsyncDisposable: iAsyncDisposable, + Lazy1: lazy1, + ValueTask: valueTask, + ValueTask1: valueTask1, + Task1: task1, + ObjectDisposedException: objectDisposedException, + Enumerable1: iEnumerable1, + ReadOnlyCollection1: iReadOnlyCollection1, + ReadOnlyList1: iReadOnlyList1, + ConcurrentBagOfDisposable: concurrentBagOfDisposable, + Action: action, + Func: func, + Exception: exception, + SemaphoreSlim: semaphoreSlim); - return true; - } + return true; } } \ No newline at end of file diff --git a/Sample/Container.cs b/Sample/Container.cs index ac144ef3..36402598 100644 --- a/Sample/Container.cs +++ b/Sample/Container.cs @@ -6,9 +6,8 @@ [assembly:SingleInstance(typeof(ISingleInstance))] [assembly:Transient(typeof(ITransient))] -namespace MrMeeseeks.DIE.Sample +namespace MrMeeseeks.DIE.Sample; + +internal partial class Container : IContainer { - internal partial class Container : IContainer - { - } -} +} \ No newline at end of file diff --git a/Sample/Context.cs b/Sample/Context.cs index 6b1a2eb8..4a7a48f3 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -2,23 +2,22 @@ using System.Collections.Generic; using MrMeeseeks.DIE.SampleChild; -namespace MrMeeseeks.DIE.Sample +namespace MrMeeseeks.DIE.Sample; + +internal interface IContext { - internal interface IContext - { - string Text { get; } - } + string Text { get; } +} - internal class Context : IContext, IDisposable, ISingleInstance +internal class Context : IContext, IDisposable, ISingleInstance +{ + public string Text => "Hello, world!"; + public Context(IReadOnlyList child) { - public string Text => "Hello, world!"; - public Context(IReadOnlyList child) - { - } + } - public void Dispose() - { - } + public void Dispose() + { } -} +} \ No newline at end of file diff --git a/Sample/StrongInjectContainer.cs b/Sample/StrongInjectContainer.cs index 9986e014..181f3533 100644 --- a/Sample/StrongInjectContainer.cs +++ b/Sample/StrongInjectContainer.cs @@ -2,15 +2,14 @@ using StrongInject; using StrongInject.Modules; -namespace MrMeeseeks.DIE.Sample +namespace MrMeeseeks.DIE.Sample; + +[Register(typeof(Context), Scope.SingleInstance, typeof(Context), typeof(IContext))] +[Register(typeof(Child), Scope.SingleInstance, typeof(Child), typeof(IChild))] +[Register(typeof(InternalChild), typeof(IInternalChild))] +[Register(typeof(YetAnotherInternalChild), typeof(IYetAnotherInternalChild))] +[RegisterModule(typeof(StandardModule))] +internal partial class StrongInjectContainer : StrongInject.IContainer { - [Register(typeof(Context), Scope.SingleInstance, typeof(Context), typeof(IContext))] - [Register(typeof(Child), Scope.SingleInstance, typeof(Child), typeof(IChild))] - [Register(typeof(InternalChild), typeof(IInternalChild))] - [Register(typeof(YetAnotherInternalChild), typeof(IYetAnotherInternalChild))] - [RegisterModule(typeof(StandardModule))] - internal partial class StrongInjectContainer : StrongInject.IContainer - { - } } \ No newline at end of file diff --git a/SampleChild/Child.cs b/SampleChild/Child.cs index 080b74df..6abc42f4 100644 --- a/SampleChild/Child.cs +++ b/SampleChild/Child.cs @@ -1,17 +1,16 @@ using System; -namespace MrMeeseeks.DIE.SampleChild +namespace MrMeeseeks.DIE.SampleChild; + +public interface IChild +{ } + +public class Child : IChild, IDisposable, ISingleInstance { - public interface IChild - { } + public Child( + IInternalChild innerChild){} - public class Child : IChild, IDisposable, ISingleInstance + public void Dispose() { - public Child( - IInternalChild innerChild){} - - public void Dispose() - { - } } -} +} \ No newline at end of file diff --git a/SampleChild/InternalChild.cs b/SampleChild/InternalChild.cs index f1ed9700..e429f68b 100644 --- a/SampleChild/InternalChild.cs +++ b/SampleChild/InternalChild.cs @@ -1,27 +1,26 @@ using System; -namespace MrMeeseeks.DIE.SampleChild +namespace MrMeeseeks.DIE.SampleChild; + +public interface IInternalChild +{} +internal class InternalChild : IInternalChild, IDisposable { - public interface IInternalChild - {} - internal class InternalChild : IInternalChild, IDisposable + public InternalChild(Lazy yetAnotherInternalChild) { - public InternalChild(Lazy yetAnotherInternalChild) - { - } + } - public void Dispose() - { - } + public void Dispose() + { } +} - public interface IYetAnotherInternalChild - {} - internal class YetAnotherInternalChild : IYetAnotherInternalChild, IDisposable +public interface IYetAnotherInternalChild +{} +internal class YetAnotherInternalChild : IYetAnotherInternalChild, IDisposable +{ + public void Dispose() { - public void Dispose() - { - } } } \ No newline at end of file diff --git a/SampleChild/MarkerInterfaces.cs b/SampleChild/MarkerInterfaces.cs index 33d5c0ff..ed59627b 100644 --- a/SampleChild/MarkerInterfaces.cs +++ b/SampleChild/MarkerInterfaces.cs @@ -1,5 +1,4 @@ -namespace MrMeeseeks.DIE.SampleChild -{ - public interface ISingleInstance { } - public interface ITransient { } -} \ No newline at end of file +namespace MrMeeseeks.DIE.SampleChild; + +public interface ISingleInstance { } +public interface ITransient { } \ No newline at end of file diff --git a/Spy/AssemblyInfo.cs b/Spy/AssemblyInfo.cs new file mode 100644 index 00000000..71805a26 --- /dev/null +++ b/Spy/AssemblyInfo.cs @@ -0,0 +1,12 @@ +global using Microsoft.CodeAnalysis; +global using System.Collections.Generic; +global using System.Collections.ObjectModel; +global using System.Linq; +global using System.Text; + +namespace MrMeeseeks.DIE.Spy; + +public class AssemblyInfo +{ + +} \ No newline at end of file diff --git a/Spy/DiagLogger.cs b/Spy/DiagLogger.cs index a652115e..5daaef09 100644 --- a/Spy/DiagLogger.cs +++ b/Spy/DiagLogger.cs @@ -1,27 +1,24 @@ -using Microsoft.CodeAnalysis; +namespace MrMeeseeks.DIE.Spy; -namespace MrMeeseeks.DIE.Spy +internal interface IDiagLogger { - internal interface IDiagLogger - { - void Log(string message); - } + void Log(string message); +} - internal class DiagLogger : IDiagLogger - { - private readonly GeneratorExecutionContext _context; +internal class DiagLogger : IDiagLogger +{ + private readonly GeneratorExecutionContext _context; - public DiagLogger( - GeneratorExecutionContext context) - { - _context = context; - } + public DiagLogger( + GeneratorExecutionContext context) + { + _context = context; + } - private void Log(int id, string title, string message, string category, DiagnosticSeverity diagnosticSeverity) => - _context.ReportDiagnostic(Diagnostic.Create( - new DiagnosticDescriptor($"DIESPY{id.ToString().PadLeft(3, '0')}", title, message, category, diagnosticSeverity, true), - Location.None)); + private void Log(int id, string title, string message, string category, DiagnosticSeverity diagnosticSeverity) => + _context.ReportDiagnostic(Diagnostic.Create( + new DiagnosticDescriptor($"DIESPY{id.ToString().PadLeft(3, '0')}", title, message, category, diagnosticSeverity, true), + Location.None)); - public void Log(string message) => Log(0, "INFO", message, "INFO", DiagnosticSeverity.Warning); - } -} + public void Log(string message) => Log(0, "INFO", message, "INFO", DiagnosticSeverity.Warning); +} \ No newline at end of file diff --git a/Spy/ExecuteImpl.cs b/Spy/ExecuteImpl.cs index e95b0b7c..94fe44ba 100644 --- a/Spy/ExecuteImpl.cs +++ b/Spy/ExecuteImpl.cs @@ -1,36 +1,33 @@ -using Microsoft.CodeAnalysis; +namespace MrMeeseeks.DIE.Spy; -namespace MrMeeseeks.DIE.Spy +internal interface IExecute { - internal interface IExecute + void Execute(); +} + +internal class ExecuteImpl : IExecute +{ + private readonly GeneratorExecutionContext _context; + private readonly ITypeReportGenerator _typeReportGenerator; + private readonly IDiagLogger _diagLogger; + + public ExecuteImpl( + GeneratorExecutionContext context, + ITypeReportGenerator typeReportGenerator, + IDiagLogger diagLogger) { - void Execute(); + _context = context; + _typeReportGenerator = typeReportGenerator; + _diagLogger = diagLogger; } - internal class ExecuteImpl : IExecute + public void Execute() { - private readonly GeneratorExecutionContext _context; - private readonly ITypeReportGenerator _typeReportGenerator; - private readonly IDiagLogger _diagLogger; + _diagLogger.Log("Start Execute"); - public ExecuteImpl( - GeneratorExecutionContext context, - ITypeReportGenerator typeReportGenerator, - IDiagLogger diagLogger) - { - _context = context; - _typeReportGenerator = typeReportGenerator; - _diagLogger = diagLogger; - } + _typeReportGenerator.Generate( + _context.Compilation.Assembly.Name); - public void Execute() - { - _diagLogger.Log("Start Execute"); - - _typeReportGenerator.Generate( - _context.Compilation.Assembly.Name); - - _diagLogger.Log("End Execute"); - } + _diagLogger.Log("End Execute"); } -} +} \ No newline at end of file diff --git a/Spy/GetAllImplementations.cs b/Spy/GetAllImplementations.cs index 58d51464..24ec2856 100644 --- a/Spy/GetAllImplementations.cs +++ b/Spy/GetAllImplementations.cs @@ -1,35 +1,30 @@ -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; +using Microsoft.CodeAnalysis.CSharp.Syntax; -namespace MrMeeseeks.DIE.Spy -{ - internal interface IGetAllImplementations - { - IReadOnlyList AllNonStaticImplementations { get; } - } +namespace MrMeeseeks.DIE.Spy; - internal class GetAllImplementations : IGetAllImplementations - { - private readonly GeneratorExecutionContext _context; +internal interface IGetAllImplementations +{ + IReadOnlyList AllNonStaticImplementations { get; } +} - public GetAllImplementations(GeneratorExecutionContext context) - { - _context = context; - } +internal class GetAllImplementations : IGetAllImplementations +{ + private readonly GeneratorExecutionContext _context; - public IReadOnlyList AllNonStaticImplementations => new ReadOnlyCollection(_context.Compilation.SyntaxTrees - .Select(st => (st, _context.Compilation.GetSemanticModel(st))) - .SelectMany(t => t.st - .GetRoot() - .DescendantNodesAndSelf() - .OfType() - .Select(c => t.Item2.GetDeclaredSymbol(c)) - .Where(c => c is not null) - .OfType()) - .Where(nts => !nts.IsStatic) - .ToList()); + public GetAllImplementations(GeneratorExecutionContext context) + { + _context = context; } -} + + public IReadOnlyList AllNonStaticImplementations => new ReadOnlyCollection(_context.Compilation.SyntaxTrees + .Select(st => (st, _context.Compilation.GetSemanticModel(st))) + .SelectMany(t => t.st + .GetRoot() + .DescendantNodesAndSelf() + .OfType() + .Select(c => t.Item2.GetDeclaredSymbol(c)) + .Where(c => c is not null) + .OfType()) + .Where(nts => !nts.IsStatic) + .ToList()); +} \ No newline at end of file diff --git a/Spy/SourceGenerator.cs b/Spy/SourceGenerator.cs index 47e7e68a..a51db460 100644 --- a/Spy/SourceGenerator.cs +++ b/Spy/SourceGenerator.cs @@ -1,22 +1,19 @@ -using Microsoft.CodeAnalysis; +namespace MrMeeseeks.DIE.Spy; -namespace MrMeeseeks.DIE.Spy +[Generator] +public class SourceGenerator : ISourceGenerator { - [Generator] - public class SourceGenerator : ISourceGenerator + public void Initialize(GeneratorInitializationContext context) { - public void Initialize(GeneratorInitializationContext context) - { - } + } - public void Execute(GeneratorExecutionContext context) - { - IDiagLogger diagLogger = new DiagLogger(context); - IGetAllImplementations getAllImplementations = new GetAllImplementations(context); - ITypeReportGenerator typeReportGenerator = new TypeReportGenerator(context, getAllImplementations); - IExecute execute = new ExecuteImpl(context, typeReportGenerator, diagLogger); + public void Execute(GeneratorExecutionContext context) + { + IDiagLogger diagLogger = new DiagLogger(context); + IGetAllImplementations getAllImplementations = new GetAllImplementations(context); + ITypeReportGenerator typeReportGenerator = new TypeReportGenerator(context, getAllImplementations); + IExecute execute = new ExecuteImpl(context, typeReportGenerator, diagLogger); - execute.Execute(); - } + execute.Execute(); } -} +} \ No newline at end of file diff --git a/Spy/TypeReportGenerator.cs b/Spy/TypeReportGenerator.cs index db6e74e2..1d37f897 100644 --- a/Spy/TypeReportGenerator.cs +++ b/Spy/TypeReportGenerator.cs @@ -1,102 +1,98 @@ -using System.Linq; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Text; -using System.Text; -namespace MrMeeseeks.DIE.Spy +namespace MrMeeseeks.DIE.Spy; + +internal interface ITypeReportGenerator +{ + void Generate(string namespaceName); +} + +internal class TypeReportGenerator : ITypeReportGenerator { - internal interface ITypeReportGenerator + private readonly GeneratorExecutionContext _context; + private readonly IGetAllImplementations _getAllImplementations; + + public TypeReportGenerator( + GeneratorExecutionContext context, + IGetAllImplementations getAllImplementations) { - void Generate(string namespaceName); + _context = context; + _getAllImplementations = getAllImplementations; } - internal class TypeReportGenerator : ITypeReportGenerator + public void Generate(string namespaceName) { - private readonly GeneratorExecutionContext _context; - private readonly IGetAllImplementations _getAllImplementations; + var generatedContainer = new StringBuilder() + .AppendLine($"namespace {namespaceName}") + .AppendLine("{"); - public TypeReportGenerator( - GeneratorExecutionContext context, - IGetAllImplementations getAllImplementations) - { - _context = context; - _getAllImplementations = getAllImplementations; - } + generatedContainer = GenerateBody(Accessibility.Public, _getAllImplementations, generatedContainer); - public void Generate(string namespaceName) - { - var generatedContainer = new StringBuilder() - .AppendLine($"namespace {namespaceName}") - .AppendLine("{"); + generatedContainer = GenerateBody(Accessibility.Internal, _getAllImplementations, generatedContainer); - generatedContainer = GenerateBody(Accessibility.Public, _getAllImplementations, generatedContainer); + generatedContainer = generatedContainer + .AppendLine("}"); - generatedContainer = GenerateBody(Accessibility.Internal, _getAllImplementations, generatedContainer); + var containerSource = CSharpSyntaxTree + .ParseText(SourceText.From(generatedContainer.ToString(), Encoding.UTF8)) + .GetRoot() + .NormalizeWhitespace() + .SyntaxTree + .GetText(); + _context.AddSource("TypeReport.g.cs", containerSource); - generatedContainer = generatedContainer - .AppendLine("}"); - - var containerSource = CSharpSyntaxTree - .ParseText(SourceText.From(generatedContainer.ToString(), Encoding.UTF8)) - .GetRoot() - .NormalizeWhitespace() - .SyntaxTree - .GetText(); - _context.AddSource("TypeReport.g.cs", containerSource); - - static StringBuilder GenerateBody(Accessibility accessModifier, IGetAllImplementations getAllImplementations, StringBuilder generatedContainer) - { - var lowerCaseAccessModifier = accessModifier.ToString().ToLower(); - var pascalCaseAccessModifier = accessModifier.ToString(); + static StringBuilder GenerateBody(Accessibility accessModifier, IGetAllImplementations getAllImplementations, StringBuilder generatedContainer) + { + var lowerCaseAccessModifier = accessModifier.ToString().ToLower(); + var pascalCaseAccessModifier = accessModifier.ToString(); - var types = getAllImplementations - .AllNonStaticImplementations - .Where(t => t.DeclaredAccessibility == accessModifier) - .ToList(); + var types = getAllImplementations + .AllNonStaticImplementations + .Where(t => t.DeclaredAccessibility == accessModifier) + .ToList(); - generatedContainer = generatedContainer - .AppendLine($"{lowerCaseAccessModifier} interface I{pascalCaseAccessModifier}TypeReport") - .AppendLine("{"); + generatedContainer = generatedContainer + .AppendLine($"{lowerCaseAccessModifier} interface I{pascalCaseAccessModifier}TypeReport") + .AppendLine("{"); - var i = -1; - generatedContainer = types.Aggregate( - generatedContainer, - (current, type) => current.AppendLine( - $"{FullName(type)} Type{++i}{(type.TypeArguments.Length > 0 ? $"<{string.Join(", ", type.TypeArguments.Select(t => t.Name))}>" : "")}(){TypeArgumentsConstraintsString(type)};")); + var i = -1; + generatedContainer = types.Aggregate( + generatedContainer, + (current, type) => current.AppendLine( + $"{FullName(type)} Type{++i}{(type.TypeArguments.Length > 0 ? $"<{string.Join(", ", type.TypeArguments.Select(t => t.Name))}>" : "")}(){TypeArgumentsConstraintsString(type)};")); - generatedContainer = generatedContainer - .AppendLine("}"); + generatedContainer = generatedContainer + .AppendLine("}"); - return generatedContainer; - } + return generatedContainer; + } - static string FullName(ISymbol type) => - type.ToDisplayString(new SymbolDisplayFormat( - globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Included, - typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces, - parameterOptions: SymbolDisplayParameterOptions.IncludeType | SymbolDisplayParameterOptions.IncludeParamsRefOut, - genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters, - memberOptions: SymbolDisplayMemberOptions.IncludeRef)); + static string FullName(ISymbol type) => + type.ToDisplayString(new SymbolDisplayFormat( + globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Included, + typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces, + parameterOptions: SymbolDisplayParameterOptions.IncludeType | SymbolDisplayParameterOptions.IncludeParamsRefOut, + genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters, + memberOptions: SymbolDisplayMemberOptions.IncludeRef)); - static string TypeArgumentsConstraintsString(INamedTypeSymbol namedTypeSymbol) - { - var displayStringWithoutConstraints = namedTypeSymbol.ToDisplayString(new SymbolDisplayFormat( - globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Included, - typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces, - parameterOptions: SymbolDisplayParameterOptions.IncludeType | SymbolDisplayParameterOptions.IncludeParamsRefOut, - genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters, - memberOptions: SymbolDisplayMemberOptions.IncludeRef)); - var displayStringWithConstraints = namedTypeSymbol.ToDisplayString(new SymbolDisplayFormat( - globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Included, - typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces, - parameterOptions: SymbolDisplayParameterOptions.IncludeType | SymbolDisplayParameterOptions.IncludeParamsRefOut, - genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters | SymbolDisplayGenericsOptions.IncludeTypeConstraints, - memberOptions: SymbolDisplayMemberOptions.IncludeRef)); + static string TypeArgumentsConstraintsString(INamedTypeSymbol namedTypeSymbol) + { + var displayStringWithoutConstraints = namedTypeSymbol.ToDisplayString(new SymbolDisplayFormat( + globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Included, + typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces, + parameterOptions: SymbolDisplayParameterOptions.IncludeType | SymbolDisplayParameterOptions.IncludeParamsRefOut, + genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters, + memberOptions: SymbolDisplayMemberOptions.IncludeRef)); + var displayStringWithConstraints = namedTypeSymbol.ToDisplayString(new SymbolDisplayFormat( + globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Included, + typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces, + parameterOptions: SymbolDisplayParameterOptions.IncludeType | SymbolDisplayParameterOptions.IncludeParamsRefOut, + genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters | SymbolDisplayGenericsOptions.IncludeTypeConstraints, + memberOptions: SymbolDisplayMemberOptions.IncludeRef)); - var ret = displayStringWithConstraints.Remove(0, displayStringWithoutConstraints.Length); - return ret; - } + var ret = displayStringWithConstraints.Remove(0, displayStringWithoutConstraints.Length); + return ret; } } -} +} \ No newline at end of file From 860b9abccaf190a45c0f0cf2d5197acf4d1fe858 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sat, 13 Nov 2021 18:06:04 +0100 Subject: [PATCH 019/162] Preparations for Scopes --- Main/Attributes.cs | 14 ++ Main/CheckTypeProperties.cs | 8 + Main/ContainerGenerator.cs | 53 ++-- Main/ContainerInfo.cs | 31 ++- Main/ExecuteImpl.cs | 11 +- Main/IContainer.cs | 3 +- Main/ResolutionTreeCreationErrorHarvester.cs | 13 +- Main/ResolutionTreeFactory.cs | 242 +++++++++++++------ Main/ResolutionTreeItem.cs | 58 ++++- Main/SourceGenerator.cs | 11 +- Main/TypesFromAttributes.cs | 6 + Main/WellKnownTypes.cs | 12 + Sample/Program.cs | 2 +- 13 files changed, 326 insertions(+), 138 deletions(-) diff --git a/Main/Attributes.cs b/Main/Attributes.cs index 4d9eef2b..a54f4426 100644 --- a/Main/Attributes.cs +++ b/Main/Attributes.cs @@ -19,4 +19,18 @@ public class SingleInstanceAttribute : Attribute { // ReSharper disable once UnusedParameter.Local *** Is used in the generator public SingleInstanceAttribute(params Type[] type) {} +} + +[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] +public class ScopedInstanceAttribute : Attribute +{ + // ReSharper disable once UnusedParameter.Local *** Is used in the generator + public ScopedInstanceAttribute(params Type[] type) {} +} + +[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] +public class ScopeRootAttribute : Attribute +{ + // ReSharper disable once UnusedParameter.Local *** Is used in the generator + public ScopeRootAttribute(params Type[] type) {} } \ No newline at end of file diff --git a/Main/CheckTypeProperties.cs b/Main/CheckTypeProperties.cs index 1ba63589..54d5c6ac 100644 --- a/Main/CheckTypeProperties.cs +++ b/Main/CheckTypeProperties.cs @@ -4,12 +4,16 @@ public interface ICheckTypeProperties { bool ShouldBeManaged(INamedTypeSymbol type); bool ShouldBeSingleInstance(INamedTypeSymbol type); + bool ShouldBeScopedInstance(INamedTypeSymbol type); + bool ShouldBeScopeRoot(INamedTypeSymbol type); } internal class CheckTypeProperties : ICheckTypeProperties { private readonly IImmutableSet _transientTypes; private readonly IImmutableSet _singleInstanceTypes; + private readonly IImmutableSet _scopedInstanceTypes; + private readonly IImmutableSet _scopeRootTypes; public CheckTypeProperties( IGetAllImplementations getAllImplementations, @@ -17,6 +21,8 @@ public CheckTypeProperties( { _transientTypes = GetSetOfTypesWithProperties(typesFromAttributes.Transient); _singleInstanceTypes = GetSetOfTypesWithProperties(typesFromAttributes.SingleInstance); + _scopedInstanceTypes = GetSetOfTypesWithProperties(typesFromAttributes.ScopedInstance); + _scopeRootTypes = GetSetOfTypesWithProperties(typesFromAttributes.ScopeRoot); IImmutableSet GetSetOfTypesWithProperties(IReadOnlyList propertyGivingTypes) => getAllImplementations .AllImplementations @@ -45,4 +51,6 @@ IEnumerable AllDerivedTypes(INamedTypeSymbol type) public bool ShouldBeManaged(INamedTypeSymbol type) => !_transientTypes.Contains(type); public bool ShouldBeSingleInstance(INamedTypeSymbol type) => _singleInstanceTypes.Contains(type); + public bool ShouldBeScopedInstance(INamedTypeSymbol type) => _scopedInstanceTypes.Contains(type); + public bool ShouldBeScopeRoot(INamedTypeSymbol type) => _scopeRootTypes.Contains(type); } \ No newline at end of file diff --git a/Main/ContainerGenerator.cs b/Main/ContainerGenerator.cs index 74d06b82..3870d14e 100644 --- a/Main/ContainerGenerator.cs +++ b/Main/ContainerGenerator.cs @@ -26,7 +26,7 @@ public ContainerGenerator( public void Generate(IContainerInfo containerInfo, ContainerResolution containerResolution) { - if (!containerInfo.IsValid || containerInfo.ResolutionRootType is null) + if (!containerInfo.IsValid) { _diagLogger.Log($"return generation"); return; @@ -56,7 +56,7 @@ public void Generate(IContainerInfo containerInfo, ContainerResolution container .AppendLine($"{{") .AppendLine($"if (this.{containerResolution.DisposalHandling.DisposedPropertyReference}) throw new {_wellKnownTypes.ObjectDisposedException}(nameof({containerInfo.Name}));"); - generatedContainer = GenerateResolutionFunction(generatedContainer, singleInstanceResolution.Dependency); + generatedContainer = GenerateResolutionFunctionContent(generatedContainer, singleInstanceResolution.Dependency); generatedContainer = generatedContainer .AppendLine($"this.{singleInstanceResolution.Function.FieldReference} = {singleInstanceResolution.Dependency.Reference};") @@ -68,20 +68,10 @@ public void Generate(IContainerInfo containerInfo, ContainerResolution container .AppendLine($"return this.{singleInstanceResolution.Function.FieldReference};") .AppendLine($"}}"); } - - generatedContainer = generatedContainer - .AppendLine($"public {containerResolution.TypeFullName} Resolve()") - .AppendLine($"{{") - .AppendLine($"if (this.{containerResolution.DisposalHandling.DisposedPropertyReference}) throw new {_wellKnownTypes.ObjectDisposedException}(nameof({containerInfo.Name}));"); - - generatedContainer = GenerateResolutionFunction(generatedContainer, containerResolution); - generatedContainer = generatedContainer - .AppendLine($"return {containerResolution.Reference};") - .AppendLine($"}}") - .AppendLine($"}}") - .AppendLine($"}}") - ; + generatedContainer = containerResolution.RootResolutions.Aggregate(generatedContainer, GenerateResolutionFunction) + .AppendLine($"}}") + .AppendLine($"}}"); var containerSource = CSharpSyntaxTree .ParseText(SourceText.From(generatedContainer.ToString(), Encoding.UTF8)) @@ -94,7 +84,7 @@ public void Generate(IContainerInfo containerInfo, ContainerResolution container StringBuilder GenerateContainerDisposalFunction( StringBuilder stringBuilder, - ContainerResolutionDisposalHandling disposalHandling, + DisposalHandling disposalHandling, ContainerResolution containerResolution) { stringBuilder = stringBuilder @@ -137,21 +127,32 @@ StringBuilder GenerateContainerDisposalFunction( .AppendLine($"this.{singleInstanceResolution.Function.LockReference}.Release();"); } - stringBuilder = stringBuilder + return stringBuilder .AppendLine($"}}") .AppendLine($"}}"); - - return stringBuilder; } StringBuilder GenerateResolutionFunction( + StringBuilder stringBuilder, + (Resolvable, INamedTypeSymbol) resolution) + { + var (resolvable, type) = resolution; + stringBuilder = stringBuilder + .AppendLine($"{resolvable.TypeFullName} {_wellKnownTypes.Container.Construct(type).FullName()}.Resolve()") + .AppendLine($"{{") + .AppendLine($"if (this.{containerResolution.DisposalHandling.DisposedPropertyReference}) throw new {_wellKnownTypes.ObjectDisposedException}(nameof({containerInfo.Name}));"); + + return GenerateResolutionFunctionContent(stringBuilder, resolvable) + .AppendLine($"return {resolvable.Reference};") + .AppendLine($"}}"); + } + + StringBuilder GenerateResolutionFunctionContent( StringBuilder stringBuilder, Resolvable resolution) { stringBuilder = GenerateFields(stringBuilder, resolution); - stringBuilder = GenerateResolutions(stringBuilder, resolution); - - return stringBuilder; + return GenerateResolutions(stringBuilder, resolution); } StringBuilder GenerateFields( @@ -163,9 +164,6 @@ StringBuilder GenerateFields( case SingleInstanceReferenceResolution(var reference, { TypeFullName: {} typeFullName}): stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); break; - case ContainerResolution(var rootResolution, _, _): - stringBuilder = GenerateFields(stringBuilder, rootResolution); - break; case InterfaceResolution(var reference, var typeFullName, Resolvable resolutionBase): stringBuilder = GenerateFields(stringBuilder, resolutionBase); stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); @@ -200,9 +198,6 @@ StringBuilder GenerateResolutions( case SingleInstanceReferenceResolution(var reference, { Reference: {} functionReference}): stringBuilder = stringBuilder.AppendLine($"{reference} = {functionReference}();"); break; - case ContainerResolution(var rootResolution, _, _): - stringBuilder = GenerateResolutions(stringBuilder, rootResolution); - break; case InterfaceResolution(var reference, var typeFullName, Resolvable resolutionBase): stringBuilder = GenerateResolutions(stringBuilder, resolutionBase); stringBuilder = stringBuilder.AppendLine( @@ -220,7 +215,7 @@ StringBuilder GenerateResolutions( case FuncResolution(var reference, _, var parameter, Resolvable resolutionBase): stringBuilder = stringBuilder.AppendLine($"{reference} = ({string.Join(", ", parameter.Select(fpr => fpr.Reference))}) =>"); stringBuilder = stringBuilder.AppendLine($"{{"); - GenerateResolutionFunction(stringBuilder, resolutionBase); + GenerateResolutionFunctionContent(stringBuilder, resolutionBase); stringBuilder = stringBuilder.AppendLine($"return {resolutionBase.Reference};"); stringBuilder = stringBuilder.AppendLine($"}};"); break; diff --git a/Main/ContainerInfo.cs b/Main/ContainerInfo.cs index 95d9dc8f..10be438d 100644 --- a/Main/ContainerInfo.cs +++ b/Main/ContainerInfo.cs @@ -5,7 +5,7 @@ public interface IContainerInfo string Name { get; } string Namespace { get; } bool IsValid { get; } - INamedTypeSymbol? ResolutionRootType { get; } + IReadOnlyList ResolutionRootTypes { get; } } internal class ContainerInfo : IContainerInfo @@ -20,21 +20,26 @@ public ContainerInfo( Name = containerClass.Name; Namespace = containerClass.ContainingNamespace.FullName(); - var namedTypeSymbol = containerClass.AllInterfaces.Single(x => x.OriginalDefinition.Equals(wellKnowTypes.Container, SymbolEqualityComparer.Default)); - var typeParameterSymbol = namedTypeSymbol.TypeArguments.Single(); - if (typeParameterSymbol is INamedTypeSymbol { IsUnboundGenericType: false } type && type.IsAccessibleInternally()) - { - ResolutionRootType = type; - IsValid = true; - } - else - { - IsValid = false; - } + ResolutionRootTypes = containerClass + .AllInterfaces + .Where(x => x.OriginalDefinition.Equals(wellKnowTypes.Container, SymbolEqualityComparer.Default)) + .Select(nts => + { + var typeParameterSymbol = nts.TypeArguments.Single(); + if (typeParameterSymbol is INamedTypeSymbol { IsUnboundGenericType: false } type && type.IsAccessibleInternally()) + { + return typeParameterSymbol; + } + return null; + }) + .OfType() + .ToList(); + + IsValid = ResolutionRootTypes.Any(); } public string Name { get; } public string Namespace { get; } public bool IsValid { get; } - public INamedTypeSymbol? ResolutionRootType { get; } + public IReadOnlyList ResolutionRootTypes { get; } } \ No newline at end of file diff --git a/Main/ExecuteImpl.cs b/Main/ExecuteImpl.cs index cf45a030..4c027947 100644 --- a/Main/ExecuteImpl.cs +++ b/Main/ExecuteImpl.cs @@ -13,7 +13,7 @@ internal class ExecuteImpl : IExecute private readonly WellKnownTypes _wellKnownTypes; private readonly IContainerGenerator _containerGenerator; private readonly IContainerErrorGenerator _containerErrorGenerator; - private readonly IResolutionTreeFactory _resolutionTreeFactory; + private readonly IContainerResolutionBuilder _containerResolutionBuilder; private readonly IResolutionTreeCreationErrorHarvester _resolutionTreeCreationErrorHarvester; private readonly Func _containerInfoFactory; private readonly IDiagLogger _diagLogger; @@ -23,7 +23,7 @@ public ExecuteImpl( WellKnownTypes wellKnownTypes, IContainerGenerator containerGenerator, IContainerErrorGenerator containerErrorGenerator, - IResolutionTreeFactory resolutionTreeFactory, + IContainerResolutionBuilder containerResolutionBuilder, IResolutionTreeCreationErrorHarvester resolutionTreeCreationErrorHarvester, Func containerInfoFactory, IDiagLogger diagLogger) @@ -32,7 +32,7 @@ public ExecuteImpl( _wellKnownTypes = wellKnownTypes; _containerGenerator = containerGenerator; _containerErrorGenerator = containerErrorGenerator; - _resolutionTreeFactory = resolutionTreeFactory; + _containerResolutionBuilder = containerResolutionBuilder; _resolutionTreeCreationErrorHarvester = resolutionTreeCreationErrorHarvester; _containerInfoFactory = containerInfoFactory; _diagLogger = diagLogger; @@ -55,9 +55,10 @@ public void Execute() foreach (var namedTypeSymbol in containerClasses) { var containerInfo = _containerInfoFactory(namedTypeSymbol); - if (containerInfo.IsValid && containerInfo.ResolutionRootType is { }) + if (containerInfo.IsValid) { - var containerResolution = _resolutionTreeFactory.Create(containerInfo.ResolutionRootType); + _containerResolutionBuilder.AddCreateFunctions(containerInfo.ResolutionRootTypes); + var containerResolution = _containerResolutionBuilder.Build(); var errorTreeItems = _resolutionTreeCreationErrorHarvester.Harvest(containerResolution); if (errorTreeItems.Any()) _containerErrorGenerator.Generate(containerInfo, errorTreeItems); diff --git a/Main/IContainer.cs b/Main/IContainer.cs index cea31bdf..5f970d6f 100644 --- a/Main/IContainer.cs +++ b/Main/IContainer.cs @@ -1,5 +1,6 @@ namespace MrMeeseeks.DIE; -public partial interface IContainer +public interface IContainer { + T Resolve(); } \ No newline at end of file diff --git a/Main/ResolutionTreeCreationErrorHarvester.cs b/Main/ResolutionTreeCreationErrorHarvester.cs index 9c4fc81b..949b640d 100644 --- a/Main/ResolutionTreeCreationErrorHarvester.cs +++ b/Main/ResolutionTreeCreationErrorHarvester.cs @@ -20,7 +20,18 @@ static void Inner(ResolutionTreeItem item, ICollection errorTreeI case SingleInstanceReferenceResolution: break; case ContainerResolution containerResolution: - Inner(containerResolution.RootResolution, errorTreeItems); + foreach (var singleInstance in containerResolution.SingleInstanceResolutions) + Inner(singleInstance.Dependency, errorTreeItems); + foreach (var scopedInstance in containerResolution.ScopedInstanceResolutions) + Inner(scopedInstance.Dependency, errorTreeItems); + foreach (var rootResolution in containerResolution.RootResolutions) + Inner(rootResolution.Item1, errorTreeItems); + break; + case ScopeResolution scopeResolution: + foreach (var scopedInstance in scopeResolution.ScopedInstanceResolutions) + Inner(scopedInstance.Dependency, errorTreeItems); + foreach (var rootResolution in scopeResolution.RootResolutions) + Inner(rootResolution.Item1, errorTreeItems); break; case ErrorTreeItem errorTreeItem: errorTreeItems.Add(errorTreeItem); diff --git a/Main/ResolutionTreeFactory.cs b/Main/ResolutionTreeFactory.cs index 86f3fb3b..a85f525d 100644 --- a/Main/ResolutionTreeFactory.cs +++ b/Main/ResolutionTreeFactory.cs @@ -1,73 +1,51 @@ namespace MrMeeseeks.DIE; -internal interface IResolutionTreeFactory +internal interface IContainerResolutionBuilder { - ContainerResolution Create(ITypeSymbol root); + void AddCreateFunctions(IReadOnlyList rootTypes); + + ContainerResolution Build(); } -internal class ResolutionTreeFactory : IResolutionTreeFactory +internal interface IScopeResolutionBuilder { - private readonly ITypeToImplementationsMapper _typeToImplementationsMapper; - private readonly IReferenceGeneratorFactory _referenceGeneratorFactory; - private readonly ICheckTypeProperties _checkTypeProperties; - private readonly WellKnownTypes _wellKnownTypes; + void AddCreateFunction(INamedTypeSymbol rootType); - private readonly IDictionary _singleInstanceReferenceResolutions = - new Dictionary(SymbolEqualityComparer.Default); - private readonly Queue _singleInstanceResolutionsQueue = new(); + ScopeResolution Build(); +} + +internal abstract class RangeResolutionBaseBuilder +{ + protected readonly WellKnownTypes WellKnownTypes; + protected readonly ITypeToImplementationsMapper TypeToImplementationsMapper; + protected readonly IReferenceGeneratorFactory ReferenceGeneratorFactory; + protected readonly ICheckTypeProperties CheckTypeProperties; + + private readonly IDictionary + _containerScopedInstanceReferenceResolutions = + new Dictionary(SymbolEqualityComparer.Default); + private readonly Queue _scopedInstanceResolutionsQueue = new(); + + protected readonly List ScopedInstances = new (); - private readonly IReferenceGenerator _singleInstanceReferenceGenerator; - public ResolutionTreeFactory( + protected RangeResolutionBaseBuilder( + WellKnownTypes wellKnownTypes, ITypeToImplementationsMapper typeToImplementationsMapper, IReferenceGeneratorFactory referenceGeneratorFactory, - ICheckTypeProperties checkTypeProperties, - WellKnownTypes wellKnownTypes) + ICheckTypeProperties checkTypeProperties) { - _typeToImplementationsMapper = typeToImplementationsMapper; - _referenceGeneratorFactory = referenceGeneratorFactory; - _checkTypeProperties = checkTypeProperties; - _wellKnownTypes = wellKnownTypes; - _singleInstanceReferenceGenerator = referenceGeneratorFactory.Create(); + WellKnownTypes = wellKnownTypes; + TypeToImplementationsMapper = typeToImplementationsMapper; + ReferenceGeneratorFactory = referenceGeneratorFactory; + CheckTypeProperties = checkTypeProperties; } - public ContainerResolution Create(ITypeSymbol type) - { - var disposableCollectionResolution = new DisposableCollectionResolution( - _singleInstanceReferenceGenerator.Generate(_wellKnownTypes.ConcurrentBagOfDisposable), - _wellKnownTypes.ConcurrentBagOfDisposable.FullName()); - var referenceGenerator = _referenceGeneratorFactory.Create(); - var rootResolution = Create( - type, - referenceGenerator, - Array.Empty<(ITypeSymbol Type, FuncParameterResolution Resolution)>(), - disposableCollectionResolution); - var singleInstances = new List(); - - while (_singleInstanceResolutionsQueue.Any()) - { - var singleInstanceFunction = _singleInstanceResolutionsQueue.Dequeue(); - var resolvable = CreateConstructorResolution( - singleInstanceFunction.Type, - _referenceGeneratorFactory.Create(), - Array.Empty<(ITypeSymbol Type, FuncParameterResolution Resolution)>(), - disposableCollectionResolution, - true); - singleInstances.Add(new SingleInstance(singleInstanceFunction, resolvable)); - } - - return new ContainerResolution( - rootResolution, - new ContainerResolutionDisposalHandling( - disposableCollectionResolution, - _singleInstanceReferenceGenerator.Generate("_disposed"), - _singleInstanceReferenceGenerator.Generate("disposed"), - _singleInstanceReferenceGenerator.Generate("Disposed"), - _singleInstanceReferenceGenerator.Generate("disposable")), - singleInstances); - } + protected abstract SingleInstanceReferenceResolution CreateSingleInstanceReferenceResolution( + INamedTypeSymbol implementationType, + IReferenceGenerator referenceGenerator); - private Resolvable Create( + protected Resolvable Create( ITypeSymbol type, IReferenceGenerator referenceGenerator, IReadOnlyList<(ITypeSymbol Type, FuncParameterResolution Resolution)> currentFuncParameters, @@ -78,7 +56,7 @@ private Resolvable Create( return funcParameter.Resolution; } - if (type.OriginalDefinition.Equals(_wellKnownTypes.Lazy1, SymbolEqualityComparer.Default) + if (type.OriginalDefinition.Equals(WellKnownTypes.Lazy1, SymbolEqualityComparer.Default) && type is INamedTypeSymbol namedTypeSymbol) { if (namedTypeSymbol.TypeArguments.SingleOrDefault() is not INamedTypeSymbol genericType) @@ -93,13 +71,13 @@ private Resolvable Create( var dependency = Create( genericType, - _referenceGeneratorFactory.Create(), + ReferenceGeneratorFactory.Create(), Array.Empty<(ITypeSymbol Type, FuncParameterResolution Resolution)>(), disposableCollectionResolution); return new ConstructorResolution( referenceGenerator.Generate(namedTypeSymbol), namedTypeSymbol.FullName(), - ImplementsIDisposable(namedTypeSymbol, _wellKnownTypes, disposableCollectionResolution, _checkTypeProperties), + ImplementsIDisposable(namedTypeSymbol, WellKnownTypes, disposableCollectionResolution, CheckTypeProperties), new ReadOnlyCollection<(string Name, Resolvable Dependency)>( new List<(string Name, Resolvable Dependency)> { @@ -114,9 +92,9 @@ private Resolvable Create( })); } - if (type.OriginalDefinition.Equals(_wellKnownTypes.Enumerable1, SymbolEqualityComparer.Default) - || type.OriginalDefinition.Equals(_wellKnownTypes.ReadOnlyCollection1, SymbolEqualityComparer.Default) - || type.OriginalDefinition.Equals(_wellKnownTypes.ReadOnlyList1, SymbolEqualityComparer.Default)) + if (type.OriginalDefinition.Equals(WellKnownTypes.Enumerable1, SymbolEqualityComparer.Default) + || type.OriginalDefinition.Equals(WellKnownTypes.ReadOnlyCollection1, SymbolEqualityComparer.Default) + || type.OriginalDefinition.Equals(WellKnownTypes.ReadOnlyList1, SymbolEqualityComparer.Default)) { if (type is not INamedTypeSymbol collectionType) { @@ -132,7 +110,7 @@ private Resolvable Create( }); } var itemFullName = itemType.FullName(); - var items = _typeToImplementationsMapper + var items = TypeToImplementationsMapper .Map(itemType) .Select(i => Create(i, referenceGenerator, currentFuncParameters, disposableCollectionResolution)) .ToList(); @@ -145,7 +123,7 @@ private Resolvable Create( if (type.TypeKind == TypeKind.Interface) { - var implementations = _typeToImplementationsMapper + var implementations = TypeToImplementationsMapper .Map(type); if (implementations .SingleOrDefault() is not { } implementationType) @@ -171,7 +149,7 @@ private Resolvable Create( && type is INamedTypeSymbol namedTypeSymbol0) { var returnType = namedTypeSymbol0.TypeArguments.Last(); - var innerReferenceGenerator = _referenceGeneratorFactory.Create(); + var innerReferenceGenerator = ReferenceGeneratorFactory.Create(); var parameterTypes = namedTypeSymbol0 .TypeArguments .Take(namedTypeSymbol0.TypeArguments.Length - 1) @@ -192,15 +170,15 @@ private Resolvable Create( return new ErrorTreeItem($"[{type.FullName()}] Couldn't process in resolution tree creation."); } - - private Resolvable CreateConstructorResolution( - ITypeSymbol typeSymbol, + + protected Resolvable CreateConstructorResolution( + ITypeSymbol typeSymbol, IReferenceGenerator referenceGenerator, - IReadOnlyList<(ITypeSymbol Type, FuncParameterResolution Resolution)> readOnlyList, + IReadOnlyList<(ITypeSymbol Type, FuncParameterResolution Resolution)> readOnlyList, DisposableCollectionResolution disposableCollectionResolution, bool skipSingleInstanceCheck = false) { - var implementations = _typeToImplementationsMapper + var implementations = TypeToImplementationsMapper .Map(typeSymbol); if (implementations .SingleOrDefault() is not { } implementationType) @@ -214,7 +192,7 @@ private Resolvable CreateConstructorResolution( }); } - if (!skipSingleInstanceCheck && _checkTypeProperties.ShouldBeSingleInstance(implementationType)) + if (!skipSingleInstanceCheck && CheckTypeProperties.ShouldBeSingleInstance(implementationType)) return CreateSingleInstanceReferenceResolution(implementationType, referenceGenerator); if (implementationType.Constructors.SingleOrDefault() is not { } constructor) @@ -233,8 +211,8 @@ private Resolvable CreateConstructorResolution( return new ConstructorResolution( referenceGenerator.Generate(implementationType), implementationType.FullName(), - ImplementsIDisposable(implementationType, _wellKnownTypes, disposableCollectionResolution, - _checkTypeProperties), + ImplementsIDisposable(implementationType, WellKnownTypes, disposableCollectionResolution, + CheckTypeProperties), new ReadOnlyCollection<(string Name, Resolvable Dependency)>(constructor .Parameters .Select(p => @@ -256,7 +234,67 @@ private Resolvable CreateConstructorResolution( .ToList())); } - private SingleInstanceReferenceResolution CreateSingleInstanceReferenceResolution( + private static DisposableCollectionResolution? ImplementsIDisposable( + INamedTypeSymbol type, + WellKnownTypes wellKnownTypes, + DisposableCollectionResolution disposableCollectionResolution, + ICheckTypeProperties checkDisposalManagement) => + type.AllInterfaces.Contains(wellKnownTypes.Disposable) && checkDisposalManagement.ShouldBeManaged(type) + ? disposableCollectionResolution + : null; +} + +internal class ContainerResolutionBuilder : RangeResolutionBaseBuilder, IContainerResolutionBuilder +{ + private readonly IDictionary _singleInstanceReferenceResolutions = + new Dictionary(SymbolEqualityComparer.Default); + private readonly Queue _singleInstanceResolutionsQueue = new(); + + private readonly IReferenceGenerator _singleInstanceReferenceGenerator; + private readonly List<(Resolvable, INamedTypeSymbol)> _rootResolutions = new (); + private readonly List _singleInstances = new (); + private readonly DisposableCollectionResolution _disposableCollectionResolution; + private readonly IScopeResolutionBuilder _scopeResolutionBuilder; + + public ContainerResolutionBuilder( + ITypeToImplementationsMapper typeToImplementationsMapper, + IReferenceGeneratorFactory referenceGeneratorFactory, + ICheckTypeProperties checkTypeProperties, + WellKnownTypes wellKnownTypes, + Func scopeResolutionBuilderFactory) : base(wellKnownTypes, typeToImplementationsMapper, referenceGeneratorFactory, + checkTypeProperties) + { + _singleInstanceReferenceGenerator = referenceGeneratorFactory.Create(); + _disposableCollectionResolution = new DisposableCollectionResolution( + _singleInstanceReferenceGenerator.Generate(WellKnownTypes.ConcurrentBagOfDisposable), + WellKnownTypes.ConcurrentBagOfDisposable.FullName()); + _scopeResolutionBuilder = scopeResolutionBuilderFactory(); + } + + public void AddCreateFunctions(IReadOnlyList rootTypes) + { + foreach (var typeSymbol in rootTypes) + _rootResolutions.Add((Create( + typeSymbol, + ReferenceGeneratorFactory.Create(), + Array.Empty<(ITypeSymbol Type, FuncParameterResolution Resolution)>(), + _disposableCollectionResolution), + typeSymbol)); + + while (_singleInstanceResolutionsQueue.Any()) + { + var singleInstanceFunction = _singleInstanceResolutionsQueue.Dequeue(); + var resolvable = CreateConstructorResolution( + singleInstanceFunction.Type, + ReferenceGeneratorFactory.Create(), + Array.Empty<(ITypeSymbol Type, FuncParameterResolution Resolution)>(), + _disposableCollectionResolution, + true); + _singleInstances.Add(new SingleInstance(singleInstanceFunction, resolvable)); + } + } + + protected override SingleInstanceReferenceResolution CreateSingleInstanceReferenceResolution( INamedTypeSymbol implementationType, IReferenceGenerator referenceGenerator) { @@ -273,17 +311,61 @@ private SingleInstanceReferenceResolution CreateSingleInstanceReferenceResolutio _singleInstanceReferenceResolutions[implementationType] = function; _singleInstanceResolutionsQueue.Enqueue(function); } + return new SingleInstanceReferenceResolution( referenceGenerator.Generate(implementationType), function); } - private static DisposableCollectionResolution? ImplementsIDisposable( - INamedTypeSymbol type, + public ContainerResolution Build() => + new(_rootResolutions, + new DisposalHandling( + _disposableCollectionResolution, + _singleInstanceReferenceGenerator.Generate("_disposed"), + _singleInstanceReferenceGenerator.Generate("disposed"), + _singleInstanceReferenceGenerator.Generate("Disposed"), + _singleInstanceReferenceGenerator.Generate("disposable")), + ScopedInstances, + _singleInstances, + _scopeResolutionBuilder.Build()); +} + +internal class ScopeResolutionBuilder : RangeResolutionBaseBuilder, IScopeResolutionBuilder +{ + private readonly IReferenceGenerator _scopeInstanceReferenceGenerator; + private readonly List<(Resolvable, INamedTypeSymbol)> _rootResolutions = new (); + private readonly DisposableCollectionResolution _disposableCollectionResolution; + + public ScopeResolutionBuilder( WellKnownTypes wellKnownTypes, - DisposableCollectionResolution disposableCollectionResolution, - ICheckTypeProperties checkDisposalManagement) => - type.AllInterfaces.Contains(wellKnownTypes.Disposable) && checkDisposalManagement.ShouldBeManaged(type) - ? disposableCollectionResolution - : null; + ITypeToImplementationsMapper typeToImplementationsMapper, + IReferenceGeneratorFactory referenceGeneratorFactory, + ICheckTypeProperties checkTypeProperties) : base(wellKnownTypes, typeToImplementationsMapper, referenceGeneratorFactory, checkTypeProperties) + { + _scopeInstanceReferenceGenerator = referenceGeneratorFactory.Create(); + _disposableCollectionResolution = new DisposableCollectionResolution( + _scopeInstanceReferenceGenerator.Generate(WellKnownTypes.ConcurrentBagOfDisposable), + WellKnownTypes.ConcurrentBagOfDisposable.FullName()); + } + + protected override SingleInstanceReferenceResolution CreateSingleInstanceReferenceResolution(INamedTypeSymbol implementationType, + IReferenceGenerator referenceGenerator) + { + throw new NotImplementedException(); + } + + public void AddCreateFunction(INamedTypeSymbol rootType) + { + throw new NotImplementedException(); + } + + public ScopeResolution Build() => + new(_rootResolutions, + new DisposalHandling( + _disposableCollectionResolution, + _scopeInstanceReferenceGenerator.Generate("_disposed"), + _scopeInstanceReferenceGenerator.Generate("disposed"), + _scopeInstanceReferenceGenerator.Generate("Disposed"), + _scopeInstanceReferenceGenerator.Generate("disposable")), + ScopedInstances); } \ No newline at end of file diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index 6d333376..1f86903d 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -20,24 +20,54 @@ internal record ConstructorResolution( DisposableCollectionResolution? DisposableCollectionResolution, IReadOnlyList<(string name, Resolvable Dependency)> Parameter) : Resolvable(Reference, TypeFullName); +internal abstract record RangedInstanceBase( + T Function, + Resolvable Dependency) where T : RangedInstanceFunctionBase; + internal record SingleInstance( SingleInstanceFunction Function, - Resolvable Dependency); + Resolvable Dependency) : RangedInstanceBase(Function, Dependency); + +internal record ScopedInstance( + ScopedInstanceFunction Function, + Resolvable Dependency) : RangedInstanceBase(Function, Dependency); internal record FuncParameterResolution( string Reference, string TypeFullName) : Resolvable(Reference, TypeFullName); -internal record SingleInstanceFunction( +internal abstract record RangedInstanceFunctionBase( string Reference, string TypeFullName, INamedTypeSymbol Type, string FieldReference, string LockReference); +internal record SingleInstanceFunction( + string Reference, + string TypeFullName, + INamedTypeSymbol Type, + string FieldReference, + string LockReference) : RangedInstanceFunctionBase(Reference, TypeFullName, Type, FieldReference, LockReference); + +internal record ScopedInstanceFunction( + string Reference, + string TypeFullName, + INamedTypeSymbol Type, + string FieldReference, + string LockReference) : RangedInstanceFunctionBase(Reference, TypeFullName, Type, FieldReference, LockReference); + +internal abstract record RangedInstanceReferenceResolutionBase( + string Reference, + T Function) : Resolvable(Reference, Function.TypeFullName) where T : RangedInstanceFunctionBase; + internal record SingleInstanceReferenceResolution( string Reference, - SingleInstanceFunction Function) : Resolvable(Reference, Function.TypeFullName); + SingleInstanceFunction Function) : RangedInstanceReferenceResolutionBase(Reference, Function); + +internal record ScopedInstanceReferenceResolution( + string Reference, + ScopedInstanceFunction Function) : RangedInstanceReferenceResolutionBase(Reference, Function); internal record FuncResolution( string Reference, @@ -55,12 +85,26 @@ internal record DisposableCollectionResolution( string Reference, string TypeFullName) : ConstructorResolution(Reference, TypeFullName, null, Array.Empty<(string name, Resolvable Dependency)>()); +internal abstract record RangeResolution( + IReadOnlyList<(Resolvable, INamedTypeSymbol)> RootResolutions, + DisposalHandling DisposalHandling, + IReadOnlyList ScopedInstanceResolutions) : ResolutionTreeItem; + +internal record ScopeResolution( + IReadOnlyList<(Resolvable, INamedTypeSymbol)> RootResolutions, + DisposalHandling DisposalHandling, + IReadOnlyList ScopedInstanceResolutions) + : RangeResolution(RootResolutions, DisposalHandling, ScopedInstanceResolutions); + internal record ContainerResolution( - Resolvable RootResolution, - ContainerResolutionDisposalHandling DisposalHandling, - IReadOnlyList SingleInstanceResolutions) : Resolvable(RootResolution.Reference, RootResolution.TypeFullName); + IReadOnlyList<(Resolvable, INamedTypeSymbol)> RootResolutions, + DisposalHandling DisposalHandling, + IReadOnlyList ScopedInstanceResolutions, + IReadOnlyList SingleInstanceResolutions, + ScopeResolution DefaultScope) + : RangeResolution(RootResolutions, DisposalHandling, ScopedInstanceResolutions); -internal record ContainerResolutionDisposalHandling( +internal record DisposalHandling( DisposableCollectionResolution DisposableCollection, string DisposedFieldReference, string DisposedLocalReference, diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index d4e79789..b70bd57e 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -21,7 +21,16 @@ public void Execute(GeneratorExecutionContext context) var containerGenerator = new ContainerGenerator(context, wellKnownTypes, diagLogger); var referenceGeneratorFactory = new ReferenceGeneratorFactory(ReferenceGeneratorFactory); var checkDisposalManagement = new CheckTypeProperties(getAllImplementations, typesFromAttributes); - var resolutionTreeFactory = new ResolutionTreeFactory(typeToImplementationMapper, referenceGeneratorFactory, checkDisposalManagement, wellKnownTypes); + var resolutionTreeFactory = new ContainerResolutionBuilder( + typeToImplementationMapper, + referenceGeneratorFactory, + checkDisposalManagement, + wellKnownTypes, + () => new ScopeResolutionBuilder( + wellKnownTypes, + typeToImplementationMapper, + referenceGeneratorFactory, + checkDisposalManagement)); var containerErrorGenerator = new ContainerErrorGenerator(context); var resolutionTreeCreationErrorHarvester = new ResolutionTreeCreationErrorHarvester(); new ExecuteImpl( diff --git a/Main/TypesFromAttributes.cs b/Main/TypesFromAttributes.cs index 2079a8da..3dcdc5a4 100644 --- a/Main/TypesFromAttributes.cs +++ b/Main/TypesFromAttributes.cs @@ -5,6 +5,8 @@ public interface ITypesFromAttributes IReadOnlyList Spy { get; } IReadOnlyList Transient { get; } IReadOnlyList SingleInstance { get; } + IReadOnlyList ScopedInstance { get; } + IReadOnlyList ScopeRoot { get; } } internal class TypesFromAttributes : ITypesFromAttributes @@ -16,6 +18,8 @@ public TypesFromAttributes( Spy = GetTypesFromAttribute(wellKnownTypes.SpyAttribute).ToList(); Transient = GetTypesFromAttribute(wellKnownTypes.TransientAttribute).ToList(); SingleInstance = GetTypesFromAttribute(wellKnownTypes.SingleInstanceAttribute).ToList(); + ScopedInstance = GetTypesFromAttribute(wellKnownTypes.ScopedInstanceAttribute).ToList(); + ScopeRoot = GetTypesFromAttribute(wellKnownTypes.ScopeRootAttribute).ToList(); IEnumerable GetTypesFromAttribute(INamedTypeSymbol attribute) => getAssemblyAttributes .AllAssemblyAttributes @@ -54,4 +58,6 @@ bool CheckValidType(TypedConstant typedConstant, out INamedTypeSymbol type) public IReadOnlyList Spy { get; } public IReadOnlyList Transient { get; } public IReadOnlyList SingleInstance { get; } + public IReadOnlyList ScopedInstance { get; } + public IReadOnlyList ScopeRoot { get; } } \ No newline at end of file diff --git a/Main/WellKnownTypes.cs b/Main/WellKnownTypes.cs index 8f172d9c..234bc56c 100644 --- a/Main/WellKnownTypes.cs +++ b/Main/WellKnownTypes.cs @@ -5,6 +5,8 @@ internal record WellKnownTypes( INamedTypeSymbol SpyAttribute, INamedTypeSymbol TransientAttribute, INamedTypeSymbol SingleInstanceAttribute, + INamedTypeSymbol ScopedInstanceAttribute, + INamedTypeSymbol ScopeRootAttribute, INamedTypeSymbol Disposable, INamedTypeSymbol AsyncDisposable, INamedTypeSymbol Lazy1, @@ -52,10 +54,18 @@ public static bool TryCreate(Compilation compilation, out WellKnownTypes wellKno var singleInstanceAttribute = compilation .GetTypeByMetadataName(typeof(SingleInstanceAttribute).FullName ?? ""); + var scopedInstanceAttribute = compilation + .GetTypeByMetadataName(typeof(ScopedInstanceAttribute).FullName ?? ""); + + var scopeRootAttribute = compilation + .GetTypeByMetadataName(typeof(ScopeRootAttribute).FullName ?? ""); + if (iContainer is null || spyAttribute is null || transientAttribute is null || singleInstanceAttribute is null + || scopedInstanceAttribute is null + || scopeRootAttribute is null || iDisposable is null || iAsyncDisposable is null || lazy1 is null @@ -81,6 +91,8 @@ public static bool TryCreate(Compilation compilation, out WellKnownTypes wellKno SpyAttribute: spyAttribute, TransientAttribute: transientAttribute, SingleInstanceAttribute: singleInstanceAttribute, + ScopedInstanceAttribute: scopedInstanceAttribute, + ScopeRootAttribute: scopeRootAttribute, Disposable: iDisposable, AsyncDisposable: iAsyncDisposable, Lazy1: lazy1, diff --git a/Sample/Program.cs b/Sample/Program.cs index e41f5e7f..9ef8cd2b 100644 --- a/Sample/Program.cs +++ b/Sample/Program.cs @@ -4,7 +4,7 @@ System.Console.WriteLine("Hello, world!"); { using var container = new Container(); - System.Console.WriteLine(container.Resolve().Text); + System.Console.WriteLine(((MrMeeseeks.DIE.IContainer) container).Resolve().Text); } { using var strongInjectContainer = new StrongInjectContainer(); From b65c0a9b23e3c7460aa094f0cbbcd92e0190453f Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sat, 13 Nov 2021 21:50:54 +0100 Subject: [PATCH 020/162] Implemented scoped instances for container --- Main/ContainerGenerator.cs | 83 +++++++++------ Main/ExecuteImpl.cs | 2 +- Main/ResolutionTreeCreationErrorHarvester.cs | 2 + Main/ResolutionTreeFactory.cs | 104 +++++++++++++------ Sample/Container.cs | 2 + Sample/README.md | 1 + SampleChild/Child.cs | 2 +- SampleChild/InternalChild.cs | 4 +- SampleChild/MarkerInterfaces.cs | 2 + 9 files changed, 134 insertions(+), 68 deletions(-) create mode 100644 Sample/README.md diff --git a/Main/ContainerGenerator.cs b/Main/ContainerGenerator.cs index 3870d14e..7c414dba 100644 --- a/Main/ContainerGenerator.cs +++ b/Main/ContainerGenerator.cs @@ -42,32 +42,9 @@ public void Generate(IContainerInfo containerInfo, ContainerResolution container generatedContainer, containerResolution.DisposalHandling, containerResolution); - - foreach (var singleInstanceResolution in containerResolution.SingleInstanceResolutions) - { - generatedContainer = generatedContainer - .AppendLine($"private {singleInstanceResolution.Function.TypeFullName} {singleInstanceResolution.Function.FieldReference};") - .AppendLine($"private {_wellKnownTypes.SemaphoreSlim.FullName()} {singleInstanceResolution.Function.LockReference} = new {_wellKnownTypes.SemaphoreSlim.FullName()}(1);") - .AppendLine($"public {singleInstanceResolution.Function.TypeFullName} {singleInstanceResolution.Function.Reference}()") - .AppendLine($"{{") - .AppendLine($"if (!object.ReferenceEquals({singleInstanceResolution.Function.FieldReference}, null)) return {singleInstanceResolution.Function.FieldReference};") - .AppendLine($"this.{singleInstanceResolution.Function.LockReference}.Wait();") - .AppendLine($"try") - .AppendLine($"{{") - .AppendLine($"if (this.{containerResolution.DisposalHandling.DisposedPropertyReference}) throw new {_wellKnownTypes.ObjectDisposedException}(nameof({containerInfo.Name}));"); - - generatedContainer = GenerateResolutionFunctionContent(generatedContainer, singleInstanceResolution.Dependency); - generatedContainer = generatedContainer - .AppendLine($"this.{singleInstanceResolution.Function.FieldReference} = {singleInstanceResolution.Dependency.Reference};") - .AppendLine($"}}") - .AppendLine($"finally") - .AppendLine($"{{") - .AppendLine($"this.{singleInstanceResolution.Function.LockReference}.Release();") - .AppendLine($"}}") - .AppendLine($"return this.{singleInstanceResolution.Function.FieldReference};") - .AppendLine($"}}"); - } + generatedContainer = containerResolution.SingleInstanceResolutions.Aggregate(generatedContainer, GenerateRangedInstanceFunction); + generatedContainer = containerResolution.ScopedInstanceResolutions.Aggregate(generatedContainer, GenerateRangedInstanceFunction); generatedContainer = containerResolution.RootResolutions.Aggregate(generatedContainer, GenerateResolutionFunction) .AppendLine($"}}") @@ -80,8 +57,7 @@ public void Generate(IContainerInfo containerInfo, ContainerResolution container .SyntaxTree .GetText(); _context.AddSource($"{containerInfo.Namespace}.{containerInfo.Name}.g.cs", containerSource); - - + StringBuilder GenerateContainerDisposalFunction( StringBuilder stringBuilder, DisposalHandling disposalHandling, @@ -96,13 +72,14 @@ StringBuilder GenerateContainerDisposalFunction( .AppendLine($"var {disposalHandling.DisposedLocalReference} = global::System.Threading.Interlocked.Exchange(ref this.{disposalHandling.DisposedFieldReference}, 1);") .AppendLine($"if ({disposalHandling.DisposedLocalReference} != 0) return;"); - foreach (var singleInstanceResolution in containerResolution.SingleInstanceResolutions) - { - stringBuilder = stringBuilder - .AppendLine($"this.{singleInstanceResolution.Function.LockReference}.Wait();"); + stringBuilder = containerResolution.SingleInstanceResolutions.Aggregate( + stringBuilder, + (current, singleInstanceResolution) => current.AppendLine($"this.{singleInstanceResolution.Function.LockReference}.Wait();")); + + stringBuilder = containerResolution.ScopedInstanceResolutions.Aggregate( + stringBuilder, + (current, singleInstanceResolution) => current.AppendLine($"this.{singleInstanceResolution.Function.LockReference}.Wait();")); - } - stringBuilder = stringBuilder .AppendLine($"try") .AppendLine($"{{") @@ -164,6 +141,9 @@ StringBuilder GenerateFields( case SingleInstanceReferenceResolution(var reference, { TypeFullName: {} typeFullName}): stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); break; + case ScopedInstanceReferenceResolution(var reference, { TypeFullName: {} typeFullName}): + stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); + break; case InterfaceResolution(var reference, var typeFullName, Resolvable resolutionBase): stringBuilder = GenerateFields(stringBuilder, resolutionBase); stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); @@ -198,6 +178,9 @@ StringBuilder GenerateResolutions( case SingleInstanceReferenceResolution(var reference, { Reference: {} functionReference}): stringBuilder = stringBuilder.AppendLine($"{reference} = {functionReference}();"); break; + case ScopedInstanceReferenceResolution(var reference, { Reference: {} functionReference}): + stringBuilder = stringBuilder.AppendLine($"{reference} = {functionReference}();"); + break; case InterfaceResolution(var reference, var typeFullName, Resolvable resolutionBase): stringBuilder = GenerateResolutions(stringBuilder, resolutionBase); stringBuilder = stringBuilder.AppendLine( @@ -232,5 +215,39 @@ StringBuilder GenerateResolutions( return stringBuilder; } + + StringBuilder GenerateRangedInstanceFunction(StringBuilder stringBuilder, RangedInstanceBase rangedInstance) + where T : RangedInstanceFunctionBase + { + stringBuilder = stringBuilder + .AppendLine( + $"private {rangedInstance.Function.TypeFullName} {rangedInstance.Function.FieldReference};") + .AppendLine( + $"private {_wellKnownTypes.SemaphoreSlim.FullName()} {rangedInstance.Function.LockReference} = new {_wellKnownTypes.SemaphoreSlim.FullName()}(1);") + .AppendLine( + $"public {rangedInstance.Function.TypeFullName} {rangedInstance.Function.Reference}()") + .AppendLine($"{{") + .AppendLine( + $"if (!object.ReferenceEquals({rangedInstance.Function.FieldReference}, null)) return {rangedInstance.Function.FieldReference};") + .AppendLine($"this.{rangedInstance.Function.LockReference}.Wait();") + .AppendLine($"try") + .AppendLine($"{{") + .AppendLine( + $"if (this.{containerResolution.DisposalHandling.DisposedPropertyReference}) throw new {_wellKnownTypes.ObjectDisposedException}(nameof({containerInfo.Name}));"); + + stringBuilder = GenerateResolutionFunctionContent(stringBuilder, rangedInstance.Dependency); + + stringBuilder = stringBuilder + .AppendLine( + $"this.{rangedInstance.Function.FieldReference} = {rangedInstance.Dependency.Reference};") + .AppendLine($"}}") + .AppendLine($"finally") + .AppendLine($"{{") + .AppendLine($"this.{rangedInstance.Function.LockReference}.Release();") + .AppendLine($"}}") + .AppendLine($"return this.{rangedInstance.Function.FieldReference};") + .AppendLine($"}}"); + return stringBuilder; + } } } \ No newline at end of file diff --git a/Main/ExecuteImpl.cs b/Main/ExecuteImpl.cs index 4c027947..c3f210aa 100644 --- a/Main/ExecuteImpl.cs +++ b/Main/ExecuteImpl.cs @@ -57,7 +57,7 @@ public void Execute() var containerInfo = _containerInfoFactory(namedTypeSymbol); if (containerInfo.IsValid) { - _containerResolutionBuilder.AddCreateFunctions(containerInfo.ResolutionRootTypes); + _containerResolutionBuilder.AddCreateResolveFunctions(containerInfo.ResolutionRootTypes); var containerResolution = _containerResolutionBuilder.Build(); var errorTreeItems = _resolutionTreeCreationErrorHarvester.Harvest(containerResolution); if (errorTreeItems.Any()) diff --git a/Main/ResolutionTreeCreationErrorHarvester.cs b/Main/ResolutionTreeCreationErrorHarvester.cs index 949b640d..4617799b 100644 --- a/Main/ResolutionTreeCreationErrorHarvester.cs +++ b/Main/ResolutionTreeCreationErrorHarvester.cs @@ -19,6 +19,8 @@ static void Inner(ResolutionTreeItem item, ICollection errorTreeI { case SingleInstanceReferenceResolution: break; + case ScopedInstanceReferenceResolution: + break; case ContainerResolution containerResolution: foreach (var singleInstance in containerResolution.SingleInstanceResolutions) Inner(singleInstance.Dependency, errorTreeItems); diff --git a/Main/ResolutionTreeFactory.cs b/Main/ResolutionTreeFactory.cs index a85f525d..80421bc2 100644 --- a/Main/ResolutionTreeFactory.cs +++ b/Main/ResolutionTreeFactory.cs @@ -2,14 +2,14 @@ namespace MrMeeseeks.DIE; internal interface IContainerResolutionBuilder { - void AddCreateFunctions(IReadOnlyList rootTypes); + void AddCreateResolveFunctions(IReadOnlyList rootTypes); ContainerResolution Build(); } internal interface IScopeResolutionBuilder { - void AddCreateFunction(INamedTypeSymbol rootType); + void AddCreateResolveFunction(INamedTypeSymbol rootType); ScopeResolution Build(); } @@ -20,11 +20,11 @@ internal abstract class RangeResolutionBaseBuilder protected readonly ITypeToImplementationsMapper TypeToImplementationsMapper; protected readonly IReferenceGeneratorFactory ReferenceGeneratorFactory; protected readonly ICheckTypeProperties CheckTypeProperties; - - private readonly IDictionary - _containerScopedInstanceReferenceResolutions = + + protected readonly IReferenceGenerator RootReferenceGenerator; + protected readonly IDictionary _scopedInstanceReferenceResolutions = new Dictionary(SymbolEqualityComparer.Default); - private readonly Queue _scopedInstanceResolutionsQueue = new(); + protected readonly Queue _scopedInstanceResolutionsQueue = new(); protected readonly List ScopedInstances = new (); @@ -39,6 +39,8 @@ protected RangeResolutionBaseBuilder( TypeToImplementationsMapper = typeToImplementationsMapper; ReferenceGeneratorFactory = referenceGeneratorFactory; CheckTypeProperties = checkTypeProperties; + + RootReferenceGenerator = referenceGeneratorFactory.Create(); } protected abstract SingleInstanceReferenceResolution CreateSingleInstanceReferenceResolution( @@ -176,7 +178,7 @@ protected Resolvable CreateConstructorResolution( IReferenceGenerator referenceGenerator, IReadOnlyList<(ITypeSymbol Type, FuncParameterResolution Resolution)> readOnlyList, DisposableCollectionResolution disposableCollectionResolution, - bool skipSingleInstanceCheck = false) + bool skipRangedInstanceCheck = false) { var implementations = TypeToImplementationsMapper .Map(typeSymbol); @@ -192,8 +194,11 @@ protected Resolvable CreateConstructorResolution( }); } - if (!skipSingleInstanceCheck && CheckTypeProperties.ShouldBeSingleInstance(implementationType)) + if (!skipRangedInstanceCheck && CheckTypeProperties.ShouldBeSingleInstance(implementationType)) return CreateSingleInstanceReferenceResolution(implementationType, referenceGenerator); + + if (!skipRangedInstanceCheck && CheckTypeProperties.ShouldBeScopedInstance(implementationType)) + return CreateScopedInstanceReferenceResolution(implementationType, referenceGenerator); if (implementationType.Constructors.SingleOrDefault() is not { } constructor) { @@ -234,6 +239,29 @@ protected Resolvable CreateConstructorResolution( .ToList())); } + protected ScopedInstanceReferenceResolution CreateScopedInstanceReferenceResolution( + INamedTypeSymbol implementationType, + IReferenceGenerator referenceGenerator) + { + if (!_scopedInstanceReferenceResolutions.TryGetValue( + implementationType, + out ScopedInstanceFunction function)) + { + function = new ScopedInstanceFunction( + RootReferenceGenerator.Generate("GetScopedInstance", implementationType), + implementationType.FullName(), + implementationType, + RootReferenceGenerator.Generate("_scopedInstanceField", implementationType), + RootReferenceGenerator.Generate("_scopedInstanceLock")); + _scopedInstanceReferenceResolutions[implementationType] = function; + _scopedInstanceResolutionsQueue.Enqueue(function); + } + + return new ScopedInstanceReferenceResolution( + referenceGenerator.Generate(implementationType), + function); + } + private static DisposableCollectionResolution? ImplementsIDisposable( INamedTypeSymbol type, WellKnownTypes wellKnownTypes, @@ -249,8 +277,7 @@ internal class ContainerResolutionBuilder : RangeResolutionBaseBuilder, IContain private readonly IDictionary _singleInstanceReferenceResolutions = new Dictionary(SymbolEqualityComparer.Default); private readonly Queue _singleInstanceResolutionsQueue = new(); - - private readonly IReferenceGenerator _singleInstanceReferenceGenerator; + private readonly List<(Resolvable, INamedTypeSymbol)> _rootResolutions = new (); private readonly List _singleInstances = new (); private readonly DisposableCollectionResolution _disposableCollectionResolution; @@ -264,14 +291,13 @@ public ContainerResolutionBuilder( Func scopeResolutionBuilderFactory) : base(wellKnownTypes, typeToImplementationsMapper, referenceGeneratorFactory, checkTypeProperties) { - _singleInstanceReferenceGenerator = referenceGeneratorFactory.Create(); _disposableCollectionResolution = new DisposableCollectionResolution( - _singleInstanceReferenceGenerator.Generate(WellKnownTypes.ConcurrentBagOfDisposable), + RootReferenceGenerator.Generate(WellKnownTypes.ConcurrentBagOfDisposable), WellKnownTypes.ConcurrentBagOfDisposable.FullName()); _scopeResolutionBuilder = scopeResolutionBuilderFactory(); } - public void AddCreateFunctions(IReadOnlyList rootTypes) + public void AddCreateResolveFunctions(IReadOnlyList rootTypes) { foreach (var typeSymbol in rootTypes) _rootResolutions.Add((Create( @@ -281,16 +307,31 @@ public void AddCreateFunctions(IReadOnlyList rootTypes) _disposableCollectionResolution), typeSymbol)); - while (_singleInstanceResolutionsQueue.Any()) + while (_singleInstanceResolutionsQueue.Any() || _scopedInstanceResolutionsQueue.Any()) { - var singleInstanceFunction = _singleInstanceResolutionsQueue.Dequeue(); - var resolvable = CreateConstructorResolution( - singleInstanceFunction.Type, - ReferenceGeneratorFactory.Create(), - Array.Empty<(ITypeSymbol Type, FuncParameterResolution Resolution)>(), - _disposableCollectionResolution, - true); - _singleInstances.Add(new SingleInstance(singleInstanceFunction, resolvable)); + while (_singleInstanceResolutionsQueue.Any()) + { + var singleInstanceFunction = _singleInstanceResolutionsQueue.Dequeue(); + var resolvable = CreateConstructorResolution( + singleInstanceFunction.Type, + ReferenceGeneratorFactory.Create(), + Array.Empty<(ITypeSymbol Type, FuncParameterResolution Resolution)>(), + _disposableCollectionResolution, + true); + _singleInstances.Add(new SingleInstance(singleInstanceFunction, resolvable)); + } + + while (_scopedInstanceResolutionsQueue.Any()) + { + var scopedInstanceFunction = _scopedInstanceResolutionsQueue.Dequeue(); + var resolvable = CreateConstructorResolution( + scopedInstanceFunction.Type, + ReferenceGeneratorFactory.Create(), + Array.Empty<(ITypeSymbol Type, FuncParameterResolution Resolution)>(), + _disposableCollectionResolution, + true); + ScopedInstances.Add(new ScopedInstance(scopedInstanceFunction, resolvable)); + } } } @@ -303,11 +344,11 @@ protected override SingleInstanceReferenceResolution CreateSingleInstanceReferen out SingleInstanceFunction function)) { function = new SingleInstanceFunction( - _singleInstanceReferenceGenerator.Generate("GetSingleInstance", implementationType), + RootReferenceGenerator.Generate("GetSingleInstance", implementationType), implementationType.FullName(), implementationType, - _singleInstanceReferenceGenerator.Generate("_singleInstanceField", implementationType), - _singleInstanceReferenceGenerator.Generate("_singleInstanceLock")); + RootReferenceGenerator.Generate("_singleInstanceField", implementationType), + RootReferenceGenerator.Generate("_singleInstanceLock")); _singleInstanceReferenceResolutions[implementationType] = function; _singleInstanceResolutionsQueue.Enqueue(function); } @@ -321,10 +362,10 @@ public ContainerResolution Build() => new(_rootResolutions, new DisposalHandling( _disposableCollectionResolution, - _singleInstanceReferenceGenerator.Generate("_disposed"), - _singleInstanceReferenceGenerator.Generate("disposed"), - _singleInstanceReferenceGenerator.Generate("Disposed"), - _singleInstanceReferenceGenerator.Generate("disposable")), + RootReferenceGenerator.Generate("_disposed"), + RootReferenceGenerator.Generate("disposed"), + RootReferenceGenerator.Generate("Disposed"), + RootReferenceGenerator.Generate("disposable")), ScopedInstances, _singleInstances, _scopeResolutionBuilder.Build()); @@ -348,13 +389,14 @@ public ScopeResolutionBuilder( WellKnownTypes.ConcurrentBagOfDisposable.FullName()); } - protected override SingleInstanceReferenceResolution CreateSingleInstanceReferenceResolution(INamedTypeSymbol implementationType, + protected override SingleInstanceReferenceResolution CreateSingleInstanceReferenceResolution( + INamedTypeSymbol implementationType, IReferenceGenerator referenceGenerator) { throw new NotImplementedException(); } - public void AddCreateFunction(INamedTypeSymbol rootType) + public void AddCreateResolveFunction(INamedTypeSymbol rootType) { throw new NotImplementedException(); } diff --git a/Sample/Container.cs b/Sample/Container.cs index 36402598..13307e9f 100644 --- a/Sample/Container.cs +++ b/Sample/Container.cs @@ -4,6 +4,8 @@ [assembly:Spy(typeof(IPublicTypeReport), typeof(IInternalTypeReport))] [assembly:SingleInstance(typeof(ISingleInstance))] +[assembly:ScopedInstance(typeof(IScopedInstance))] +[assembly:ScopeRoot(typeof(IScopeRoot))] [assembly:Transient(typeof(ITransient))] namespace MrMeeseeks.DIE.Sample; diff --git a/Sample/README.md b/Sample/README.md new file mode 100644 index 00000000..10b82646 --- /dev/null +++ b/Sample/README.md @@ -0,0 +1 @@ +**DIE** is a recursive acronym stands for **D**ependency **I**njection DI**E** \ No newline at end of file diff --git a/SampleChild/Child.cs b/SampleChild/Child.cs index 6abc42f4..c73605cc 100644 --- a/SampleChild/Child.cs +++ b/SampleChild/Child.cs @@ -5,7 +5,7 @@ namespace MrMeeseeks.DIE.SampleChild; public interface IChild { } -public class Child : IChild, IDisposable, ISingleInstance +public class Child : IChild, IDisposable, IScopeRoot { public Child( IInternalChild innerChild){} diff --git a/SampleChild/InternalChild.cs b/SampleChild/InternalChild.cs index e429f68b..84037cfe 100644 --- a/SampleChild/InternalChild.cs +++ b/SampleChild/InternalChild.cs @@ -4,7 +4,7 @@ namespace MrMeeseeks.DIE.SampleChild; public interface IInternalChild {} -internal class InternalChild : IInternalChild, IDisposable +internal class InternalChild : IInternalChild, IDisposable, IScopedInstance { public InternalChild(Lazy yetAnotherInternalChild) { @@ -18,7 +18,7 @@ public void Dispose() public interface IYetAnotherInternalChild {} -internal class YetAnotherInternalChild : IYetAnotherInternalChild, IDisposable +internal class YetAnotherInternalChild : IYetAnotherInternalChild, IDisposable, IScopedInstance { public void Dispose() { diff --git a/SampleChild/MarkerInterfaces.cs b/SampleChild/MarkerInterfaces.cs index ed59627b..7295b29c 100644 --- a/SampleChild/MarkerInterfaces.cs +++ b/SampleChild/MarkerInterfaces.cs @@ -1,4 +1,6 @@ namespace MrMeeseeks.DIE.SampleChild; public interface ISingleInstance { } +public interface IScopedInstance { } +public interface IScopeRoot { } public interface ITransient { } \ No newline at end of file From b14cc9cff55be5eecdb9396be3cbb42be8c97a9c Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sun, 14 Nov 2021 20:14:44 +0100 Subject: [PATCH 021/162] Implemented scopes --- Main/ContainerGenerator.cs | 95 +++-- Main/ContainerInfo.cs | 3 + Main/ExecuteImpl.cs | 11 +- Main/ResolutionTreeCreationErrorHarvester.cs | 22 +- Main/ResolutionTreeFactory.cs | 346 +++++++++++++------ Main/ResolutionTreeItem.cs | 85 +++-- Main/SourceGenerator.cs | 25 +- Sample/StrongInjectContainer.cs | 2 + SampleChild/InternalChild.cs | 25 +- 9 files changed, 396 insertions(+), 218 deletions(-) diff --git a/Main/ContainerGenerator.cs b/Main/ContainerGenerator.cs index 7c414dba..ae13b1ae 100644 --- a/Main/ContainerGenerator.cs +++ b/Main/ContainerGenerator.cs @@ -38,15 +38,28 @@ public void Generate(IContainerInfo containerInfo, ContainerResolution container .AppendLine($"partial class {containerInfo.Name} : {_wellKnownTypes.Disposable.FullName()}") .AppendLine($"{{"); - generatedContainer = GenerateContainerDisposalFunction( + generatedContainer = GenerateResolutionRange( generatedContainer, - containerResolution.DisposalHandling, containerResolution); - generatedContainer = containerResolution.SingleInstanceResolutions.Aggregate(generatedContainer, GenerateRangedInstanceFunction); - generatedContainer = containerResolution.ScopedInstanceResolutions.Aggregate(generatedContainer, GenerateRangedInstanceFunction); + var defaultScopeResolution = containerResolution.DefaultScope; + generatedContainer = generatedContainer + .AppendLine($"internal partial class {defaultScopeResolution.Name} : {_wellKnownTypes.Disposable.FullName()}") + .AppendLine($"{{") + .AppendLine($"private readonly {containerInfo.FullName} {defaultScopeResolution.ContainerReference};") + .AppendLine($"internal {defaultScopeResolution.Name}({containerInfo.FullName} {defaultScopeResolution.ContainerParameterReference})") + .AppendLine($"{{") + .AppendLine($"{defaultScopeResolution.ContainerReference} = {defaultScopeResolution.ContainerParameterReference};") + .AppendLine($"}}"); - generatedContainer = containerResolution.RootResolutions.Aggregate(generatedContainer, GenerateResolutionFunction) + generatedContainer = GenerateResolutionRange( + generatedContainer, + defaultScopeResolution); + + generatedContainer = generatedContainer + .AppendLine($"}}"); + + generatedContainer = generatedContainer .AppendLine($"}}") .AppendLine($"}}"); @@ -57,12 +70,25 @@ public void Generate(IContainerInfo containerInfo, ContainerResolution container .SyntaxTree .GetText(); _context.AddSource($"{containerInfo.Namespace}.{containerInfo.Name}.g.cs", containerSource); + + StringBuilder GenerateResolutionRange( + StringBuilder stringBuilder, + RangeResolution rangeResolution) + { + stringBuilder = GenerateContainerDisposalFunction( + stringBuilder, + rangeResolution); + + stringBuilder = rangeResolution.AllRangedInstances.Aggregate(stringBuilder, GenerateRangedInstanceFunction); + + return rangeResolution.RootResolutions.Aggregate(stringBuilder, GenerateResolutionFunction); + } StringBuilder GenerateContainerDisposalFunction( StringBuilder stringBuilder, - DisposalHandling disposalHandling, - ContainerResolution containerResolution) + RangeResolution rangeResolution) { + var disposalHandling = rangeResolution.DisposalHandling; stringBuilder = stringBuilder .AppendLine($"private {disposalHandling.DisposableCollection.TypeFullName} {disposalHandling.DisposableCollection.Reference} = new {disposalHandling.DisposableCollection.TypeFullName}();") .AppendLine($"private int {disposalHandling.DisposedFieldReference} = 0;") @@ -72,11 +98,7 @@ StringBuilder GenerateContainerDisposalFunction( .AppendLine($"var {disposalHandling.DisposedLocalReference} = global::System.Threading.Interlocked.Exchange(ref this.{disposalHandling.DisposedFieldReference}, 1);") .AppendLine($"if ({disposalHandling.DisposedLocalReference} != 0) return;"); - stringBuilder = containerResolution.SingleInstanceResolutions.Aggregate( - stringBuilder, - (current, singleInstanceResolution) => current.AppendLine($"this.{singleInstanceResolution.Function.LockReference}.Wait();")); - - stringBuilder = containerResolution.ScopedInstanceResolutions.Aggregate( + stringBuilder = rangeResolution.AllRangedInstances.Aggregate( stringBuilder, (current, singleInstanceResolution) => current.AppendLine($"this.{singleInstanceResolution.Function.LockReference}.Wait();")); @@ -98,12 +120,10 @@ StringBuilder GenerateContainerDisposalFunction( .AppendLine($"finally") .AppendLine($"{{"); - foreach (var singleInstanceResolution in containerResolution.SingleInstanceResolutions) - { - stringBuilder = stringBuilder - .AppendLine($"this.{singleInstanceResolution.Function.LockReference}.Release();"); - } - + stringBuilder = rangeResolution.AllRangedInstances.Aggregate( + stringBuilder, + (current, singleInstanceResolution) => current.AppendLine($"this.{singleInstanceResolution.Function.LockReference}.Release();")); + return stringBuilder .AppendLine($"}}") .AppendLine($"}}"); @@ -111,16 +131,15 @@ StringBuilder GenerateContainerDisposalFunction( StringBuilder GenerateResolutionFunction( StringBuilder stringBuilder, - (Resolvable, INamedTypeSymbol) resolution) + RootResolutionFunction resolution) { - var (resolvable, type) = resolution; stringBuilder = stringBuilder - .AppendLine($"{resolvable.TypeFullName} {_wellKnownTypes.Container.Construct(type).FullName()}.Resolve()") + .AppendLine($"{resolution.AccessModifier} {resolution.TypeFullName} {resolution.ExplicitImplementationFullName}{(string.IsNullOrWhiteSpace(resolution.ExplicitImplementationFullName) ? "" : ".")}{resolution.Reference}()") .AppendLine($"{{") - .AppendLine($"if (this.{containerResolution.DisposalHandling.DisposedPropertyReference}) throw new {_wellKnownTypes.ObjectDisposedException}(nameof({containerInfo.Name}));"); + .AppendLine($"if (this.{resolution.DisposalHandling.DisposedPropertyReference}) throw new {_wellKnownTypes.ObjectDisposedException}(nameof({resolution.RangeName}));"); - return GenerateResolutionFunctionContent(stringBuilder, resolvable) - .AppendLine($"return {resolvable.Reference};") + return GenerateResolutionFunctionContent(stringBuilder, resolution.Resolvable) + .AppendLine($"return {resolution.Resolvable.Reference};") .AppendLine($"}}"); } @@ -138,11 +157,10 @@ StringBuilder GenerateFields( { switch (resolution) { - case SingleInstanceReferenceResolution(var reference, { TypeFullName: {} typeFullName}): - stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); - break; - case ScopedInstanceReferenceResolution(var reference, { TypeFullName: {} typeFullName}): - stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); + case ScopeRootResolution(var reference, var typeFullName, var scopeReference, var scopeTypeFullName, _, _, _): + stringBuilder = stringBuilder + .AppendLine($"{scopeTypeFullName} {scopeReference};") + .AppendLine($"{typeFullName} {reference};"); break; case InterfaceResolution(var reference, var typeFullName, Resolvable resolutionBase): stringBuilder = GenerateFields(stringBuilder, resolutionBase); @@ -162,6 +180,9 @@ StringBuilder GenerateFields( stringBuilder = items.OfType().Aggregate(stringBuilder, GenerateFields); stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); break; + case var (reference, typeFullName): + stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); + break; default: throw new Exception("Unexpected case or not implemented."); } @@ -175,11 +196,14 @@ StringBuilder GenerateResolutions( { switch (resolution) { - case SingleInstanceReferenceResolution(var reference, { Reference: {} functionReference}): - stringBuilder = stringBuilder.AppendLine($"{reference} = {functionReference}();"); + case ScopeRootResolution(var reference, var typeFullName, var scopeReference, var scopeTypeFullName, var singleInstanceScopeReference, var (disposableCollectionReference, _, _, _), var (createFunctionReference, _, _)): + stringBuilder = stringBuilder + .AppendLine($"{scopeReference} = new {scopeTypeFullName}({singleInstanceScopeReference});") + .AppendLine($"{disposableCollectionReference}.Add(({_wellKnownTypes.Disposable.FullName()}) {scopeReference});") + .AppendLine($"{reference} = ({typeFullName}) {scopeReference}.{createFunctionReference}();"); break; - case ScopedInstanceReferenceResolution(var reference, { Reference: {} functionReference}): - stringBuilder = stringBuilder.AppendLine($"{reference} = {functionReference}();"); + case RangedInstanceReferenceResolution(var reference, { Reference: {} functionReference}, var owningObjectReference): + stringBuilder = stringBuilder.AppendLine($"{reference} = {owningObjectReference}.{functionReference}();"); break; case InterfaceResolution(var reference, var typeFullName, Resolvable resolutionBase): stringBuilder = GenerateResolutions(stringBuilder, resolutionBase); @@ -216,8 +240,7 @@ StringBuilder GenerateResolutions( return stringBuilder; } - StringBuilder GenerateRangedInstanceFunction(StringBuilder stringBuilder, RangedInstanceBase rangedInstance) - where T : RangedInstanceFunctionBase + StringBuilder GenerateRangedInstanceFunction(StringBuilder stringBuilder, RangedInstance rangedInstance) { stringBuilder = stringBuilder .AppendLine( @@ -233,7 +256,7 @@ StringBuilder GenerateRangedInstanceFunction(StringBuilder stringBuilder, Ran .AppendLine($"try") .AppendLine($"{{") .AppendLine( - $"if (this.{containerResolution.DisposalHandling.DisposedPropertyReference}) throw new {_wellKnownTypes.ObjectDisposedException}(nameof({containerInfo.Name}));"); + $"if (this.{rangedInstance.DisposalHandling.DisposedPropertyReference}) throw new {_wellKnownTypes.ObjectDisposedException}(nameof({rangedInstance.DisposalHandling.RangeName}));"); stringBuilder = GenerateResolutionFunctionContent(stringBuilder, rangedInstance.Dependency); diff --git a/Main/ContainerInfo.cs b/Main/ContainerInfo.cs index 10be438d..44372bea 100644 --- a/Main/ContainerInfo.cs +++ b/Main/ContainerInfo.cs @@ -4,6 +4,7 @@ public interface IContainerInfo { string Name { get; } string Namespace { get; } + string FullName { get; } bool IsValid { get; } IReadOnlyList ResolutionRootTypes { get; } } @@ -19,6 +20,7 @@ public ContainerInfo( { Name = containerClass.Name; Namespace = containerClass.ContainingNamespace.FullName(); + FullName = containerClass.FullName(); ResolutionRootTypes = containerClass .AllInterfaces @@ -40,6 +42,7 @@ public ContainerInfo( public string Name { get; } public string Namespace { get; } + public string FullName { get; } public bool IsValid { get; } public IReadOnlyList ResolutionRootTypes { get; } } \ No newline at end of file diff --git a/Main/ExecuteImpl.cs b/Main/ExecuteImpl.cs index c3f210aa..cec9bbaa 100644 --- a/Main/ExecuteImpl.cs +++ b/Main/ExecuteImpl.cs @@ -13,7 +13,7 @@ internal class ExecuteImpl : IExecute private readonly WellKnownTypes _wellKnownTypes; private readonly IContainerGenerator _containerGenerator; private readonly IContainerErrorGenerator _containerErrorGenerator; - private readonly IContainerResolutionBuilder _containerResolutionBuilder; + private readonly Func _containerResolutionBuilderFactory; private readonly IResolutionTreeCreationErrorHarvester _resolutionTreeCreationErrorHarvester; private readonly Func _containerInfoFactory; private readonly IDiagLogger _diagLogger; @@ -23,7 +23,7 @@ public ExecuteImpl( WellKnownTypes wellKnownTypes, IContainerGenerator containerGenerator, IContainerErrorGenerator containerErrorGenerator, - IContainerResolutionBuilder containerResolutionBuilder, + Func containerResolutionBuilderFactory, IResolutionTreeCreationErrorHarvester resolutionTreeCreationErrorHarvester, Func containerInfoFactory, IDiagLogger diagLogger) @@ -32,7 +32,7 @@ public ExecuteImpl( _wellKnownTypes = wellKnownTypes; _containerGenerator = containerGenerator; _containerErrorGenerator = containerErrorGenerator; - _containerResolutionBuilder = containerResolutionBuilder; + _containerResolutionBuilderFactory = containerResolutionBuilderFactory; _resolutionTreeCreationErrorHarvester = resolutionTreeCreationErrorHarvester; _containerInfoFactory = containerInfoFactory; _diagLogger = diagLogger; @@ -57,8 +57,9 @@ public void Execute() var containerInfo = _containerInfoFactory(namedTypeSymbol); if (containerInfo.IsValid) { - _containerResolutionBuilder.AddCreateResolveFunctions(containerInfo.ResolutionRootTypes); - var containerResolution = _containerResolutionBuilder.Build(); + var containerResolutionBuilder = _containerResolutionBuilderFactory(containerInfo); + containerResolutionBuilder.AddCreateResolveFunctions(containerInfo.ResolutionRootTypes); + var containerResolution = containerResolutionBuilder.Build(); var errorTreeItems = _resolutionTreeCreationErrorHarvester.Harvest(containerResolution); if (errorTreeItems.Any()) _containerErrorGenerator.Generate(containerInfo, errorTreeItems); diff --git a/Main/ResolutionTreeCreationErrorHarvester.cs b/Main/ResolutionTreeCreationErrorHarvester.cs index 4617799b..db6386be 100644 --- a/Main/ResolutionTreeCreationErrorHarvester.cs +++ b/Main/ResolutionTreeCreationErrorHarvester.cs @@ -17,23 +17,19 @@ static void Inner(ResolutionTreeItem item, ICollection errorTreeI { switch (item) { - case SingleInstanceReferenceResolution: + case RootResolutionFunction: break; - case ScopedInstanceReferenceResolution: + case RangedInstanceReferenceResolution: break; - case ContainerResolution containerResolution: - foreach (var singleInstance in containerResolution.SingleInstanceResolutions) + case ScopeRootFunction: + break; + case ScopeRootResolution: + break; + case RangeResolution containerResolution: + foreach (var singleInstance in containerResolution.AllRangedInstances) Inner(singleInstance.Dependency, errorTreeItems); - foreach (var scopedInstance in containerResolution.ScopedInstanceResolutions) - Inner(scopedInstance.Dependency, errorTreeItems); foreach (var rootResolution in containerResolution.RootResolutions) - Inner(rootResolution.Item1, errorTreeItems); - break; - case ScopeResolution scopeResolution: - foreach (var scopedInstance in scopeResolution.ScopedInstanceResolutions) - Inner(scopedInstance.Dependency, errorTreeItems); - foreach (var rootResolution in scopeResolution.RootResolutions) - Inner(rootResolution.Item1, errorTreeItems); + Inner(rootResolution, errorTreeItems); break; case ErrorTreeItem errorTreeItem: errorTreeItems.Add(errorTreeItem); diff --git a/Main/ResolutionTreeFactory.cs b/Main/ResolutionTreeFactory.cs index 80421bc2..53617870 100644 --- a/Main/ResolutionTreeFactory.cs +++ b/Main/ResolutionTreeFactory.cs @@ -4,12 +4,25 @@ internal interface IContainerResolutionBuilder { void AddCreateResolveFunctions(IReadOnlyList rootTypes); + RangedInstanceReferenceResolution CreateSingleInstanceReferenceResolution( + INamedTypeSymbol type, + IReferenceGenerator referenceGenerator, + string containerReference); + ContainerResolution Build(); } internal interface IScopeResolutionBuilder { - void AddCreateResolveFunction(INamedTypeSymbol rootType); + bool HasWorkToDo { get; } + + ScopeRootResolution AddCreateResolveFunction( + INamedTypeSymbol rootType, + IReferenceGenerator referenceGenerator, + string singleInstanceScopeReference, + DisposableCollectionResolution disposableCollectionResolution); + + void DoWork(); ScopeResolution Build(); } @@ -22,14 +35,20 @@ internal abstract class RangeResolutionBaseBuilder protected readonly ICheckTypeProperties CheckTypeProperties; protected readonly IReferenceGenerator RootReferenceGenerator; - protected readonly IDictionary _scopedInstanceReferenceResolutions = - new Dictionary(SymbolEqualityComparer.Default); - protected readonly Queue _scopedInstanceResolutionsQueue = new(); + protected readonly IDictionary ScopedInstanceReferenceResolutions = + new Dictionary(SymbolEqualityComparer.Default); + protected readonly Queue ScopedInstanceResolutionsQueue = new(); - protected readonly List ScopedInstances = new (); - + protected readonly List ScopedInstances = new (); + protected readonly DisposableCollectionResolution DisposableCollectionResolution; + protected readonly DisposalHandling DisposalHandling; + protected readonly string Name; protected RangeResolutionBaseBuilder( + // parameters + (string, bool) name, + + // dependencies WellKnownTypes wellKnownTypes, ITypeToImplementationsMapper typeToImplementationsMapper, IReferenceGeneratorFactory referenceGeneratorFactory, @@ -41,17 +60,33 @@ protected RangeResolutionBaseBuilder( CheckTypeProperties = checkTypeProperties; RootReferenceGenerator = referenceGeneratorFactory.Create(); + DisposableCollectionResolution = new DisposableCollectionResolution( + RootReferenceGenerator.Generate(WellKnownTypes.ConcurrentBagOfDisposable), + WellKnownTypes.ConcurrentBagOfDisposable.FullName()); + + Name = name.Item2 ? RootReferenceGenerator.Generate(name.Item1) : name.Item1; + DisposalHandling = new DisposalHandling( + DisposableCollectionResolution, + Name, + RootReferenceGenerator.Generate("_disposed"), + RootReferenceGenerator.Generate("disposed"), + RootReferenceGenerator.Generate("Disposed"), + RootReferenceGenerator.Generate("disposable")); } - protected abstract SingleInstanceReferenceResolution CreateSingleInstanceReferenceResolution( + protected abstract RangedInstanceReferenceResolution CreateSingleInstanceReferenceResolution( INamedTypeSymbol implementationType, IReferenceGenerator referenceGenerator); + + protected abstract ScopeRootResolution CreateScopeRootResolution( + INamedTypeSymbol rootType, + IReferenceGenerator referenceGenerator, + DisposableCollectionResolution disposableCollectionResolution); protected Resolvable Create( ITypeSymbol type, IReferenceGenerator referenceGenerator, - IReadOnlyList<(ITypeSymbol Type, FuncParameterResolution Resolution)> currentFuncParameters, - DisposableCollectionResolution disposableCollectionResolution) + IReadOnlyList<(ITypeSymbol Type, FuncParameterResolution Resolution)> currentFuncParameters) { if (currentFuncParameters.FirstOrDefault(t => SymbolEqualityComparer.Default.Equals(t.Type.OriginalDefinition, type.OriginalDefinition)) is { Type: not null, Resolution: not null } funcParameter) { @@ -74,12 +109,11 @@ protected Resolvable Create( var dependency = Create( genericType, ReferenceGeneratorFactory.Create(), - Array.Empty<(ITypeSymbol Type, FuncParameterResolution Resolution)>(), - disposableCollectionResolution); + Array.Empty<(ITypeSymbol Type, FuncParameterResolution Resolution)>()); return new ConstructorResolution( referenceGenerator.Generate(namedTypeSymbol), namedTypeSymbol.FullName(), - ImplementsIDisposable(namedTypeSymbol, WellKnownTypes, disposableCollectionResolution, CheckTypeProperties), + ImplementsIDisposable(namedTypeSymbol, WellKnownTypes, DisposableCollectionResolution, CheckTypeProperties), new ReadOnlyCollection<(string Name, Resolvable Dependency)>( new List<(string Name, Resolvable Dependency)> { @@ -114,7 +148,7 @@ protected Resolvable Create( var itemFullName = itemType.FullName(); var items = TypeToImplementationsMapper .Map(itemType) - .Select(i => Create(i, referenceGenerator, currentFuncParameters, disposableCollectionResolution)) + .Select(i => Create(i, referenceGenerator, currentFuncParameters)) .ToList(); return new CollectionResolution( referenceGenerator.Generate(type), @@ -140,11 +174,11 @@ protected Resolvable Create( return new InterfaceResolution( referenceGenerator.Generate(type), type.FullName(), - Create(implementationType, referenceGenerator, currentFuncParameters, disposableCollectionResolution)); + Create(implementationType, referenceGenerator, currentFuncParameters)); } if (type.TypeKind == TypeKind.Class) - return CreateConstructorResolution(type, referenceGenerator, currentFuncParameters, disposableCollectionResolution); + return CreateConstructorResolution(type, referenceGenerator, currentFuncParameters); if (type.TypeKind == TypeKind.Delegate && type.FullName().StartsWith("global::System.Func<") @@ -161,8 +195,7 @@ protected Resolvable Create( var dependency = Create( returnType, innerReferenceGenerator, - parameterTypes, - disposableCollectionResolution); + parameterTypes); return new FuncResolution( referenceGenerator.Generate(type), type.FullName(), @@ -177,8 +210,8 @@ protected Resolvable CreateConstructorResolution( ITypeSymbol typeSymbol, IReferenceGenerator referenceGenerator, IReadOnlyList<(ITypeSymbol Type, FuncParameterResolution Resolution)> readOnlyList, - DisposableCollectionResolution disposableCollectionResolution, - bool skipRangedInstanceCheck = false) + bool skipRangedInstanceCheck = false, + bool skipScopeRootCheck = false) { var implementations = TypeToImplementationsMapper .Map(typeSymbol); @@ -196,6 +229,9 @@ protected Resolvable CreateConstructorResolution( if (!skipRangedInstanceCheck && CheckTypeProperties.ShouldBeSingleInstance(implementationType)) return CreateSingleInstanceReferenceResolution(implementationType, referenceGenerator); + + if (!skipScopeRootCheck && CheckTypeProperties.ShouldBeScopeRoot(implementationType)) + return CreateScopeRootResolution(implementationType, referenceGenerator, DisposableCollectionResolution); if (!skipRangedInstanceCheck && CheckTypeProperties.ShouldBeScopedInstance(implementationType)) return CreateScopedInstanceReferenceResolution(implementationType, referenceGenerator); @@ -216,7 +252,10 @@ protected Resolvable CreateConstructorResolution( return new ConstructorResolution( referenceGenerator.Generate(implementationType), implementationType.FullName(), - ImplementsIDisposable(implementationType, WellKnownTypes, disposableCollectionResolution, + ImplementsIDisposable( + implementationType, + WellKnownTypes, + DisposableCollectionResolution, CheckTypeProperties), new ReadOnlyCollection<(string Name, Resolvable Dependency)>(constructor .Parameters @@ -233,33 +272,33 @@ protected Resolvable CreateConstructorResolution( p.Name, Create(parameterType, referenceGenerator, - readOnlyList, - disposableCollectionResolution)); + readOnlyList)); }) .ToList())); } - protected ScopedInstanceReferenceResolution CreateScopedInstanceReferenceResolution( + protected RangedInstanceReferenceResolution CreateScopedInstanceReferenceResolution( INamedTypeSymbol implementationType, IReferenceGenerator referenceGenerator) { - if (!_scopedInstanceReferenceResolutions.TryGetValue( + if (!ScopedInstanceReferenceResolutions.TryGetValue( implementationType, - out ScopedInstanceFunction function)) + out RangedInstanceFunction function)) { - function = new ScopedInstanceFunction( + function = new RangedInstanceFunction( RootReferenceGenerator.Generate("GetScopedInstance", implementationType), implementationType.FullName(), implementationType, RootReferenceGenerator.Generate("_scopedInstanceField", implementationType), RootReferenceGenerator.Generate("_scopedInstanceLock")); - _scopedInstanceReferenceResolutions[implementationType] = function; - _scopedInstanceResolutionsQueue.Enqueue(function); + ScopedInstanceReferenceResolutions[implementationType] = function; + ScopedInstanceResolutionsQueue.Enqueue(function); } - return new ScopedInstanceReferenceResolution( + return new RangedInstanceReferenceResolution( referenceGenerator.Generate(implementationType), - function); + function, + "this"); } private static DisposableCollectionResolution? ImplementsIDisposable( @@ -274,40 +313,86 @@ protected ScopedInstanceReferenceResolution CreateScopedInstanceReferenceResolut internal class ContainerResolutionBuilder : RangeResolutionBaseBuilder, IContainerResolutionBuilder { - private readonly IDictionary _singleInstanceReferenceResolutions = - new Dictionary(SymbolEqualityComparer.Default); - private readonly Queue _singleInstanceResolutionsQueue = new(); + private readonly IContainerInfo _containerInfo; + + private readonly IDictionary _singleInstanceReferenceResolutions = + new Dictionary(SymbolEqualityComparer.Default); + private readonly Queue _singleInstanceResolutionsQueue = new(); - private readonly List<(Resolvable, INamedTypeSymbol)> _rootResolutions = new (); - private readonly List _singleInstances = new (); - private readonly DisposableCollectionResolution _disposableCollectionResolution; + private readonly List _rootResolutions = new (); + private readonly List _singleInstances = new (); private readonly IScopeResolutionBuilder _scopeResolutionBuilder; public ContainerResolutionBuilder( + // parameters + IContainerInfo containerInfo, + + // dependencies ITypeToImplementationsMapper typeToImplementationsMapper, IReferenceGeneratorFactory referenceGeneratorFactory, ICheckTypeProperties checkTypeProperties, WellKnownTypes wellKnownTypes, - Func scopeResolutionBuilderFactory) : base(wellKnownTypes, typeToImplementationsMapper, referenceGeneratorFactory, - checkTypeProperties) + Func scopeResolutionBuilderFactory) + : base((containerInfo.Name, false), wellKnownTypes, typeToImplementationsMapper, referenceGeneratorFactory, checkTypeProperties) { - _disposableCollectionResolution = new DisposableCollectionResolution( - RootReferenceGenerator.Generate(WellKnownTypes.ConcurrentBagOfDisposable), - WellKnownTypes.ConcurrentBagOfDisposable.FullName()); - _scopeResolutionBuilder = scopeResolutionBuilderFactory(); + _containerInfo = containerInfo; + _scopeResolutionBuilder = scopeResolutionBuilderFactory(this); } public void AddCreateResolveFunctions(IReadOnlyList rootTypes) { foreach (var typeSymbol in rootTypes) - _rootResolutions.Add((Create( - typeSymbol, - ReferenceGeneratorFactory.Create(), - Array.Empty<(ITypeSymbol Type, FuncParameterResolution Resolution)>(), - _disposableCollectionResolution), - typeSymbol)); - - while (_singleInstanceResolutionsQueue.Any() || _scopedInstanceResolutionsQueue.Any()) + _rootResolutions.Add( + new RootResolutionFunction( + nameof(IContainer.Resolve), + typeSymbol.FullName(), + "", + Create( + typeSymbol, + ReferenceGeneratorFactory.Create(), + Array.Empty<(ITypeSymbol Type, FuncParameterResolution Resolution)>()), + WellKnownTypes.Container.Construct(typeSymbol).FullName(), + _containerInfo.Name, + DisposalHandling)); + } + + public RangedInstanceReferenceResolution CreateSingleInstanceReferenceResolution( + INamedTypeSymbol type, + IReferenceGenerator referenceGenerator, + string containerReference) + { + if (!_singleInstanceReferenceResolutions.TryGetValue( + type, + out RangedInstanceFunction function)) + { + function = new RangedInstanceFunction( + RootReferenceGenerator.Generate("GetSingleInstance", type), + type.FullName(), + type, + RootReferenceGenerator.Generate("_singleInstanceField", type), + RootReferenceGenerator.Generate("_singleInstanceLock")); + _singleInstanceReferenceResolutions[type] = function; + _singleInstanceResolutionsQueue.Enqueue(function); + } + + return new RangedInstanceReferenceResolution( + referenceGenerator.Generate(type), + function, + containerReference); + } + + protected override RangedInstanceReferenceResolution CreateSingleInstanceReferenceResolution( + INamedTypeSymbol implementationType, + IReferenceGenerator referenceGenerator) => + CreateSingleInstanceReferenceResolution(implementationType, referenceGenerator, "this"); + + protected override ScopeRootResolution CreateScopeRootResolution(INamedTypeSymbol rootType, IReferenceGenerator referenceGenerator, + DisposableCollectionResolution disposableCollectionResolution) => + _scopeResolutionBuilder.AddCreateResolveFunction(rootType, referenceGenerator, "this", disposableCollectionResolution); + + public ContainerResolution Build() + { + while (_singleInstanceResolutionsQueue.Any() || ScopedInstanceResolutionsQueue.Any() || _scopeResolutionBuilder.HasWorkToDo) { while (_singleInstanceResolutionsQueue.Any()) { @@ -316,98 +401,141 @@ public void AddCreateResolveFunctions(IReadOnlyList rootTypes) singleInstanceFunction.Type, ReferenceGeneratorFactory.Create(), Array.Empty<(ITypeSymbol Type, FuncParameterResolution Resolution)>(), - _disposableCollectionResolution, true); - _singleInstances.Add(new SingleInstance(singleInstanceFunction, resolvable)); + _singleInstances.Add(new RangedInstance(singleInstanceFunction, resolvable, DisposalHandling)); } - while (_scopedInstanceResolutionsQueue.Any()) + while (ScopedInstanceResolutionsQueue.Any()) { - var scopedInstanceFunction = _scopedInstanceResolutionsQueue.Dequeue(); + var scopedInstanceFunction = ScopedInstanceResolutionsQueue.Dequeue(); var resolvable = CreateConstructorResolution( scopedInstanceFunction.Type, ReferenceGeneratorFactory.Create(), Array.Empty<(ITypeSymbol Type, FuncParameterResolution Resolution)>(), - _disposableCollectionResolution, true); - ScopedInstances.Add(new ScopedInstance(scopedInstanceFunction, resolvable)); + ScopedInstances.Add(new RangedInstance(scopedInstanceFunction, resolvable, DisposalHandling)); } + + _scopeResolutionBuilder.DoWork(); } - } - - protected override SingleInstanceReferenceResolution CreateSingleInstanceReferenceResolution( - INamedTypeSymbol implementationType, - IReferenceGenerator referenceGenerator) - { - if (!_singleInstanceReferenceResolutions.TryGetValue( - implementationType, - out SingleInstanceFunction function)) - { - function = new SingleInstanceFunction( - RootReferenceGenerator.Generate("GetSingleInstance", implementationType), - implementationType.FullName(), - implementationType, - RootReferenceGenerator.Generate("_singleInstanceField", implementationType), - RootReferenceGenerator.Generate("_singleInstanceLock")); - _singleInstanceReferenceResolutions[implementationType] = function; - _singleInstanceResolutionsQueue.Enqueue(function); - } - - return new SingleInstanceReferenceResolution( - referenceGenerator.Generate(implementationType), - function); - } - - public ContainerResolution Build() => - new(_rootResolutions, - new DisposalHandling( - _disposableCollectionResolution, - RootReferenceGenerator.Generate("_disposed"), - RootReferenceGenerator.Generate("disposed"), - RootReferenceGenerator.Generate("Disposed"), - RootReferenceGenerator.Generate("disposable")), + + return new( + _rootResolutions, + DisposalHandling, ScopedInstances, _singleInstances, _scopeResolutionBuilder.Build()); + } } internal class ScopeResolutionBuilder : RangeResolutionBaseBuilder, IScopeResolutionBuilder { - private readonly IReferenceGenerator _scopeInstanceReferenceGenerator; - private readonly List<(Resolvable, INamedTypeSymbol)> _rootResolutions = new (); - private readonly DisposableCollectionResolution _disposableCollectionResolution; + private readonly IContainerResolutionBuilder _containerResolutionBuilder; + private readonly List _rootResolutions = new (); + private readonly string _containerReference; + private readonly string _containerParameterReference; + + private readonly IDictionary _scopeRootFunctionResolutions = + new Dictionary(SymbolEqualityComparer.Default); + private readonly Queue _scopeRootFunctionResolutionsQueue = new(); public ScopeResolutionBuilder( + // parameter + IContainerResolutionBuilder containerResolutionBuilder, + + // dependencies WellKnownTypes wellKnownTypes, ITypeToImplementationsMapper typeToImplementationsMapper, IReferenceGeneratorFactory referenceGeneratorFactory, - ICheckTypeProperties checkTypeProperties) : base(wellKnownTypes, typeToImplementationsMapper, referenceGeneratorFactory, checkTypeProperties) + ICheckTypeProperties checkTypeProperties) : base(("DefaultScope", true), wellKnownTypes, typeToImplementationsMapper, referenceGeneratorFactory, checkTypeProperties) { - _scopeInstanceReferenceGenerator = referenceGeneratorFactory.Create(); - _disposableCollectionResolution = new DisposableCollectionResolution( - _scopeInstanceReferenceGenerator.Generate(WellKnownTypes.ConcurrentBagOfDisposable), - WellKnownTypes.ConcurrentBagOfDisposable.FullName()); + _containerResolutionBuilder = containerResolutionBuilder; + _containerReference = RootReferenceGenerator.Generate("_container"); + _containerParameterReference = RootReferenceGenerator.Generate("container"); } - protected override SingleInstanceReferenceResolution CreateSingleInstanceReferenceResolution( + protected override RangedInstanceReferenceResolution CreateSingleInstanceReferenceResolution( INamedTypeSymbol implementationType, - IReferenceGenerator referenceGenerator) + IReferenceGenerator referenceGenerator) => + _containerResolutionBuilder.CreateSingleInstanceReferenceResolution( + implementationType, + referenceGenerator, + _containerReference); + + protected override ScopeRootResolution CreateScopeRootResolution(INamedTypeSymbol rootType, IReferenceGenerator referenceGenerator, + DisposableCollectionResolution disposableCollectionResolution) => + AddCreateResolveFunction(rootType, referenceGenerator, _containerReference, disposableCollectionResolution); + + public bool HasWorkToDo => _scopeRootFunctionResolutionsQueue.Any() || ScopedInstanceResolutionsQueue.Any(); + + public ScopeRootResolution AddCreateResolveFunction( + INamedTypeSymbol rootType, + IReferenceGenerator referenceGenerator, + string singleInstanceScopeReference, + DisposableCollectionResolution disposableCollectionResolution) { - throw new NotImplementedException(); + if (!_scopeRootFunctionResolutions.TryGetValue( + rootType, + out ScopeRootFunction function)) + { + function = new ScopeRootFunction( + RootReferenceGenerator.Generate("Create", rootType), + rootType.FullName(), + rootType); + _scopeRootFunctionResolutions[rootType] = function; + _scopeRootFunctionResolutionsQueue.Enqueue(function); + } + + return new ScopeRootResolution( + referenceGenerator.Generate(rootType), + rootType.FullName(), + referenceGenerator.Generate("scopeRoot"), + Name, + singleInstanceScopeReference, + disposableCollectionResolution, + function); } - public void AddCreateResolveFunction(INamedTypeSymbol rootType) + public void DoWork() { - throw new NotImplementedException(); + while (HasWorkToDo) + { + while (_scopeRootFunctionResolutionsQueue.Any()) + { + var scopeRootFunction = _scopeRootFunctionResolutionsQueue.Dequeue(); + var resolvable = CreateConstructorResolution( + scopeRootFunction.Type, + ReferenceGeneratorFactory.Create(), + Array.Empty<(ITypeSymbol Type, FuncParameterResolution Resolution)>(), + skipScopeRootCheck: true); + _rootResolutions.Add(new RootResolutionFunction( + scopeRootFunction.Reference, + scopeRootFunction.Type.FullName(), + "internal", + resolvable, + "", + Name, + DisposalHandling)); + } + + while (ScopedInstanceResolutionsQueue.Any()) + { + var scopedInstanceFunction = ScopedInstanceResolutionsQueue.Dequeue(); + var resolvable = CreateConstructorResolution( + scopedInstanceFunction.Type, + ReferenceGeneratorFactory.Create(), + Array.Empty<(ITypeSymbol Type, FuncParameterResolution Resolution)>(), + true); + ScopedInstances.Add(new RangedInstance(scopedInstanceFunction, resolvable, DisposalHandling)); + } + } } public ScopeResolution Build() => new(_rootResolutions, - new DisposalHandling( - _disposableCollectionResolution, - _scopeInstanceReferenceGenerator.Generate("_disposed"), - _scopeInstanceReferenceGenerator.Generate("disposed"), - _scopeInstanceReferenceGenerator.Generate("Disposed"), - _scopeInstanceReferenceGenerator.Generate("disposable")), - ScopedInstances); + DisposalHandling, + ScopedInstances, + _containerReference, + _containerParameterReference, + Name); } \ No newline at end of file diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index 1f86903d..4c893a02 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -4,7 +4,16 @@ internal abstract record ResolutionTreeItem; internal abstract record Resolvable( string Reference, - string TypeFullName) : ResolutionTreeItem; + string TypeFullName) : ResolutionTreeItem; + +internal record RootResolutionFunction( + string Reference, + string TypeFullName, + string AccessModifier, + Resolvable Resolvable, + string ExplicitImplementationFullName, + string RangeName, + DisposalHandling DisposalHandling) : Resolvable(Reference, TypeFullName); internal record ErrorTreeItem( string Message) : Resolvable("error_99_99", "Error"); @@ -20,54 +29,40 @@ internal record ConstructorResolution( DisposableCollectionResolution? DisposableCollectionResolution, IReadOnlyList<(string name, Resolvable Dependency)> Parameter) : Resolvable(Reference, TypeFullName); -internal abstract record RangedInstanceBase( - T Function, - Resolvable Dependency) where T : RangedInstanceFunctionBase; +internal record ScopeRootResolution( + string Reference, + string TypeFullName, + string ScopeReference, + string ScopeTypeFullName, + string SingleInstanceScopeReference, + DisposableCollectionResolution DisposableCollectionResolution, + ScopeRootFunction ScopeRootFunction) : Resolvable(Reference, TypeFullName); -internal record SingleInstance( - SingleInstanceFunction Function, - Resolvable Dependency) : RangedInstanceBase(Function, Dependency); +internal record ScopeRootFunction( + string Reference, + string TypeFullName, + INamedTypeSymbol Type) : Resolvable(Reference, TypeFullName); -internal record ScopedInstance( - ScopedInstanceFunction Function, - Resolvable Dependency) : RangedInstanceBase(Function, Dependency); +internal record RangedInstance( + RangedInstanceFunction Function, + Resolvable Dependency, + DisposalHandling DisposalHandling); internal record FuncParameterResolution( string Reference, string TypeFullName) : Resolvable(Reference, TypeFullName); -internal abstract record RangedInstanceFunctionBase( +internal record RangedInstanceFunction( string Reference, string TypeFullName, INamedTypeSymbol Type, string FieldReference, string LockReference); -internal record SingleInstanceFunction( - string Reference, - string TypeFullName, - INamedTypeSymbol Type, - string FieldReference, - string LockReference) : RangedInstanceFunctionBase(Reference, TypeFullName, Type, FieldReference, LockReference); - -internal record ScopedInstanceFunction( - string Reference, - string TypeFullName, - INamedTypeSymbol Type, - string FieldReference, - string LockReference) : RangedInstanceFunctionBase(Reference, TypeFullName, Type, FieldReference, LockReference); - -internal abstract record RangedInstanceReferenceResolutionBase( +internal record RangedInstanceReferenceResolution( string Reference, - T Function) : Resolvable(Reference, Function.TypeFullName) where T : RangedInstanceFunctionBase; - -internal record SingleInstanceReferenceResolution( - string Reference, - SingleInstanceFunction Function) : RangedInstanceReferenceResolutionBase(Reference, Function); - -internal record ScopedInstanceReferenceResolution( - string Reference, - ScopedInstanceFunction Function) : RangedInstanceReferenceResolutionBase(Reference, Function); + RangedInstanceFunction Function, + string owningObjectReference) : Resolvable(Reference, Function.TypeFullName); internal record FuncResolution( string Reference, @@ -86,26 +81,30 @@ internal record DisposableCollectionResolution( string TypeFullName) : ConstructorResolution(Reference, TypeFullName, null, Array.Empty<(string name, Resolvable Dependency)>()); internal abstract record RangeResolution( - IReadOnlyList<(Resolvable, INamedTypeSymbol)> RootResolutions, + IReadOnlyList RootResolutions, DisposalHandling DisposalHandling, - IReadOnlyList ScopedInstanceResolutions) : ResolutionTreeItem; + IReadOnlyList AllRangedInstances) : ResolutionTreeItem; internal record ScopeResolution( - IReadOnlyList<(Resolvable, INamedTypeSymbol)> RootResolutions, + IReadOnlyList RootResolutions, DisposalHandling DisposalHandling, - IReadOnlyList ScopedInstanceResolutions) + IReadOnlyList ScopedInstanceResolutions, + string ContainerReference, + string ContainerParameterReference, + string Name) : RangeResolution(RootResolutions, DisposalHandling, ScopedInstanceResolutions); internal record ContainerResolution( - IReadOnlyList<(Resolvable, INamedTypeSymbol)> RootResolutions, + IReadOnlyList RootResolutions, DisposalHandling DisposalHandling, - IReadOnlyList ScopedInstanceResolutions, - IReadOnlyList SingleInstanceResolutions, + IReadOnlyList ScopedInstanceResolutions, + IReadOnlyList SingleInstanceResolutions, ScopeResolution DefaultScope) - : RangeResolution(RootResolutions, DisposalHandling, ScopedInstanceResolutions); + : RangeResolution(RootResolutions, DisposalHandling, SingleInstanceResolutions.Concat(ScopedInstanceResolutions).ToList()); internal record DisposalHandling( DisposableCollectionResolution DisposableCollection, + string RangeName, string DisposedFieldReference, string DisposedLocalReference, string DisposedPropertyReference, diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index b70bd57e..1fb6e45e 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -21,16 +21,6 @@ public void Execute(GeneratorExecutionContext context) var containerGenerator = new ContainerGenerator(context, wellKnownTypes, diagLogger); var referenceGeneratorFactory = new ReferenceGeneratorFactory(ReferenceGeneratorFactory); var checkDisposalManagement = new CheckTypeProperties(getAllImplementations, typesFromAttributes); - var resolutionTreeFactory = new ContainerResolutionBuilder( - typeToImplementationMapper, - referenceGeneratorFactory, - checkDisposalManagement, - wellKnownTypes, - () => new ScopeResolutionBuilder( - wellKnownTypes, - typeToImplementationMapper, - referenceGeneratorFactory, - checkDisposalManagement)); var containerErrorGenerator = new ContainerErrorGenerator(context); var resolutionTreeCreationErrorHarvester = new ResolutionTreeCreationErrorHarvester(); new ExecuteImpl( @@ -38,11 +28,24 @@ public void Execute(GeneratorExecutionContext context) wellKnownTypes, containerGenerator, containerErrorGenerator, - resolutionTreeFactory, + ResolutionTreeFactory, resolutionTreeCreationErrorHarvester, ContainerInfoFactory, diagLogger).Execute(); + IContainerResolutionBuilder ResolutionTreeFactory(IContainerInfo ci) => new ContainerResolutionBuilder( + ci, + typeToImplementationMapper, + referenceGeneratorFactory, + checkDisposalManagement, + wellKnownTypes, + ScopeResolutionBuilderFactory); + IScopeResolutionBuilder ScopeResolutionBuilderFactory(IContainerResolutionBuilder containerBuilder) => new ScopeResolutionBuilder( + containerBuilder, + wellKnownTypes, + typeToImplementationMapper, + referenceGeneratorFactory, + checkDisposalManagement); IContainerInfo ContainerInfoFactory(INamedTypeSymbol type) => new ContainerInfo(type, wellKnownTypes); IReferenceGenerator ReferenceGeneratorFactory(int j) => new ReferenceGenerator(j); } diff --git a/Sample/StrongInjectContainer.cs b/Sample/StrongInjectContainer.cs index 181f3533..8cd0b52e 100644 --- a/Sample/StrongInjectContainer.cs +++ b/Sample/StrongInjectContainer.cs @@ -8,6 +8,8 @@ namespace MrMeeseeks.DIE.Sample; [Register(typeof(Child), Scope.SingleInstance, typeof(Child), typeof(IChild))] [Register(typeof(InternalChild), typeof(IInternalChild))] [Register(typeof(YetAnotherInternalChild), typeof(IYetAnotherInternalChild))] +[Register(typeof(AndThenSingleInstance), typeof(IAndThenSingleInstance))] +[Register(typeof(AndThenAnotherScope), typeof(IAndThenAnotherScope))] [RegisterModule(typeof(StandardModule))] internal partial class StrongInjectContainer : StrongInject.IContainer { diff --git a/SampleChild/InternalChild.cs b/SampleChild/InternalChild.cs index 84037cfe..84ee58b1 100644 --- a/SampleChild/InternalChild.cs +++ b/SampleChild/InternalChild.cs @@ -6,7 +6,9 @@ public interface IInternalChild {} internal class InternalChild : IInternalChild, IDisposable, IScopedInstance { - public InternalChild(Lazy yetAnotherInternalChild) + public InternalChild( + Lazy yetAnotherInternalChild, + IAndThenAnotherScope andThenAnotherScope) { } @@ -16,9 +18,30 @@ public void Dispose() } } +public interface IAndThenAnotherScope +{} +internal class AndThenAnotherScope : IAndThenAnotherScope, IDisposable, IScopedInstance, IScopeRoot +{ + public void Dispose() + { + } +} + public interface IYetAnotherInternalChild {} internal class YetAnotherInternalChild : IYetAnotherInternalChild, IDisposable, IScopedInstance +{ + public YetAnotherInternalChild( + IAndThenSingleInstance andThenSingleInstance) + {} + public void Dispose() + { + } +} + +public interface IAndThenSingleInstance +{} +internal class AndThenSingleInstance : IAndThenSingleInstance, IDisposable, ISingleInstance { public void Dispose() { From 3e6f90ab2c60033cfd0e3ef94e3be8c45496bc28 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sun, 21 Nov 2021 16:23:16 +0100 Subject: [PATCH 022/162] Currying ranged instances --- Main/ContainerGenerator.cs | 65 +++--- Main/ResolutionTreeCreationErrorHarvester.cs | 6 +- Main/ResolutionTreeFactory.cs | 208 ++++++++++--------- Main/ResolutionTreeItem.cs | 25 ++- Sample/Program.cs | 2 + Sample/StrongInjectContainer.cs | 8 +- SampleChild/InternalChild.cs | 14 +- 7 files changed, 186 insertions(+), 142 deletions(-) diff --git a/Main/ContainerGenerator.cs b/Main/ContainerGenerator.cs index ae13b1ae..289ad55c 100644 --- a/Main/ContainerGenerator.cs +++ b/Main/ContainerGenerator.cs @@ -79,7 +79,7 @@ StringBuilder GenerateResolutionRange( stringBuilder, rangeResolution); - stringBuilder = rangeResolution.AllRangedInstances.Aggregate(stringBuilder, GenerateRangedInstanceFunction); + stringBuilder = rangeResolution.RangedInstances.Aggregate(stringBuilder, GenerateRangedInstanceFunction); return rangeResolution.RootResolutions.Aggregate(stringBuilder, GenerateResolutionFunction); } @@ -98,7 +98,7 @@ StringBuilder GenerateContainerDisposalFunction( .AppendLine($"var {disposalHandling.DisposedLocalReference} = global::System.Threading.Interlocked.Exchange(ref this.{disposalHandling.DisposedFieldReference}, 1);") .AppendLine($"if ({disposalHandling.DisposedLocalReference} != 0) return;"); - stringBuilder = rangeResolution.AllRangedInstances.Aggregate( + stringBuilder = rangeResolution.RangedInstances.Aggregate( stringBuilder, (current, singleInstanceResolution) => current.AppendLine($"this.{singleInstanceResolution.Function.LockReference}.Wait();")); @@ -120,7 +120,7 @@ StringBuilder GenerateContainerDisposalFunction( .AppendLine($"finally") .AppendLine($"{{"); - stringBuilder = rangeResolution.AllRangedInstances.Aggregate( + stringBuilder = rangeResolution.RangedInstances.Aggregate( stringBuilder, (current, singleInstanceResolution) => current.AppendLine($"this.{singleInstanceResolution.Function.LockReference}.Release();")); @@ -174,7 +174,7 @@ StringBuilder GenerateFields( case FuncResolution(var reference, var typeFullName, _, _): stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); break; - case FuncParameterResolution: + case ParameterResolution: break; case CollectionResolution(var reference, var typeFullName, _, var items): stringBuilder = items.OfType().Aggregate(stringBuilder, GenerateFields); @@ -202,8 +202,8 @@ StringBuilder GenerateResolutions( .AppendLine($"{disposableCollectionReference}.Add(({_wellKnownTypes.Disposable.FullName()}) {scopeReference});") .AppendLine($"{reference} = ({typeFullName}) {scopeReference}.{createFunctionReference}();"); break; - case RangedInstanceReferenceResolution(var reference, { Reference: {} functionReference}, var owningObjectReference): - stringBuilder = stringBuilder.AppendLine($"{reference} = {owningObjectReference}.{functionReference}();"); + case RangedInstanceReferenceResolution(var reference, { Reference: {} functionReference}, var parameter, var owningObjectReference): + stringBuilder = stringBuilder.AppendLine($"{reference} = {owningObjectReference}.{functionReference}({string.Join(", ", parameter.Select(p => p.Reference))});"); break; case InterfaceResolution(var reference, var typeFullName, Resolvable resolutionBase): stringBuilder = GenerateResolutions(stringBuilder, resolutionBase); @@ -226,7 +226,7 @@ StringBuilder GenerateResolutions( stringBuilder = stringBuilder.AppendLine($"return {resolutionBase.Reference};"); stringBuilder = stringBuilder.AppendLine($"}};"); break; - case FuncParameterResolution: + case ParameterResolution: break; case CollectionResolution(var reference, _, var itemFullName, var items): stringBuilder = items.OfType().Aggregate(stringBuilder, GenerateResolutions); @@ -246,30 +246,37 @@ StringBuilder GenerateRangedInstanceFunction(StringBuilder stringBuilder, Ranged .AppendLine( $"private {rangedInstance.Function.TypeFullName} {rangedInstance.Function.FieldReference};") .AppendLine( - $"private {_wellKnownTypes.SemaphoreSlim.FullName()} {rangedInstance.Function.LockReference} = new {_wellKnownTypes.SemaphoreSlim.FullName()}(1);") - .AppendLine( - $"public {rangedInstance.Function.TypeFullName} {rangedInstance.Function.Reference}()") - .AppendLine($"{{") - .AppendLine( - $"if (!object.ReferenceEquals({rangedInstance.Function.FieldReference}, null)) return {rangedInstance.Function.FieldReference};") - .AppendLine($"this.{rangedInstance.Function.LockReference}.Wait();") - .AppendLine($"try") - .AppendLine($"{{") - .AppendLine( - $"if (this.{rangedInstance.DisposalHandling.DisposedPropertyReference}) throw new {_wellKnownTypes.ObjectDisposedException}(nameof({rangedInstance.DisposalHandling.RangeName}));"); + $"private {_wellKnownTypes.SemaphoreSlim.FullName()} {rangedInstance.Function.LockReference} = new {_wellKnownTypes.SemaphoreSlim.FullName()}(1);"); + + foreach (var (resolvable, funcParameterResolutions) in rangedInstance.Overloads) + { + var parameters = string.Join(", ", + funcParameterResolutions.Select(p => $"{p.TypeFullName} {p.Reference}")); + stringBuilder = stringBuilder.AppendLine( + $"public {rangedInstance.Function.TypeFullName} {rangedInstance.Function.Reference}({parameters})") + .AppendLine($"{{") + .AppendLine($"this.{rangedInstance.Function.LockReference}.Wait();") + .AppendLine($"try") + .AppendLine($"{{") + .AppendLine( + $"if (this.{rangedInstance.DisposalHandling.DisposedPropertyReference}) throw new {_wellKnownTypes.ObjectDisposedException}(nameof({rangedInstance.DisposalHandling.RangeName}));") + .AppendLine( + $"if (!object.ReferenceEquals({rangedInstance.Function.FieldReference}, null)) return {rangedInstance.Function.FieldReference};"); - stringBuilder = GenerateResolutionFunctionContent(stringBuilder, rangedInstance.Dependency); + stringBuilder = GenerateResolutionFunctionContent(stringBuilder, resolvable); - stringBuilder = stringBuilder - .AppendLine( - $"this.{rangedInstance.Function.FieldReference} = {rangedInstance.Dependency.Reference};") - .AppendLine($"}}") - .AppendLine($"finally") - .AppendLine($"{{") - .AppendLine($"this.{rangedInstance.Function.LockReference}.Release();") - .AppendLine($"}}") - .AppendLine($"return this.{rangedInstance.Function.FieldReference};") - .AppendLine($"}}"); + stringBuilder = stringBuilder + .AppendLine( + $"this.{rangedInstance.Function.FieldReference} = {resolvable.Reference};") + .AppendLine($"}}") + .AppendLine($"finally") + .AppendLine($"{{") + .AppendLine($"this.{rangedInstance.Function.LockReference}.Release();") + .AppendLine($"}}") + .AppendLine($"return this.{rangedInstance.Function.FieldReference};") + .AppendLine($"}}"); + } + return stringBuilder; } } diff --git a/Main/ResolutionTreeCreationErrorHarvester.cs b/Main/ResolutionTreeCreationErrorHarvester.cs index db6386be..afe9ba1f 100644 --- a/Main/ResolutionTreeCreationErrorHarvester.cs +++ b/Main/ResolutionTreeCreationErrorHarvester.cs @@ -26,8 +26,8 @@ static void Inner(ResolutionTreeItem item, ICollection errorTreeI case ScopeRootResolution: break; case RangeResolution containerResolution: - foreach (var singleInstance in containerResolution.AllRangedInstances) - Inner(singleInstance.Dependency, errorTreeItems); + foreach (var overload in containerResolution.RangedInstances.SelectMany(ri => ri.Overloads)) + Inner(overload.Dependency, errorTreeItems); foreach (var rootResolution in containerResolution.RootResolutions) Inner(rootResolution, errorTreeItems); break; @@ -42,7 +42,7 @@ static void Inner(ResolutionTreeItem item, ICollection errorTreeI foreach (var resolutionTreeItem in collectionResolution.Parameter) Inner(resolutionTreeItem, errorTreeItems); break; - case FuncParameterResolution: + case ParameterResolution: break; case FuncResolution funcResolution: foreach (var funcParameterResolution in funcResolution.Parameter) diff --git a/Main/ResolutionTreeFactory.cs b/Main/ResolutionTreeFactory.cs index 53617870..e92f06ba 100644 --- a/Main/ResolutionTreeFactory.cs +++ b/Main/ResolutionTreeFactory.cs @@ -5,9 +5,10 @@ internal interface IContainerResolutionBuilder void AddCreateResolveFunctions(IReadOnlyList rootTypes); RangedInstanceReferenceResolution CreateSingleInstanceReferenceResolution( - INamedTypeSymbol type, + INamedTypeSymbol implementationType, IReferenceGenerator referenceGenerator, - string containerReference); + string containerReference, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters); ContainerResolution Build(); } @@ -35,11 +36,13 @@ internal abstract class RangeResolutionBaseBuilder protected readonly ICheckTypeProperties CheckTypeProperties; protected readonly IReferenceGenerator RootReferenceGenerator; - protected readonly IDictionary ScopedInstanceReferenceResolutions = - new Dictionary(SymbolEqualityComparer.Default); - protected readonly Queue ScopedInstanceResolutionsQueue = new(); + protected readonly IDictionary RangedInstanceReferenceResolutions = + new Dictionary(SymbolEqualityComparer.Default); + protected readonly HashSet<(RangedInstanceFunction, string)> RangedInstanceQueuedOverloads = new (); + protected readonly HashSet<(RangedInstanceFunction, string)> RangedInstanceDoneOverloads = new (); + protected readonly Queue<(RangedInstanceFunction, IReadOnlyList<(ITypeSymbol, ParameterResolution)>, INamedTypeSymbol)> RangedInstanceResolutionsQueue = new(); - protected readonly List ScopedInstances = new (); + protected readonly List<(RangedInstanceFunction, RangedInstanceFunctionOverload)> RangedInstances = new (); protected readonly DisposableCollectionResolution DisposableCollectionResolution; protected readonly DisposalHandling DisposalHandling; protected readonly string Name; @@ -76,7 +79,8 @@ protected RangeResolutionBaseBuilder( protected abstract RangedInstanceReferenceResolution CreateSingleInstanceReferenceResolution( INamedTypeSymbol implementationType, - IReferenceGenerator referenceGenerator); + IReferenceGenerator referenceGenerator, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters); protected abstract ScopeRootResolution CreateScopeRootResolution( INamedTypeSymbol rootType, @@ -86,7 +90,7 @@ protected abstract ScopeRootResolution CreateScopeRootResolution( protected Resolvable Create( ITypeSymbol type, IReferenceGenerator referenceGenerator, - IReadOnlyList<(ITypeSymbol Type, FuncParameterResolution Resolution)> currentFuncParameters) + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentFuncParameters) { if (currentFuncParameters.FirstOrDefault(t => SymbolEqualityComparer.Default.Equals(t.Type.OriginalDefinition, type.OriginalDefinition)) is { Type: not null, Resolution: not null } funcParameter) { @@ -109,7 +113,7 @@ protected Resolvable Create( var dependency = Create( genericType, ReferenceGeneratorFactory.Create(), - Array.Empty<(ITypeSymbol Type, FuncParameterResolution Resolution)>()); + Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>()); return new ConstructorResolution( referenceGenerator.Generate(namedTypeSymbol), namedTypeSymbol.FullName(), @@ -122,7 +126,7 @@ protected Resolvable Create( new FuncResolution( referenceGenerator.Generate("func"), $"global::System.Func<{genericType.FullName()}>", - Array.Empty(), + Array.Empty(), dependency) ) })); @@ -189,7 +193,7 @@ protected Resolvable Create( var parameterTypes = namedTypeSymbol0 .TypeArguments .Take(namedTypeSymbol0.TypeArguments.Length - 1) - .Select(ts => (Type: ts, Resolution: new FuncParameterResolution(innerReferenceGenerator.Generate(ts), ts.FullName()))) + .Select(ts => (Type: ts, Resolution: new ParameterResolution(innerReferenceGenerator.Generate(ts), ts.FullName()))) .ToArray(); var dependency = Create( @@ -209,7 +213,7 @@ protected Resolvable Create( protected Resolvable CreateConstructorResolution( ITypeSymbol typeSymbol, IReferenceGenerator referenceGenerator, - IReadOnlyList<(ITypeSymbol Type, FuncParameterResolution Resolution)> readOnlyList, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters, bool skipRangedInstanceCheck = false, bool skipScopeRootCheck = false) { @@ -228,13 +232,13 @@ protected Resolvable CreateConstructorResolution( } if (!skipRangedInstanceCheck && CheckTypeProperties.ShouldBeSingleInstance(implementationType)) - return CreateSingleInstanceReferenceResolution(implementationType, referenceGenerator); + return CreateSingleInstanceReferenceResolution(implementationType, referenceGenerator, currentParameters); if (!skipScopeRootCheck && CheckTypeProperties.ShouldBeScopeRoot(implementationType)) return CreateScopeRootResolution(implementationType, referenceGenerator, DisposableCollectionResolution); if (!skipRangedInstanceCheck && CheckTypeProperties.ShouldBeScopedInstance(implementationType)) - return CreateScopedInstanceReferenceResolution(implementationType, referenceGenerator); + return CreateScopedInstanceReferenceResolution(implementationType, referenceGenerator, currentParameters); if (implementationType.Constructors.SingleOrDefault() is not { } constructor) { @@ -272,33 +276,83 @@ protected Resolvable CreateConstructorResolution( p.Name, Create(parameterType, referenceGenerator, - readOnlyList)); + currentParameters)); }) .ToList())); } - protected RangedInstanceReferenceResolution CreateScopedInstanceReferenceResolution( + private RangedInstanceReferenceResolution CreateScopedInstanceReferenceResolution( INamedTypeSymbol implementationType, - IReferenceGenerator referenceGenerator) + IReferenceGenerator referenceGenerator, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) => + CreateRangedInstanceReferenceResolution( + implementationType, + referenceGenerator, + currentParameters, + "Scoped", + "this"); + + protected RangedInstanceReferenceResolution CreateRangedInstanceReferenceResolution( + INamedTypeSymbol implementationType, + IReferenceGenerator referenceGenerator, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters, + string label, + string owningObjectReference) { - if (!ScopedInstanceReferenceResolutions.TryGetValue( + if (!RangedInstanceReferenceResolutions.TryGetValue( implementationType, out RangedInstanceFunction function)) { function = new RangedInstanceFunction( - RootReferenceGenerator.Generate("GetScopedInstance", implementationType), + RootReferenceGenerator.Generate($"Get{label}Instance", implementationType), implementationType.FullName(), - implementationType, - RootReferenceGenerator.Generate("_scopedInstanceField", implementationType), - RootReferenceGenerator.Generate("_scopedInstanceLock")); - ScopedInstanceReferenceResolutions[implementationType] = function; - ScopedInstanceResolutionsQueue.Enqueue(function); + RootReferenceGenerator.Generate($"_{label.ToLower()}InstanceField", implementationType), + RootReferenceGenerator.Generate($"_{label.ToLower()}InstanceLock")); + RangedInstanceReferenceResolutions[implementationType] = function; + var parameter = currentParameters + .Select(t => (t.Type, new ParameterResolution(RootReferenceGenerator.Generate(t.Type), t.Type.FullName()))) + .ToList(); + RangedInstanceResolutionsQueue.Enqueue((function, parameter, implementationType)); + } + + var listedParameterTypes = string.Join(",", currentParameters.Select(p => p.Item2.TypeFullName)); + if (!RangedInstanceQueuedOverloads.Contains((function, listedParameterTypes))) + { + var parameter = currentParameters + .Select(t => (t.Type, new ParameterResolution(RootReferenceGenerator.Generate(t.Type), t.Type.FullName()))) + .ToList(); + RangedInstanceResolutionsQueue.Enqueue((function, parameter, implementationType)); + RangedInstanceQueuedOverloads.Add((function, listedParameterTypes)); } return new RangedInstanceReferenceResolution( referenceGenerator.Generate(implementationType), function, - "this"); + currentParameters.Select(t => t.Resolution).ToList(), + owningObjectReference); + } + + protected void DoRangedInstancesWork() + { + while (RangedInstanceResolutionsQueue.Any()) + { + var (scopedInstanceFunction, parameter, type) = RangedInstanceResolutionsQueue.Dequeue(); + var listedParameterTypes = string.Join(",", parameter.Select(p => p.Item2.TypeFullName)); + if (RangedInstanceDoneOverloads.Contains((scopedInstanceFunction, listedParameterTypes))) + continue; + var referenceGenerator = ReferenceGeneratorFactory.Create(); + var resolvable = CreateConstructorResolution( + type, + referenceGenerator, + parameter, + true); + RangedInstances.Add(( + scopedInstanceFunction, + new RangedInstanceFunctionOverload( + resolvable, + parameter.Select(t => t.Item2).ToList()))); + RangedInstanceDoneOverloads.Add((scopedInstanceFunction, listedParameterTypes)); + } } private static DisposableCollectionResolution? ImplementsIDisposable( @@ -314,13 +368,8 @@ protected RangedInstanceReferenceResolution CreateScopedInstanceReferenceResolut internal class ContainerResolutionBuilder : RangeResolutionBaseBuilder, IContainerResolutionBuilder { private readonly IContainerInfo _containerInfo; - - private readonly IDictionary _singleInstanceReferenceResolutions = - new Dictionary(SymbolEqualityComparer.Default); - private readonly Queue _singleInstanceResolutionsQueue = new(); private readonly List _rootResolutions = new (); - private readonly List _singleInstances = new (); private readonly IScopeResolutionBuilder _scopeResolutionBuilder; public ContainerResolutionBuilder( @@ -350,41 +399,29 @@ public void AddCreateResolveFunctions(IReadOnlyList rootTypes) Create( typeSymbol, ReferenceGeneratorFactory.Create(), - Array.Empty<(ITypeSymbol Type, FuncParameterResolution Resolution)>()), + Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>()), WellKnownTypes.Container.Construct(typeSymbol).FullName(), _containerInfo.Name, DisposalHandling)); } public RangedInstanceReferenceResolution CreateSingleInstanceReferenceResolution( - INamedTypeSymbol type, + INamedTypeSymbol implementationType, IReferenceGenerator referenceGenerator, - string containerReference) - { - if (!_singleInstanceReferenceResolutions.TryGetValue( - type, - out RangedInstanceFunction function)) - { - function = new RangedInstanceFunction( - RootReferenceGenerator.Generate("GetSingleInstance", type), - type.FullName(), - type, - RootReferenceGenerator.Generate("_singleInstanceField", type), - RootReferenceGenerator.Generate("_singleInstanceLock")); - _singleInstanceReferenceResolutions[type] = function; - _singleInstanceResolutionsQueue.Enqueue(function); - } - - return new RangedInstanceReferenceResolution( - referenceGenerator.Generate(type), - function, + string containerReference, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) => + CreateRangedInstanceReferenceResolution( + implementationType, + referenceGenerator, + currentParameters, + "Single", containerReference); - } protected override RangedInstanceReferenceResolution CreateSingleInstanceReferenceResolution( INamedTypeSymbol implementationType, - IReferenceGenerator referenceGenerator) => - CreateSingleInstanceReferenceResolution(implementationType, referenceGenerator, "this"); + IReferenceGenerator referenceGenerator, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) => + CreateSingleInstanceReferenceResolution(implementationType, referenceGenerator, "this", currentParameters); protected override ScopeRootResolution CreateScopeRootResolution(INamedTypeSymbol rootType, IReferenceGenerator referenceGenerator, DisposableCollectionResolution disposableCollectionResolution) => @@ -392,38 +429,22 @@ protected override ScopeRootResolution CreateScopeRootResolution(INamedTypeSymbo public ContainerResolution Build() { - while (_singleInstanceResolutionsQueue.Any() || ScopedInstanceResolutionsQueue.Any() || _scopeResolutionBuilder.HasWorkToDo) + while (RangedInstanceResolutionsQueue.Any() || _scopeResolutionBuilder.HasWorkToDo) { - while (_singleInstanceResolutionsQueue.Any()) - { - var singleInstanceFunction = _singleInstanceResolutionsQueue.Dequeue(); - var resolvable = CreateConstructorResolution( - singleInstanceFunction.Type, - ReferenceGeneratorFactory.Create(), - Array.Empty<(ITypeSymbol Type, FuncParameterResolution Resolution)>(), - true); - _singleInstances.Add(new RangedInstance(singleInstanceFunction, resolvable, DisposalHandling)); - } - - while (ScopedInstanceResolutionsQueue.Any()) - { - var scopedInstanceFunction = ScopedInstanceResolutionsQueue.Dequeue(); - var resolvable = CreateConstructorResolution( - scopedInstanceFunction.Type, - ReferenceGeneratorFactory.Create(), - Array.Empty<(ITypeSymbol Type, FuncParameterResolution Resolution)>(), - true); - ScopedInstances.Add(new RangedInstance(scopedInstanceFunction, resolvable, DisposalHandling)); - } - + DoRangedInstancesWork(); _scopeResolutionBuilder.DoWork(); } return new( _rootResolutions, DisposalHandling, - ScopedInstances, - _singleInstances, + RangedInstances + .GroupBy(t => t.Item1) + .Select(g => new RangedInstance( + g.Key, + g.Select(t => t.Item2).ToList(), + DisposalHandling)) + .ToList(), _scopeResolutionBuilder.Build()); } } @@ -456,17 +477,19 @@ public ScopeResolutionBuilder( protected override RangedInstanceReferenceResolution CreateSingleInstanceReferenceResolution( INamedTypeSymbol implementationType, - IReferenceGenerator referenceGenerator) => + IReferenceGenerator referenceGenerator, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) => _containerResolutionBuilder.CreateSingleInstanceReferenceResolution( implementationType, referenceGenerator, - _containerReference); + _containerReference, + currentParameters); protected override ScopeRootResolution CreateScopeRootResolution(INamedTypeSymbol rootType, IReferenceGenerator referenceGenerator, DisposableCollectionResolution disposableCollectionResolution) => AddCreateResolveFunction(rootType, referenceGenerator, _containerReference, disposableCollectionResolution); - public bool HasWorkToDo => _scopeRootFunctionResolutionsQueue.Any() || ScopedInstanceResolutionsQueue.Any(); + public bool HasWorkToDo => _scopeRootFunctionResolutionsQueue.Any() || RangedInstanceResolutionsQueue.Any(); public ScopeRootResolution AddCreateResolveFunction( INamedTypeSymbol rootType, @@ -506,7 +529,7 @@ public void DoWork() var resolvable = CreateConstructorResolution( scopeRootFunction.Type, ReferenceGeneratorFactory.Create(), - Array.Empty<(ITypeSymbol Type, FuncParameterResolution Resolution)>(), + Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>(), skipScopeRootCheck: true); _rootResolutions.Add(new RootResolutionFunction( scopeRootFunction.Reference, @@ -518,23 +541,20 @@ public void DoWork() DisposalHandling)); } - while (ScopedInstanceResolutionsQueue.Any()) - { - var scopedInstanceFunction = ScopedInstanceResolutionsQueue.Dequeue(); - var resolvable = CreateConstructorResolution( - scopedInstanceFunction.Type, - ReferenceGeneratorFactory.Create(), - Array.Empty<(ITypeSymbol Type, FuncParameterResolution Resolution)>(), - true); - ScopedInstances.Add(new RangedInstance(scopedInstanceFunction, resolvable, DisposalHandling)); - } + DoRangedInstancesWork(); } } public ScopeResolution Build() => new(_rootResolutions, DisposalHandling, - ScopedInstances, + RangedInstances + .GroupBy(t => t.Item1) + .Select(g => new RangedInstance( + g.Key, + g.Select(t => t.Item2).ToList(), + DisposalHandling)) + .ToList(), _containerReference, _containerParameterReference, Name); diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index 4c893a02..9f0acc59 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -45,29 +45,33 @@ internal record ScopeRootFunction( internal record RangedInstance( RangedInstanceFunction Function, - Resolvable Dependency, + IReadOnlyList Overloads, DisposalHandling DisposalHandling); -internal record FuncParameterResolution( +internal record ParameterResolution( string Reference, string TypeFullName) : Resolvable(Reference, TypeFullName); internal record RangedInstanceFunction( string Reference, string TypeFullName, - INamedTypeSymbol Type, string FieldReference, string LockReference); +internal record RangedInstanceFunctionOverload( + Resolvable Dependency, + IReadOnlyList Parameter); + internal record RangedInstanceReferenceResolution( string Reference, RangedInstanceFunction Function, - string owningObjectReference) : Resolvable(Reference, Function.TypeFullName); + IReadOnlyList Parameter, + string OwningObjectReference) : Resolvable(Reference, Function.TypeFullName); internal record FuncResolution( string Reference, string TypeFullName, - IReadOnlyList Parameter, + IReadOnlyList Parameter, ResolutionTreeItem Dependency) : Resolvable(Reference, TypeFullName); internal record CollectionResolution( @@ -83,24 +87,23 @@ internal record DisposableCollectionResolution( internal abstract record RangeResolution( IReadOnlyList RootResolutions, DisposalHandling DisposalHandling, - IReadOnlyList AllRangedInstances) : ResolutionTreeItem; + IReadOnlyList RangedInstances) : ResolutionTreeItem; internal record ScopeResolution( IReadOnlyList RootResolutions, DisposalHandling DisposalHandling, - IReadOnlyList ScopedInstanceResolutions, + IReadOnlyList RangedInstances, string ContainerReference, string ContainerParameterReference, string Name) - : RangeResolution(RootResolutions, DisposalHandling, ScopedInstanceResolutions); + : RangeResolution(RootResolutions, DisposalHandling, RangedInstances); internal record ContainerResolution( IReadOnlyList RootResolutions, DisposalHandling DisposalHandling, - IReadOnlyList ScopedInstanceResolutions, - IReadOnlyList SingleInstanceResolutions, + IReadOnlyList RangedInstances, ScopeResolution DefaultScope) - : RangeResolution(RootResolutions, DisposalHandling, SingleInstanceResolutions.Concat(ScopedInstanceResolutions).ToList()); + : RangeResolution(RootResolutions, DisposalHandling, RangedInstances); internal record DisposalHandling( DisposableCollectionResolution DisposableCollection, diff --git a/Sample/Program.cs b/Sample/Program.cs index 9ef8cd2b..9ba9269f 100644 --- a/Sample/Program.cs +++ b/Sample/Program.cs @@ -7,8 +7,10 @@ System.Console.WriteLine(((MrMeeseeks.DIE.IContainer) container).Resolve().Text); } { + /* using var strongInjectContainer = new StrongInjectContainer(); using var owned = strongInjectContainer.Resolve(); System.Console.WriteLine(owned.Value.Text); + */ } diff --git a/Sample/StrongInjectContainer.cs b/Sample/StrongInjectContainer.cs index 8cd0b52e..1d405d72 100644 --- a/Sample/StrongInjectContainer.cs +++ b/Sample/StrongInjectContainer.cs @@ -3,15 +3,17 @@ using StrongInject.Modules; namespace MrMeeseeks.DIE.Sample; - +//* [Register(typeof(Context), Scope.SingleInstance, typeof(Context), typeof(IContext))] [Register(typeof(Child), Scope.SingleInstance, typeof(Child), typeof(IChild))] [Register(typeof(InternalChild), typeof(IInternalChild))] [Register(typeof(YetAnotherInternalChild), typeof(IYetAnotherInternalChild))] -[Register(typeof(AndThenSingleInstance), typeof(IAndThenSingleInstance))] +[Register(typeof(AndThenSingleInstance), Scope.SingleInstance, typeof(IAndThenSingleInstance))] [Register(typeof(AndThenAnotherScope), typeof(IAndThenAnotherScope))] +[Register(typeof(A), typeof(IA))] +[Register(typeof(B), typeof(IB))] [RegisterModule(typeof(StandardModule))] internal partial class StrongInjectContainer : StrongInject.IContainer { -} \ No newline at end of file +}//*/ \ No newline at end of file diff --git a/SampleChild/InternalChild.cs b/SampleChild/InternalChild.cs index 84ee58b1..819af9e3 100644 --- a/SampleChild/InternalChild.cs +++ b/SampleChild/InternalChild.cs @@ -32,7 +32,8 @@ public interface IYetAnotherInternalChild internal class YetAnotherInternalChild : IYetAnotherInternalChild, IDisposable, IScopedInstance { public YetAnotherInternalChild( - IAndThenSingleInstance andThenSingleInstance) + Func andThenSingleInstanceA, + Func andThenSingleInstanceB) {} public void Dispose() { @@ -43,7 +44,16 @@ public interface IAndThenSingleInstance {} internal class AndThenSingleInstance : IAndThenSingleInstance, IDisposable, ISingleInstance { + public AndThenSingleInstance( + IA a, + IB b){} public void Dispose() { } -} \ No newline at end of file +} + +public interface IA {} +public interface IB {} + +public class A : IA {} +public class B : IB {} \ No newline at end of file From 0d719f2983131f1de5a2e9e98e4501a511e35a3f Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sun, 21 Nov 2021 18:07:21 +0100 Subject: [PATCH 023/162] Currying scope roots --- Main/ContainerGenerator.cs | 9 +++-- Main/ResolutionTreeFactory.cs | 76 ++++++++++++++++++++++------------- Main/ResolutionTreeItem.cs | 5 ++- SampleChild/InternalChild.cs | 6 ++- 4 files changed, 62 insertions(+), 34 deletions(-) diff --git a/Main/ContainerGenerator.cs b/Main/ContainerGenerator.cs index 289ad55c..62562300 100644 --- a/Main/ContainerGenerator.cs +++ b/Main/ContainerGenerator.cs @@ -133,8 +133,9 @@ StringBuilder GenerateResolutionFunction( StringBuilder stringBuilder, RootResolutionFunction resolution) { + var parameter = string.Join(",", resolution.Parameter.Select(r => $"{r.TypeFullName} {r.Reference}")); stringBuilder = stringBuilder - .AppendLine($"{resolution.AccessModifier} {resolution.TypeFullName} {resolution.ExplicitImplementationFullName}{(string.IsNullOrWhiteSpace(resolution.ExplicitImplementationFullName) ? "" : ".")}{resolution.Reference}()") + .AppendLine($"{resolution.AccessModifier} {resolution.TypeFullName} {resolution.ExplicitImplementationFullName}{(string.IsNullOrWhiteSpace(resolution.ExplicitImplementationFullName) ? "" : ".")}{resolution.Reference}({parameter})") .AppendLine($"{{") .AppendLine($"if (this.{resolution.DisposalHandling.DisposedPropertyReference}) throw new {_wellKnownTypes.ObjectDisposedException}(nameof({resolution.RangeName}));"); @@ -157,7 +158,7 @@ StringBuilder GenerateFields( { switch (resolution) { - case ScopeRootResolution(var reference, var typeFullName, var scopeReference, var scopeTypeFullName, _, _, _): + case ScopeRootResolution(var reference, var typeFullName, var scopeReference, var scopeTypeFullName, _, _, _, _): stringBuilder = stringBuilder .AppendLine($"{scopeTypeFullName} {scopeReference};") .AppendLine($"{typeFullName} {reference};"); @@ -196,11 +197,11 @@ StringBuilder GenerateResolutions( { switch (resolution) { - case ScopeRootResolution(var reference, var typeFullName, var scopeReference, var scopeTypeFullName, var singleInstanceScopeReference, var (disposableCollectionReference, _, _, _), var (createFunctionReference, _, _)): + case ScopeRootResolution(var reference, var typeFullName, var scopeReference, var scopeTypeFullName, var singleInstanceScopeReference, var parameter, var (disposableCollectionReference, _, _, _), var (createFunctionReference, _)): stringBuilder = stringBuilder .AppendLine($"{scopeReference} = new {scopeTypeFullName}({singleInstanceScopeReference});") .AppendLine($"{disposableCollectionReference}.Add(({_wellKnownTypes.Disposable.FullName()}) {scopeReference});") - .AppendLine($"{reference} = ({typeFullName}) {scopeReference}.{createFunctionReference}();"); + .AppendLine($"{reference} = ({typeFullName}) {scopeReference}.{createFunctionReference}({string.Join(", ", parameter.Select(p => p.Reference))});"); break; case RangedInstanceReferenceResolution(var reference, { Reference: {} functionReference}, var parameter, var owningObjectReference): stringBuilder = stringBuilder.AppendLine($"{reference} = {owningObjectReference}.{functionReference}({string.Join(", ", parameter.Select(p => p.Reference))});"); diff --git a/Main/ResolutionTreeFactory.cs b/Main/ResolutionTreeFactory.cs index e92f06ba..361bbff8 100644 --- a/Main/ResolutionTreeFactory.cs +++ b/Main/ResolutionTreeFactory.cs @@ -21,7 +21,8 @@ ScopeRootResolution AddCreateResolveFunction( INamedTypeSymbol rootType, IReferenceGenerator referenceGenerator, string singleInstanceScopeReference, - DisposableCollectionResolution disposableCollectionResolution); + DisposableCollectionResolution disposableCollectionResolution, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters); void DoWork(); @@ -39,7 +40,6 @@ internal abstract class RangeResolutionBaseBuilder protected readonly IDictionary RangedInstanceReferenceResolutions = new Dictionary(SymbolEqualityComparer.Default); protected readonly HashSet<(RangedInstanceFunction, string)> RangedInstanceQueuedOverloads = new (); - protected readonly HashSet<(RangedInstanceFunction, string)> RangedInstanceDoneOverloads = new (); protected readonly Queue<(RangedInstanceFunction, IReadOnlyList<(ITypeSymbol, ParameterResolution)>, INamedTypeSymbol)> RangedInstanceResolutionsQueue = new(); protected readonly List<(RangedInstanceFunction, RangedInstanceFunctionOverload)> RangedInstances = new (); @@ -85,7 +85,8 @@ protected abstract RangedInstanceReferenceResolution CreateSingleInstanceReferen protected abstract ScopeRootResolution CreateScopeRootResolution( INamedTypeSymbol rootType, IReferenceGenerator referenceGenerator, - DisposableCollectionResolution disposableCollectionResolution); + DisposableCollectionResolution disposableCollectionResolution, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters); protected Resolvable Create( ITypeSymbol type, @@ -235,7 +236,7 @@ protected Resolvable CreateConstructorResolution( return CreateSingleInstanceReferenceResolution(implementationType, referenceGenerator, currentParameters); if (!skipScopeRootCheck && CheckTypeProperties.ShouldBeScopeRoot(implementationType)) - return CreateScopeRootResolution(implementationType, referenceGenerator, DisposableCollectionResolution); + return CreateScopeRootResolution(implementationType, referenceGenerator, DisposableCollectionResolution, currentParameters); if (!skipRangedInstanceCheck && CheckTypeProperties.ShouldBeScopedInstance(implementationType)) return CreateScopedInstanceReferenceResolution(implementationType, referenceGenerator, currentParameters); @@ -309,10 +310,6 @@ protected RangedInstanceReferenceResolution CreateRangedInstanceReferenceResolut RootReferenceGenerator.Generate($"_{label.ToLower()}InstanceField", implementationType), RootReferenceGenerator.Generate($"_{label.ToLower()}InstanceLock")); RangedInstanceReferenceResolutions[implementationType] = function; - var parameter = currentParameters - .Select(t => (t.Type, new ParameterResolution(RootReferenceGenerator.Generate(t.Type), t.Type.FullName()))) - .ToList(); - RangedInstanceResolutionsQueue.Enqueue((function, parameter, implementationType)); } var listedParameterTypes = string.Join(",", currentParameters.Select(p => p.Item2.TypeFullName)); @@ -337,9 +334,6 @@ protected void DoRangedInstancesWork() while (RangedInstanceResolutionsQueue.Any()) { var (scopedInstanceFunction, parameter, type) = RangedInstanceResolutionsQueue.Dequeue(); - var listedParameterTypes = string.Join(",", parameter.Select(p => p.Item2.TypeFullName)); - if (RangedInstanceDoneOverloads.Contains((scopedInstanceFunction, listedParameterTypes))) - continue; var referenceGenerator = ReferenceGeneratorFactory.Create(); var resolvable = CreateConstructorResolution( type, @@ -351,7 +345,6 @@ protected void DoRangedInstancesWork() new RangedInstanceFunctionOverload( resolvable, parameter.Select(t => t.Item2).ToList()))); - RangedInstanceDoneOverloads.Add((scopedInstanceFunction, listedParameterTypes)); } } @@ -400,6 +393,7 @@ public void AddCreateResolveFunctions(IReadOnlyList rootTypes) typeSymbol, ReferenceGeneratorFactory.Create(), Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>()), + Array.Empty(), WellKnownTypes.Container.Construct(typeSymbol).FullName(), _containerInfo.Name, DisposalHandling)); @@ -423,9 +417,17 @@ protected override RangedInstanceReferenceResolution CreateSingleInstanceReferen IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) => CreateSingleInstanceReferenceResolution(implementationType, referenceGenerator, "this", currentParameters); - protected override ScopeRootResolution CreateScopeRootResolution(INamedTypeSymbol rootType, IReferenceGenerator referenceGenerator, - DisposableCollectionResolution disposableCollectionResolution) => - _scopeResolutionBuilder.AddCreateResolveFunction(rootType, referenceGenerator, "this", disposableCollectionResolution); + protected override ScopeRootResolution CreateScopeRootResolution( + INamedTypeSymbol rootType, + IReferenceGenerator referenceGenerator, + DisposableCollectionResolution disposableCollectionResolution, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) => + _scopeResolutionBuilder.AddCreateResolveFunction( + rootType, + referenceGenerator, + "this", + disposableCollectionResolution, + currentParameters); public ContainerResolution Build() { @@ -458,7 +460,8 @@ internal class ScopeResolutionBuilder : RangeResolutionBaseBuilder, IScopeResolu private readonly IDictionary _scopeRootFunctionResolutions = new Dictionary(SymbolEqualityComparer.Default); - private readonly Queue _scopeRootFunctionResolutionsQueue = new(); + private readonly HashSet<(ScopeRootFunction, string)> _scopeRootFunctionQueuedOverloads = new (); + private readonly Queue<(ScopeRootFunction, IReadOnlyList<(ITypeSymbol, ParameterResolution)>, INamedTypeSymbol)> _scopeRootFunctionResolutionsQueue = new(); public ScopeResolutionBuilder( // parameter @@ -485,9 +488,17 @@ protected override RangedInstanceReferenceResolution CreateSingleInstanceReferen _containerReference, currentParameters); - protected override ScopeRootResolution CreateScopeRootResolution(INamedTypeSymbol rootType, IReferenceGenerator referenceGenerator, - DisposableCollectionResolution disposableCollectionResolution) => - AddCreateResolveFunction(rootType, referenceGenerator, _containerReference, disposableCollectionResolution); + protected override ScopeRootResolution CreateScopeRootResolution( + INamedTypeSymbol rootType, + IReferenceGenerator referenceGenerator, + DisposableCollectionResolution disposableCollectionResolution, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) => + AddCreateResolveFunction( + rootType, + referenceGenerator, + _containerReference, + disposableCollectionResolution, + currentParameters); public bool HasWorkToDo => _scopeRootFunctionResolutionsQueue.Any() || RangedInstanceResolutionsQueue.Any(); @@ -495,7 +506,8 @@ public ScopeRootResolution AddCreateResolveFunction( INamedTypeSymbol rootType, IReferenceGenerator referenceGenerator, string singleInstanceScopeReference, - DisposableCollectionResolution disposableCollectionResolution) + DisposableCollectionResolution disposableCollectionResolution, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) { if (!_scopeRootFunctionResolutions.TryGetValue( rootType, @@ -503,10 +515,18 @@ public ScopeRootResolution AddCreateResolveFunction( { function = new ScopeRootFunction( RootReferenceGenerator.Generate("Create", rootType), - rootType.FullName(), - rootType); + rootType.FullName()); _scopeRootFunctionResolutions[rootType] = function; - _scopeRootFunctionResolutionsQueue.Enqueue(function); + } + + var listedParameterTypes = string.Join(",", currentParameters.Select(p => p.Item2.TypeFullName)); + if (!_scopeRootFunctionQueuedOverloads.Contains((function, listedParameterTypes))) + { + var parameter = currentParameters + .Select(t => (t.Type, new ParameterResolution(RootReferenceGenerator.Generate(t.Type), t.Type.FullName()))) + .ToList(); + _scopeRootFunctionResolutionsQueue.Enqueue((function, parameter, rootType)); + _scopeRootFunctionQueuedOverloads.Add((function, listedParameterTypes)); } return new ScopeRootResolution( @@ -515,6 +535,7 @@ public ScopeRootResolution AddCreateResolveFunction( referenceGenerator.Generate("scopeRoot"), Name, singleInstanceScopeReference, + currentParameters.Select(t => t.Resolution).ToList(), disposableCollectionResolution, function); } @@ -525,17 +546,18 @@ public void DoWork() { while (_scopeRootFunctionResolutionsQueue.Any()) { - var scopeRootFunction = _scopeRootFunctionResolutionsQueue.Dequeue(); + var (scopeRootFunction, parameter, type) = _scopeRootFunctionResolutionsQueue.Dequeue(); var resolvable = CreateConstructorResolution( - scopeRootFunction.Type, + type, ReferenceGeneratorFactory.Create(), - Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>(), + parameter, skipScopeRootCheck: true); _rootResolutions.Add(new RootResolutionFunction( scopeRootFunction.Reference, - scopeRootFunction.Type.FullName(), + type.FullName(), "internal", resolvable, + parameter.Select(t => t.Item2).ToList(), "", Name, DisposalHandling)); diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index 9f0acc59..94fc5fd7 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -11,6 +11,7 @@ internal record RootResolutionFunction( string TypeFullName, string AccessModifier, Resolvable Resolvable, + IReadOnlyList Parameter, string ExplicitImplementationFullName, string RangeName, DisposalHandling DisposalHandling) : Resolvable(Reference, TypeFullName); @@ -35,13 +36,13 @@ internal record ScopeRootResolution( string ScopeReference, string ScopeTypeFullName, string SingleInstanceScopeReference, + IReadOnlyList Parameter, DisposableCollectionResolution DisposableCollectionResolution, ScopeRootFunction ScopeRootFunction) : Resolvable(Reference, TypeFullName); internal record ScopeRootFunction( string Reference, - string TypeFullName, - INamedTypeSymbol Type) : Resolvable(Reference, TypeFullName); + string TypeFullName) : Resolvable(Reference, TypeFullName); internal record RangedInstance( RangedInstanceFunction Function, diff --git a/SampleChild/InternalChild.cs b/SampleChild/InternalChild.cs index 819af9e3..0877357e 100644 --- a/SampleChild/InternalChild.cs +++ b/SampleChild/InternalChild.cs @@ -8,7 +8,8 @@ internal class InternalChild : IInternalChild, IDisposable, IScopedInstance { public InternalChild( Lazy yetAnotherInternalChild, - IAndThenAnotherScope andThenAnotherScope) + Func andThenAnotherScopeA, + Func andThenAnotherScopeB) { } @@ -22,6 +23,9 @@ public interface IAndThenAnotherScope {} internal class AndThenAnotherScope : IAndThenAnotherScope, IDisposable, IScopedInstance, IScopeRoot { + public AndThenAnotherScope( + IA a, + IB b){} public void Dispose() { } From c53341b738c7d8b3e8f8090500e6423e337acdd0 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sun, 28 Nov 2021 17:55:28 +0100 Subject: [PATCH 024/162] Implemented decorator pattern --- Main/Attributes.cs | 7 + Main/CheckTypeProperties.cs | 45 +- Main/ExecuteImpl.cs | 3 +- Main/GetAllImplementations.cs | 4 +- Main/ReferenceGenerator.cs | 13 +- .../ContainerResolutionBuilder.cs | 112 ++++ .../RangeResolutionBaseBuilder.cs} | 499 +++++++----------- .../ScopeResolutionBuilder.cs | 190 +++++++ Main/SourceGenerator.cs | 14 +- Main/TypeToImplementationMapper.cs | 6 +- Main/TypesFromAttributes.cs | 8 +- Main/WellKnownTypes.cs | 6 + MrMeeseeks.DIE.sln | 12 +- Sample/Container.cs | 12 +- Sample/Context.cs | 29 +- {SampleChild => Sample}/MarkerInterfaces.cs | 5 +- Sample/Program.cs | 15 +- Sample/Sample.csproj | 4 +- Sample/StrongInjectContainer.cs | 19 - SampleChild/AssemblyInfo.cs | 3 - SampleChild/Child.cs | 16 - SampleChild/InternalChild.cs | 63 --- SampleChild/SampleChild.csproj | 19 - Test/DecoratorTests.cs | 126 +++++ Test/MarkerInterfaces.cs | 7 + Test/Test.csproj | 33 ++ 26 files changed, 766 insertions(+), 504 deletions(-) create mode 100644 Main/ResolutionBuilding/ContainerResolutionBuilder.cs rename Main/{ResolutionTreeFactory.cs => ResolutionBuilding/RangeResolutionBaseBuilder.cs} (52%) create mode 100644 Main/ResolutionBuilding/ScopeResolutionBuilder.cs rename {SampleChild => Sample}/MarkerInterfaces.cs (51%) delete mode 100644 Sample/StrongInjectContainer.cs delete mode 100644 SampleChild/AssemblyInfo.cs delete mode 100644 SampleChild/Child.cs delete mode 100644 SampleChild/InternalChild.cs delete mode 100644 SampleChild/SampleChild.csproj create mode 100644 Test/DecoratorTests.cs create mode 100644 Test/MarkerInterfaces.cs create mode 100644 Test/Test.csproj diff --git a/Main/Attributes.cs b/Main/Attributes.cs index a54f4426..5c60ab97 100644 --- a/Main/Attributes.cs +++ b/Main/Attributes.cs @@ -33,4 +33,11 @@ public class ScopeRootAttribute : Attribute { // ReSharper disable once UnusedParameter.Local *** Is used in the generator public ScopeRootAttribute(params Type[] type) {} +} + +[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] +public class DecoratorAttribute : Attribute +{ + // ReSharper disable once UnusedParameter.Local *** Is used in the generator + public DecoratorAttribute(params Type[] type) {} } \ No newline at end of file diff --git a/Main/CheckTypeProperties.cs b/Main/CheckTypeProperties.cs index 54d5c6ac..ab3035aa 100644 --- a/Main/CheckTypeProperties.cs +++ b/Main/CheckTypeProperties.cs @@ -2,10 +2,13 @@ namespace MrMeeseeks.DIE; public interface ICheckTypeProperties { - bool ShouldBeManaged(INamedTypeSymbol type); - bool ShouldBeSingleInstance(INamedTypeSymbol type); - bool ShouldBeScopedInstance(INamedTypeSymbol type); - bool ShouldBeScopeRoot(INamedTypeSymbol type); + bool ShouldBeManaged(INamedTypeSymbol implementationType); + bool ShouldBeSingleInstance(INamedTypeSymbol implementationType); + bool ShouldBeScopedInstance(INamedTypeSymbol implementationType); + bool ShouldBeScopeRoot(INamedTypeSymbol implementationType); + bool ShouldBeDecorated(INamedTypeSymbol interfaceType); + bool IsDecorator(INamedTypeSymbol implementationType); + IReadOnlyList GetDecorators(INamedTypeSymbol interfaceType); } internal class CheckTypeProperties : ICheckTypeProperties @@ -14,6 +17,8 @@ internal class CheckTypeProperties : ICheckTypeProperties private readonly IImmutableSet _singleInstanceTypes; private readonly IImmutableSet _scopedInstanceTypes; private readonly IImmutableSet _scopeRootTypes; + private readonly IImmutableSet _decoratorTypes; + private readonly IDictionary> _interfaceToDecorators; public CheckTypeProperties( IGetAllImplementations getAllImplementations, @@ -23,14 +28,26 @@ public CheckTypeProperties( _singleInstanceTypes = GetSetOfTypesWithProperties(typesFromAttributes.SingleInstance); _scopedInstanceTypes = GetSetOfTypesWithProperties(typesFromAttributes.ScopedInstance); _scopeRootTypes = GetSetOfTypesWithProperties(typesFromAttributes.ScopeRoot); - + _decoratorTypes = GetSetOfTypesWithProperties(typesFromAttributes.Decorator); + _interfaceToDecorators = _decoratorTypes + .OfType() + .GroupBy(nts => + { + var namedTypeSymbol = nts.AllInterfaces + .Single(t => + typesFromAttributes.Decorator.Contains(t.OriginalDefinition, SymbolEqualityComparer.Default)); + return namedTypeSymbol.TypeArguments.First(); + }, SymbolEqualityComparer.Default) + .ToDictionary(g => g.Key, g => g.ToList(), SymbolEqualityComparer.Default); + IImmutableSet GetSetOfTypesWithProperties(IReadOnlyList propertyGivingTypes) => getAllImplementations .AllImplementations .Where(i => { - var derivedTypes = AllDerivedTypes(i); - return propertyGivingTypes.Any(t => derivedTypes.Contains(t, SymbolEqualityComparer.Default)); + var derivedTypes = AllDerivedTypes(i).Select(t => t.OriginalDefinition).ToList(); + return propertyGivingTypes.Any(t => derivedTypes.Contains(t.OriginalDefinition, SymbolEqualityComparer.Default)); }) + .Distinct(SymbolEqualityComparer.Default) .ToImmutableHashSet(SymbolEqualityComparer.Default); IEnumerable AllDerivedTypes(INamedTypeSymbol type) @@ -49,8 +66,14 @@ IEnumerable AllDerivedTypes(INamedTypeSymbol type) } } - public bool ShouldBeManaged(INamedTypeSymbol type) => !_transientTypes.Contains(type); - public bool ShouldBeSingleInstance(INamedTypeSymbol type) => _singleInstanceTypes.Contains(type); - public bool ShouldBeScopedInstance(INamedTypeSymbol type) => _scopedInstanceTypes.Contains(type); - public bool ShouldBeScopeRoot(INamedTypeSymbol type) => _scopeRootTypes.Contains(type); + public bool ShouldBeManaged(INamedTypeSymbol implementationType) => !_transientTypes.Contains(implementationType); + public bool ShouldBeSingleInstance(INamedTypeSymbol implementationType) => _singleInstanceTypes.Contains(implementationType); + public bool ShouldBeScopedInstance(INamedTypeSymbol implementationType) => _scopedInstanceTypes.Contains(implementationType); + public bool ShouldBeScopeRoot(INamedTypeSymbol implementationType) => _scopeRootTypes.Contains(implementationType); + public bool ShouldBeDecorated(INamedTypeSymbol interfaceType) => _interfaceToDecorators.ContainsKey(interfaceType); + public bool IsDecorator(INamedTypeSymbol implementationType) => _decoratorTypes.Contains(implementationType); + public IReadOnlyList GetDecorators(INamedTypeSymbol interfaceType) => + _interfaceToDecorators.TryGetValue(interfaceType, out var ret) + ? ret + : Array.Empty(); } \ No newline at end of file diff --git a/Main/ExecuteImpl.cs b/Main/ExecuteImpl.cs index cec9bbaa..831b8f4f 100644 --- a/Main/ExecuteImpl.cs +++ b/Main/ExecuteImpl.cs @@ -1,4 +1,5 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; +using MrMeeseeks.DIE.ResolutionBuilding; namespace MrMeeseeks.DIE; @@ -49,7 +50,7 @@ public void Execute() .DescendantNodesAndSelf() .OfType() .Select(x => semanticModel.GetDeclaredSymbol(x)) - .Where(x => x != null) + .Where(x => x is not null) .OfType() .Where(x => x.AllInterfaces.Any(x => x.OriginalDefinition.Equals(_wellKnownTypes.Container, SymbolEqualityComparer.Default))); foreach (var namedTypeSymbol in containerClasses) diff --git a/Main/GetAllImplementations.cs b/Main/GetAllImplementations.cs index 48560391..c9ae9ee5 100644 --- a/Main/GetAllImplementations.cs +++ b/Main/GetAllImplementations.cs @@ -31,7 +31,9 @@ public GetAllImplementations( .Select(ms => ms.ReturnType) .OfType()); - AllImplementations = implementationsOfThisAssembly.Concat(spiedImplementations).ToList(); + AllImplementations = implementationsOfThisAssembly + .Concat(spiedImplementations) + .ToList(); } public IReadOnlyList AllImplementations { get; } diff --git a/Main/ReferenceGenerator.cs b/Main/ReferenceGenerator.cs index de90089b..c3d73cce 100644 --- a/Main/ReferenceGenerator.cs +++ b/Main/ReferenceGenerator.cs @@ -4,6 +4,7 @@ public interface IReferenceGenerator { string Generate(ITypeSymbol type); string Generate(string prefix, ITypeSymbol type); + string Generate(string prefix, ITypeSymbol type, string suffix); string Generate(string hardcodedName); } @@ -15,13 +16,19 @@ internal class ReferenceGenerator : IReferenceGenerator public ReferenceGenerator(int j) => _j = j; public string Generate(ITypeSymbol type) => - Generate($"{char.ToLower(type.Name[0])}{type.Name.Substring(1)}"); + GenerateInner(string.Empty, $"{char.ToLower(type.Name[0])}{type.Name.Substring(1)}", string.Empty); public string Generate(string prefix, ITypeSymbol type) => - Generate($"{prefix}{type.Name}"); + GenerateInner(prefix, type.Name, string.Empty); + + public string Generate(string prefix, ITypeSymbol type, string suffix) => + GenerateInner(prefix, type.Name, suffix); public string Generate(string hardcodedName) => - $"{hardcodedName}_{_j}_{++_i}"; + GenerateInner(string.Empty, hardcodedName, string.Empty); + + private string GenerateInner(string prefix, string inner, string suffix) => + $"{prefix}{inner}{suffix}_{_j}_{++_i}"; } public interface IReferenceGeneratorFactory diff --git a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs new file mode 100644 index 00000000..75ac3dff --- /dev/null +++ b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs @@ -0,0 +1,112 @@ +namespace MrMeeseeks.DIE.ResolutionBuilding; + +internal interface IContainerResolutionBuilder +{ + void AddCreateResolveFunctions(IReadOnlyList rootTypes); + + RangedInstanceReferenceResolution CreateSingleInstanceReferenceResolution( + INamedTypeSymbol implementationType, + IReferenceGenerator referenceGenerator, + string containerReference, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters, + RangeResolutionBaseBuilder.Decoration? decoration); + + ContainerResolution Build(); +} + +internal class ContainerResolutionBuilder : RangeResolutionBaseBuilder, IContainerResolutionBuilder +{ + private readonly IContainerInfo _containerInfo; + + private readonly List _rootResolutions = new (); + private readonly IScopeResolutionBuilder _scopeResolutionBuilder; + + public ContainerResolutionBuilder( + // parameters + IContainerInfo containerInfo, + + // dependencies + ITypeToImplementationsMapper typeToImplementationsMapper, + IReferenceGeneratorFactory referenceGeneratorFactory, + ICheckTypeProperties checkTypeProperties, + WellKnownTypes wellKnownTypes, + Func scopeResolutionBuilderFactory) + : base((containerInfo.Name, false), wellKnownTypes, typeToImplementationsMapper, referenceGeneratorFactory, checkTypeProperties) + { + _containerInfo = containerInfo; + _scopeResolutionBuilder = scopeResolutionBuilderFactory(this); + } + + public void AddCreateResolveFunctions(IReadOnlyList rootTypes) + { + foreach (var typeSymbol in rootTypes) + _rootResolutions.Add(new RootResolutionFunction( + nameof(IContainer.Resolve), + typeSymbol.FullName(), + "", + Create( + typeSymbol, + ReferenceGeneratorFactory.Create(), + Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>()), + Array.Empty(), + WellKnownTypes.Container.Construct(typeSymbol).FullName(), + _containerInfo.Name, + DisposalHandling)); + } + + public RangedInstanceReferenceResolution CreateSingleInstanceReferenceResolution( + INamedTypeSymbol implementationType, + IReferenceGenerator referenceGenerator, + string containerReference, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters, + Decoration? decoration) => + CreateRangedInstanceReferenceResolution( + implementationType, + referenceGenerator, + currentParameters, + "Single", + containerReference, + decoration); + + protected override RangedInstanceReferenceResolution CreateSingleInstanceReferenceResolution( + INamedTypeSymbol implementationType, + IReferenceGenerator referenceGenerator, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters, + Decoration? decoration) => + CreateSingleInstanceReferenceResolution(implementationType, referenceGenerator, "this", currentParameters, decoration); + + protected override ScopeRootResolution CreateScopeRootResolution( + INamedTypeSymbol rootType, + IReferenceGenerator referenceGenerator, + DisposableCollectionResolution disposableCollectionResolution, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters, + DecorationScopeRoot? decoration) => + _scopeResolutionBuilder.AddCreateResolveFunction( + rootType, + referenceGenerator, + "this", + disposableCollectionResolution, + currentParameters, + decoration); + + public ContainerResolution Build() + { + while (RangedInstanceResolutionsQueue.Any() || _scopeResolutionBuilder.HasWorkToDo) + { + DoRangedInstancesWork(); + _scopeResolutionBuilder.DoWork(); + } + + return new( + _rootResolutions, + DisposalHandling, + RangedInstances + .GroupBy(t => t.Item1) + .Select(g => new RangedInstance( + g.Key, + g.Select(t => t.Item2).ToList(), + DisposalHandling)) + .ToList(), + _scopeResolutionBuilder.Build()); + } +} \ No newline at end of file diff --git a/Main/ResolutionTreeFactory.cs b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs similarity index 52% rename from Main/ResolutionTreeFactory.cs rename to Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs index 361bbff8..462b9191 100644 --- a/Main/ResolutionTreeFactory.cs +++ b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs @@ -1,46 +1,34 @@ -namespace MrMeeseeks.DIE; - -internal interface IContainerResolutionBuilder -{ - void AddCreateResolveFunctions(IReadOnlyList rootTypes); - - RangedInstanceReferenceResolution CreateSingleInstanceReferenceResolution( - INamedTypeSymbol implementationType, - IReferenceGenerator referenceGenerator, - string containerReference, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters); - - ContainerResolution Build(); -} - -internal interface IScopeResolutionBuilder -{ - bool HasWorkToDo { get; } - - ScopeRootResolution AddCreateResolveFunction( - INamedTypeSymbol rootType, - IReferenceGenerator referenceGenerator, - string singleInstanceScopeReference, - DisposableCollectionResolution disposableCollectionResolution, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters); - - void DoWork(); - - ScopeResolution Build(); -} +namespace MrMeeseeks.DIE.ResolutionBuilding; internal abstract class RangeResolutionBaseBuilder { + public record DecorationScopeRoot( + INamedTypeSymbol InterfaceType, + INamedTypeSymbol ImplementationType); + public record Decoration( + INamedTypeSymbol InterfaceType, + INamedTypeSymbol ImplementationType, + INamedTypeSymbol DecoratorType, + InterfaceResolution CurrentInterfaceResolution); + + [Flags] + public enum Skip + { + None = 1<<0, + RangedInstanceCheck = 1<<1, + ScopeRootCheck = 1<<2 + } + protected readonly WellKnownTypes WellKnownTypes; protected readonly ITypeToImplementationsMapper TypeToImplementationsMapper; protected readonly IReferenceGeneratorFactory ReferenceGeneratorFactory; protected readonly ICheckTypeProperties CheckTypeProperties; protected readonly IReferenceGenerator RootReferenceGenerator; - protected readonly IDictionary RangedInstanceReferenceResolutions = - new Dictionary(SymbolEqualityComparer.Default); + protected readonly IDictionary RangedInstanceReferenceResolutions = + new Dictionary(); protected readonly HashSet<(RangedInstanceFunction, string)> RangedInstanceQueuedOverloads = new (); - protected readonly Queue<(RangedInstanceFunction, IReadOnlyList<(ITypeSymbol, ParameterResolution)>, INamedTypeSymbol)> RangedInstanceResolutionsQueue = new(); + protected readonly Queue<(RangedInstanceFunction, IReadOnlyList<(ITypeSymbol, ParameterResolution)>, INamedTypeSymbol, Decoration?)> RangedInstanceResolutionsQueue = new(); protected readonly List<(RangedInstanceFunction, RangedInstanceFunctionOverload)> RangedInstances = new (); protected readonly DisposableCollectionResolution DisposableCollectionResolution; @@ -80,13 +68,15 @@ protected RangeResolutionBaseBuilder( protected abstract RangedInstanceReferenceResolution CreateSingleInstanceReferenceResolution( INamedTypeSymbol implementationType, IReferenceGenerator referenceGenerator, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters); + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters, + Decoration? decoration); protected abstract ScopeRootResolution CreateScopeRootResolution( INamedTypeSymbol rootType, IReferenceGenerator referenceGenerator, DisposableCollectionResolution disposableCollectionResolution, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters); + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters, + DecorationScopeRoot? decoration); protected Resolvable Create( ITypeSymbol type, @@ -163,27 +153,10 @@ protected Resolvable Create( } if (type.TypeKind == TypeKind.Interface) - { - var implementations = TypeToImplementationsMapper - .Map(type); - if (implementations - .SingleOrDefault() is not { } implementationType) - { - return new ErrorTreeItem(implementations.Count switch - { - 0 => $"[{type.FullName()}] Interface: No implementation found", - > 1 => $"[{type.FullName()}] Interface: more than one implementation found", - _ => $"[{type.FullName()}] Interface: Found single implementation {implementations[0].FullName()} is not a named type symbol" - }); - } - return new InterfaceResolution( - referenceGenerator.Generate(type), - type.FullName(), - Create(implementationType, referenceGenerator, currentFuncParameters)); - } + return CreateInterfaceResolution(type, referenceGenerator, currentFuncParameters); if (type.TypeKind == TypeKind.Class) - return CreateConstructorResolution(type, referenceGenerator, currentFuncParameters); + return CreateConstructorResolution(type, referenceGenerator, currentFuncParameters, Skip.None); if (type.TypeKind == TypeKind.Delegate && type.FullName().StartsWith("global::System.Func<") @@ -211,17 +184,77 @@ protected Resolvable Create( return new ErrorTreeItem($"[{type.FullName()}] Couldn't process in resolution tree creation."); } - protected Resolvable CreateConstructorResolution( + private Resolvable CreateInterfaceResolution( ITypeSymbol typeSymbol, IReferenceGenerator referenceGenerator, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters, - bool skipRangedInstanceCheck = false, - bool skipScopeRootCheck = false) + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) { + var interfaceType = (INamedTypeSymbol) typeSymbol; var implementations = TypeToImplementationsMapper .Map(typeSymbol); if (implementations .SingleOrDefault() is not { } implementationType) + { + return new ErrorTreeItem(implementations.Count switch + { + 0 => $"[{typeSymbol.FullName()}] Interface: No implementation found", + > 1 => $"[{typeSymbol.FullName()}] Interface: more than one implementation found", + _ => $"[{typeSymbol.FullName()}] Interface: Found single implementation {implementations[0].FullName()} is not a named type symbol" + }); + } + + var shouldBeDecorated = CheckTypeProperties.ShouldBeDecorated(interfaceType); + + if (shouldBeDecorated && CheckTypeProperties.ShouldBeScopeRoot(implementationType)) + { + var rootResolution = CreateScopeRootResolution( + interfaceType, + referenceGenerator, + DisposableCollectionResolution, + currentParameters, + new DecorationScopeRoot(interfaceType, implementationType)); + return new InterfaceResolution( + referenceGenerator.Generate(typeSymbol), + typeSymbol.FullName(), + rootResolution); + } + + var currentInterfaceResolution = new InterfaceResolution( + referenceGenerator.Generate(typeSymbol), + typeSymbol.FullName(), + Create(implementationType, referenceGenerator, currentParameters)); + + if (shouldBeDecorated) + { + var decorators = new Stack(CheckTypeProperties.GetDecorators(interfaceType)); + while (decorators.Any()) + { + var decorator = decorators.Pop(); + var decoratorResolution = CreateDecoratorConstructorResolution( + new Decoration(interfaceType, implementationType, decorator, currentInterfaceResolution), + referenceGenerator, + currentParameters, + Skip.None); + currentInterfaceResolution = new InterfaceResolution( + referenceGenerator.Generate(typeSymbol), + typeSymbol.FullName(), + decoratorResolution); + } + } + + return currentInterfaceResolution; + } + + protected Resolvable CreateConstructorResolution( + ITypeSymbol typeSymbol, + IReferenceGenerator referenceGenerator, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters, + Skip skip) + { + var implementations = TypeToImplementationsMapper + .Map(typeSymbol); + var implementationType = implementations.SingleOrDefault(); + if (implementationType is not { }) { return new ErrorTreeItem(implementations.Count switch { @@ -232,25 +265,22 @@ protected Resolvable CreateConstructorResolution( }); } - if (!skipRangedInstanceCheck && CheckTypeProperties.ShouldBeSingleInstance(implementationType)) - return CreateSingleInstanceReferenceResolution(implementationType, referenceGenerator, currentParameters); + if (!skip.HasFlag(Skip.RangedInstanceCheck) && CheckTypeProperties.ShouldBeSingleInstance(implementationType)) + return CreateSingleInstanceReferenceResolution(implementationType, referenceGenerator, currentParameters, null); - if (!skipScopeRootCheck && CheckTypeProperties.ShouldBeScopeRoot(implementationType)) - return CreateScopeRootResolution(implementationType, referenceGenerator, DisposableCollectionResolution, currentParameters); + if (!skip.HasFlag(Skip.ScopeRootCheck) && CheckTypeProperties.ShouldBeScopeRoot(implementationType)) + return CreateScopeRootResolution(implementationType, referenceGenerator, DisposableCollectionResolution, currentParameters, null); - if (!skipRangedInstanceCheck && CheckTypeProperties.ShouldBeScopedInstance(implementationType)) - return CreateScopedInstanceReferenceResolution(implementationType, referenceGenerator, currentParameters); + if (!skip.HasFlag(Skip.RangedInstanceCheck) && CheckTypeProperties.ShouldBeScopedInstance(implementationType)) + return CreateScopedInstanceReferenceResolution(implementationType, referenceGenerator, currentParameters, null); if (implementationType.Constructors.SingleOrDefault() is not { } constructor) { - return new ErrorTreeItem(implementations.Count switch + return new ErrorTreeItem(implementationType.Constructors.Length switch { - 0 => - $"[{typeSymbol.FullName()}] Class.Constructor: No constructor found for implementation {implementationType.FullName()}", - > 1 => - $"[{typeSymbol.FullName()}] Class.Constructor: More than one constructor found for implementation {implementationType.FullName()}", - _ => - $"[{typeSymbol.FullName()}] Class.Constructor: {implementationType.Constructors[0].Name} is not a method symbol" + 0 => $"[{typeSymbol.FullName()}] Class.Constructor: No constructor found for implementation {implementationType.FullName()}", + > 1 => $"[{typeSymbol.FullName()}] Class.Constructor: More than one constructor found for implementation {implementationType.FullName()}", + _ => $"[{typeSymbol.FullName()}] Class.Constructor: {implementationType.Constructors[0].Name} is not a method symbol" }); } @@ -282,34 +312,105 @@ protected Resolvable CreateConstructorResolution( .ToList())); } + protected Resolvable CreateDecoratorConstructorResolution( + Decoration decoration, + IReferenceGenerator referenceGenerator, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters, + Skip skip) + { + var decoratorType = decoration.DecoratorType; + if (!skip.HasFlag(Skip.RangedInstanceCheck) && CheckTypeProperties.ShouldBeSingleInstance(decoration.ImplementationType)) + return CreateSingleInstanceReferenceResolution(decoratorType, referenceGenerator, currentParameters, decoration); + + //if (!skipScopeRootCheck && CheckTypeProperties.ShouldBeScopeRoot(implementationType)) + // return CreateScopeRootResolution(implementationType, referenceGenerator, DisposableCollectionResolution, currentParameters); + + if (!skip.HasFlag(Skip.RangedInstanceCheck) && CheckTypeProperties.ShouldBeScopedInstance(decoration.ImplementationType)) + return CreateScopedInstanceReferenceResolution(decoratorType, referenceGenerator, currentParameters, decoration); + + if (decoratorType.Constructors.SingleOrDefault() is not { } constructor) + { + return new ErrorTreeItem(decoratorType.Constructors.Length switch + { + 0 => + $"[{decoratorType.FullName()}] Class.Constructor: No constructor found for implementation {decoratorType.FullName()}", + > 1 => + $"[{decoratorType.FullName()}] Class.Constructor: More than one constructor found for implementation {decoratorType.FullName()}", + _ => + $"[{decoratorType.FullName()}] Class.Constructor: {decoratorType.Constructors[0].Name} is not a method symbol" + }); + } + + return new ConstructorResolution( + referenceGenerator.Generate(decoratorType), + decoratorType.FullName(), + ImplementsIDisposable( + decoratorType, + WellKnownTypes, + DisposableCollectionResolution, + CheckTypeProperties), + new ReadOnlyCollection<(string Name, Resolvable Dependency)>(constructor + .Parameters + .Select(p => + { + if (p.Type.Equals(decoration.InterfaceType, SymbolEqualityComparer.Default)) + { + return (p.Name, decoration.CurrentInterfaceResolution); + } + if (p.Type is not INamedTypeSymbol parameterType) + { + return ("", + new ErrorTreeItem( + $"[{decoratorType.FullName()}] Class.Constructor.Parameter: Parameter type {p.Type.FullName()} is not a named type symbol")); + } + + return ( + p.Name, + Create(parameterType, + referenceGenerator, + currentParameters)); + }) + .ToList())); + } + private RangedInstanceReferenceResolution CreateScopedInstanceReferenceResolution( INamedTypeSymbol implementationType, IReferenceGenerator referenceGenerator, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) => + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters, + Decoration? decoration) => CreateRangedInstanceReferenceResolution( implementationType, referenceGenerator, currentParameters, "Scoped", - "this"); + "this", + decoration); protected RangedInstanceReferenceResolution CreateRangedInstanceReferenceResolution( INamedTypeSymbol implementationType, IReferenceGenerator referenceGenerator, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters, string label, - string owningObjectReference) + string owningObjectReference, + Decoration? decoration) { + var decorationKeySuffix = decoration is { } + ? $":::{decoration.ImplementationType}" + : ""; + var key = $"{implementationType.FullName()}{decorationKeySuffix}"; if (!RangedInstanceReferenceResolutions.TryGetValue( - implementationType, + key, out RangedInstanceFunction function)) { + var decorationSuffix = decoration is { } + ? $"_{decoration.ImplementationType.Name}" + : ""; function = new RangedInstanceFunction( - RootReferenceGenerator.Generate($"Get{label}Instance", implementationType), + RootReferenceGenerator.Generate($"Get{label}Instance", implementationType, decorationSuffix), implementationType.FullName(), - RootReferenceGenerator.Generate($"_{label.ToLower()}InstanceField", implementationType), - RootReferenceGenerator.Generate($"_{label.ToLower()}InstanceLock")); - RangedInstanceReferenceResolutions[implementationType] = function; + RootReferenceGenerator.Generate($"_{label.ToLower()}InstanceField", implementationType, decorationSuffix), + RootReferenceGenerator.Generate($"_{label.ToLower()}InstanceLock{decorationSuffix}")); + RangedInstanceReferenceResolutions[key] = function; } var listedParameterTypes = string.Join(",", currentParameters.Select(p => p.Item2.TypeFullName)); @@ -318,7 +419,7 @@ protected RangedInstanceReferenceResolution CreateRangedInstanceReferenceResolut var parameter = currentParameters .Select(t => (t.Type, new ParameterResolution(RootReferenceGenerator.Generate(t.Type), t.Type.FullName()))) .ToList(); - RangedInstanceResolutionsQueue.Enqueue((function, parameter, implementationType)); + RangedInstanceResolutionsQueue.Enqueue((function, parameter, implementationType, decoration)); RangedInstanceQueuedOverloads.Add((function, listedParameterTypes)); } @@ -333,13 +434,15 @@ protected void DoRangedInstancesWork() { while (RangedInstanceResolutionsQueue.Any()) { - var (scopedInstanceFunction, parameter, type) = RangedInstanceResolutionsQueue.Dequeue(); + var (scopedInstanceFunction, parameter, type, decoration) = RangedInstanceResolutionsQueue.Dequeue(); var referenceGenerator = ReferenceGeneratorFactory.Create(); - var resolvable = CreateConstructorResolution( - type, - referenceGenerator, - parameter, - true); + var resolvable = decoration is {} + ? CreateDecoratorConstructorResolution(decoration, referenceGenerator, parameter, Skip.RangedInstanceCheck) + : CreateConstructorResolution( + type, + referenceGenerator, + parameter, + Skip.RangedInstanceCheck); RangedInstances.Add(( scopedInstanceFunction, new RangedInstanceFunctionOverload( @@ -356,228 +459,4 @@ protected void DoRangedInstancesWork() type.AllInterfaces.Contains(wellKnownTypes.Disposable) && checkDisposalManagement.ShouldBeManaged(type) ? disposableCollectionResolution : null; -} - -internal class ContainerResolutionBuilder : RangeResolutionBaseBuilder, IContainerResolutionBuilder -{ - private readonly IContainerInfo _containerInfo; - - private readonly List _rootResolutions = new (); - private readonly IScopeResolutionBuilder _scopeResolutionBuilder; - - public ContainerResolutionBuilder( - // parameters - IContainerInfo containerInfo, - - // dependencies - ITypeToImplementationsMapper typeToImplementationsMapper, - IReferenceGeneratorFactory referenceGeneratorFactory, - ICheckTypeProperties checkTypeProperties, - WellKnownTypes wellKnownTypes, - Func scopeResolutionBuilderFactory) - : base((containerInfo.Name, false), wellKnownTypes, typeToImplementationsMapper, referenceGeneratorFactory, checkTypeProperties) - { - _containerInfo = containerInfo; - _scopeResolutionBuilder = scopeResolutionBuilderFactory(this); - } - - public void AddCreateResolveFunctions(IReadOnlyList rootTypes) - { - foreach (var typeSymbol in rootTypes) - _rootResolutions.Add( - new RootResolutionFunction( - nameof(IContainer.Resolve), - typeSymbol.FullName(), - "", - Create( - typeSymbol, - ReferenceGeneratorFactory.Create(), - Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>()), - Array.Empty(), - WellKnownTypes.Container.Construct(typeSymbol).FullName(), - _containerInfo.Name, - DisposalHandling)); - } - - public RangedInstanceReferenceResolution CreateSingleInstanceReferenceResolution( - INamedTypeSymbol implementationType, - IReferenceGenerator referenceGenerator, - string containerReference, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) => - CreateRangedInstanceReferenceResolution( - implementationType, - referenceGenerator, - currentParameters, - "Single", - containerReference); - - protected override RangedInstanceReferenceResolution CreateSingleInstanceReferenceResolution( - INamedTypeSymbol implementationType, - IReferenceGenerator referenceGenerator, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) => - CreateSingleInstanceReferenceResolution(implementationType, referenceGenerator, "this", currentParameters); - - protected override ScopeRootResolution CreateScopeRootResolution( - INamedTypeSymbol rootType, - IReferenceGenerator referenceGenerator, - DisposableCollectionResolution disposableCollectionResolution, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) => - _scopeResolutionBuilder.AddCreateResolveFunction( - rootType, - referenceGenerator, - "this", - disposableCollectionResolution, - currentParameters); - - public ContainerResolution Build() - { - while (RangedInstanceResolutionsQueue.Any() || _scopeResolutionBuilder.HasWorkToDo) - { - DoRangedInstancesWork(); - _scopeResolutionBuilder.DoWork(); - } - - return new( - _rootResolutions, - DisposalHandling, - RangedInstances - .GroupBy(t => t.Item1) - .Select(g => new RangedInstance( - g.Key, - g.Select(t => t.Item2).ToList(), - DisposalHandling)) - .ToList(), - _scopeResolutionBuilder.Build()); - } -} - -internal class ScopeResolutionBuilder : RangeResolutionBaseBuilder, IScopeResolutionBuilder -{ - private readonly IContainerResolutionBuilder _containerResolutionBuilder; - private readonly List _rootResolutions = new (); - private readonly string _containerReference; - private readonly string _containerParameterReference; - - private readonly IDictionary _scopeRootFunctionResolutions = - new Dictionary(SymbolEqualityComparer.Default); - private readonly HashSet<(ScopeRootFunction, string)> _scopeRootFunctionQueuedOverloads = new (); - private readonly Queue<(ScopeRootFunction, IReadOnlyList<(ITypeSymbol, ParameterResolution)>, INamedTypeSymbol)> _scopeRootFunctionResolutionsQueue = new(); - - public ScopeResolutionBuilder( - // parameter - IContainerResolutionBuilder containerResolutionBuilder, - - // dependencies - WellKnownTypes wellKnownTypes, - ITypeToImplementationsMapper typeToImplementationsMapper, - IReferenceGeneratorFactory referenceGeneratorFactory, - ICheckTypeProperties checkTypeProperties) : base(("DefaultScope", true), wellKnownTypes, typeToImplementationsMapper, referenceGeneratorFactory, checkTypeProperties) - { - _containerResolutionBuilder = containerResolutionBuilder; - _containerReference = RootReferenceGenerator.Generate("_container"); - _containerParameterReference = RootReferenceGenerator.Generate("container"); - } - - protected override RangedInstanceReferenceResolution CreateSingleInstanceReferenceResolution( - INamedTypeSymbol implementationType, - IReferenceGenerator referenceGenerator, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) => - _containerResolutionBuilder.CreateSingleInstanceReferenceResolution( - implementationType, - referenceGenerator, - _containerReference, - currentParameters); - - protected override ScopeRootResolution CreateScopeRootResolution( - INamedTypeSymbol rootType, - IReferenceGenerator referenceGenerator, - DisposableCollectionResolution disposableCollectionResolution, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) => - AddCreateResolveFunction( - rootType, - referenceGenerator, - _containerReference, - disposableCollectionResolution, - currentParameters); - - public bool HasWorkToDo => _scopeRootFunctionResolutionsQueue.Any() || RangedInstanceResolutionsQueue.Any(); - - public ScopeRootResolution AddCreateResolveFunction( - INamedTypeSymbol rootType, - IReferenceGenerator referenceGenerator, - string singleInstanceScopeReference, - DisposableCollectionResolution disposableCollectionResolution, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) - { - if (!_scopeRootFunctionResolutions.TryGetValue( - rootType, - out ScopeRootFunction function)) - { - function = new ScopeRootFunction( - RootReferenceGenerator.Generate("Create", rootType), - rootType.FullName()); - _scopeRootFunctionResolutions[rootType] = function; - } - - var listedParameterTypes = string.Join(",", currentParameters.Select(p => p.Item2.TypeFullName)); - if (!_scopeRootFunctionQueuedOverloads.Contains((function, listedParameterTypes))) - { - var parameter = currentParameters - .Select(t => (t.Type, new ParameterResolution(RootReferenceGenerator.Generate(t.Type), t.Type.FullName()))) - .ToList(); - _scopeRootFunctionResolutionsQueue.Enqueue((function, parameter, rootType)); - _scopeRootFunctionQueuedOverloads.Add((function, listedParameterTypes)); - } - - return new ScopeRootResolution( - referenceGenerator.Generate(rootType), - rootType.FullName(), - referenceGenerator.Generate("scopeRoot"), - Name, - singleInstanceScopeReference, - currentParameters.Select(t => t.Resolution).ToList(), - disposableCollectionResolution, - function); - } - - public void DoWork() - { - while (HasWorkToDo) - { - while (_scopeRootFunctionResolutionsQueue.Any()) - { - var (scopeRootFunction, parameter, type) = _scopeRootFunctionResolutionsQueue.Dequeue(); - var resolvable = CreateConstructorResolution( - type, - ReferenceGeneratorFactory.Create(), - parameter, - skipScopeRootCheck: true); - _rootResolutions.Add(new RootResolutionFunction( - scopeRootFunction.Reference, - type.FullName(), - "internal", - resolvable, - parameter.Select(t => t.Item2).ToList(), - "", - Name, - DisposalHandling)); - } - - DoRangedInstancesWork(); - } - } - - public ScopeResolution Build() => - new(_rootResolutions, - DisposalHandling, - RangedInstances - .GroupBy(t => t.Item1) - .Select(g => new RangedInstance( - g.Key, - g.Select(t => t.Item2).ToList(), - DisposalHandling)) - .ToList(), - _containerReference, - _containerParameterReference, - Name); } \ No newline at end of file diff --git a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs new file mode 100644 index 00000000..b88e9b46 --- /dev/null +++ b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs @@ -0,0 +1,190 @@ +namespace MrMeeseeks.DIE.ResolutionBuilding; + +internal interface IScopeResolutionBuilder +{ + bool HasWorkToDo { get; } + + ScopeRootResolution AddCreateResolveFunction( + INamedTypeSymbol rootType, + IReferenceGenerator referenceGenerator, + string singleInstanceScopeReference, + DisposableCollectionResolution disposableCollectionResolution, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters, + RangeResolutionBaseBuilder.DecorationScopeRoot? decoration); + + void DoWork(); + + ScopeResolution Build(); +} + +internal class ScopeResolutionBuilder : RangeResolutionBaseBuilder, IScopeResolutionBuilder +{ + private readonly IContainerResolutionBuilder _containerResolutionBuilder; + private readonly List _rootResolutions = new (); + private readonly string _containerReference; + private readonly string _containerParameterReference; + + private readonly Dictionary _scopeRootFunctionResolutions = new (); + private readonly HashSet<(ScopeRootFunction, string)> _scopeRootFunctionQueuedOverloads = new (); + private readonly Queue<(ScopeRootFunction, IReadOnlyList<(ITypeSymbol, ParameterResolution)>, INamedTypeSymbol, DecorationScopeRoot?)> _scopeRootFunctionResolutionsQueue = new(); + + public ScopeResolutionBuilder( + // parameter + IContainerResolutionBuilder containerResolutionBuilder, + + // dependencies + WellKnownTypes wellKnownTypes, + ITypeToImplementationsMapper typeToImplementationsMapper, + IReferenceGeneratorFactory referenceGeneratorFactory, + ICheckTypeProperties checkTypeProperties) : base(("DefaultScope", true), wellKnownTypes, typeToImplementationsMapper, referenceGeneratorFactory, checkTypeProperties) + { + _containerResolutionBuilder = containerResolutionBuilder; + _containerReference = RootReferenceGenerator.Generate("_container"); + _containerParameterReference = RootReferenceGenerator.Generate("container"); + } + + protected override RangedInstanceReferenceResolution CreateSingleInstanceReferenceResolution( + INamedTypeSymbol implementationType, + IReferenceGenerator referenceGenerator, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters, + Decoration? decoration) => + _containerResolutionBuilder.CreateSingleInstanceReferenceResolution( + implementationType, + referenceGenerator, + _containerReference, + currentParameters, + decoration); + + protected override ScopeRootResolution CreateScopeRootResolution( + INamedTypeSymbol rootType, + IReferenceGenerator referenceGenerator, + DisposableCollectionResolution disposableCollectionResolution, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters, + DecorationScopeRoot? decoration) => + AddCreateResolveFunction( + rootType, + referenceGenerator, + _containerReference, + disposableCollectionResolution, + currentParameters, + decoration); + + public bool HasWorkToDo => _scopeRootFunctionResolutionsQueue.Any() || RangedInstanceResolutionsQueue.Any(); + + public ScopeRootResolution AddCreateResolveFunction( + INamedTypeSymbol rootType, + IReferenceGenerator referenceGenerator, + string singleInstanceScopeReference, + DisposableCollectionResolution disposableCollectionResolution, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters, + DecorationScopeRoot? decoration) + { + var decorationKeySuffix = decoration is { } + ? $":::{decoration.ImplementationType}" + : ""; + var key = $"{rootType.FullName()}{decorationKeySuffix}"; + if (!_scopeRootFunctionResolutions.TryGetValue( + key, + out ScopeRootFunction function)) + { + var decorationSuffix = decoration is { } + ? $"_{decoration.ImplementationType.Name}" + : ""; + function = new ScopeRootFunction( + RootReferenceGenerator.Generate("Create", rootType, decorationSuffix), + rootType.FullName()); + _scopeRootFunctionResolutions[key] = function; + } + + var listedParameterTypes = string.Join(",", currentParameters.Select(p => p.Item2.TypeFullName)); + if (!_scopeRootFunctionQueuedOverloads.Contains((function, listedParameterTypes))) + { + var parameter = currentParameters + .Select(t => (t.Type, new ParameterResolution(RootReferenceGenerator.Generate(t.Type), t.Type.FullName()))) + .ToList(); + _scopeRootFunctionResolutionsQueue.Enqueue((function, parameter, rootType, decoration)); + _scopeRootFunctionQueuedOverloads.Add((function, listedParameterTypes)); + } + + return new ScopeRootResolution( + referenceGenerator.Generate(rootType), + rootType.FullName(), + referenceGenerator.Generate("scopeRoot"), + Name, + singleInstanceScopeReference, + currentParameters.Select(t => t.Resolution).ToList(), + disposableCollectionResolution, + function); + } + + public void DoWork() + { + while (HasWorkToDo) + { + while (_scopeRootFunctionResolutionsQueue.Any()) + { + var (scopeRootFunction, parameter, type, decorationScopeRoot) = _scopeRootFunctionResolutionsQueue.Dequeue(); + var referenceGenerator = ReferenceGeneratorFactory.Create(); + var resolvable = CreateConstructorResolution( + decorationScopeRoot?.ImplementationType ?? type, + referenceGenerator, + parameter, + Skip.ScopeRootCheck); + + if (decorationScopeRoot is {InterfaceType: {} interfaceType, ImplementationType: {} implementationType}) + { + var currentInterfaceResolution = new InterfaceResolution( + referenceGenerator.Generate(interfaceType), + interfaceType.FullName(), + resolvable); + var decorators = new Stack(CheckTypeProperties.GetDecorators(interfaceType)); + while (decorators.Any()) + { + var decorator = decorators.Pop(); + var decoratorResolution = CreateDecoratorConstructorResolution( + new Decoration( + interfaceType, + implementationType, + decorator, + currentInterfaceResolution), + referenceGenerator, + parameter, + Skip.None); + currentInterfaceResolution = new InterfaceResolution( + referenceGenerator.Generate(interfaceType), + interfaceType.FullName(), + decoratorResolution); + } + + resolvable = currentInterfaceResolution; + } + + _rootResolutions.Add(new RootResolutionFunction( + scopeRootFunction.Reference, + type.FullName(), + "internal", + resolvable, + parameter.Select(t => t.Item2).ToList(), + "", + Name, + DisposalHandling)); + } + + DoRangedInstancesWork(); + } + } + + public ScopeResolution Build() => + new(_rootResolutions, + DisposalHandling, + RangedInstances + .GroupBy(t => t.Item1) + .Select(g => new RangedInstance( + g.Key, + g.Select(t => t.Item2).ToList(), + DisposalHandling)) + .ToList(), + _containerReference, + _containerParameterReference, + Name); +} \ No newline at end of file diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index 1fb6e45e..0873a2f4 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -1,4 +1,6 @@ -namespace MrMeeseeks.DIE; +using MrMeeseeks.DIE.ResolutionBuilding; + +namespace MrMeeseeks.DIE; [Generator] public class SourceGenerator : ISourceGenerator @@ -17,10 +19,10 @@ public void Execute(GeneratorExecutionContext context) var getAssemblyAttributes = new GetAssemblyAttributes(context); var typesFromAttributes = new TypesFromAttributes(wellKnownTypes, getAssemblyAttributes); var getAllImplementations = new GetAllImplementations(context, typesFromAttributes); - var typeToImplementationMapper = new TypeToImplementationsMapper(getAllImplementations); + var checkTypeProperties = new CheckTypeProperties(getAllImplementations, typesFromAttributes); + var typeToImplementationMapper = new TypeToImplementationsMapper(getAllImplementations, checkTypeProperties); var containerGenerator = new ContainerGenerator(context, wellKnownTypes, diagLogger); var referenceGeneratorFactory = new ReferenceGeneratorFactory(ReferenceGeneratorFactory); - var checkDisposalManagement = new CheckTypeProperties(getAllImplementations, typesFromAttributes); var containerErrorGenerator = new ContainerErrorGenerator(context); var resolutionTreeCreationErrorHarvester = new ResolutionTreeCreationErrorHarvester(); new ExecuteImpl( @@ -37,15 +39,15 @@ public void Execute(GeneratorExecutionContext context) ci, typeToImplementationMapper, referenceGeneratorFactory, - checkDisposalManagement, + checkTypeProperties, wellKnownTypes, ScopeResolutionBuilderFactory); IScopeResolutionBuilder ScopeResolutionBuilderFactory(IContainerResolutionBuilder containerBuilder) => new ScopeResolutionBuilder( containerBuilder, wellKnownTypes, typeToImplementationMapper, - referenceGeneratorFactory, - checkDisposalManagement); + referenceGeneratorFactory, + checkTypeProperties); IContainerInfo ContainerInfoFactory(INamedTypeSymbol type) => new ContainerInfo(type, wellKnownTypes); IReferenceGenerator ReferenceGeneratorFactory(int j) => new ReferenceGenerator(j); } diff --git a/Main/TypeToImplementationMapper.cs b/Main/TypeToImplementationMapper.cs index 2586aaa5..773fef52 100644 --- a/Main/TypeToImplementationMapper.cs +++ b/Main/TypeToImplementationMapper.cs @@ -10,12 +10,14 @@ internal class TypeToImplementationsMapper : ITypeToImplementationsMapper private readonly Dictionary> _map; public TypeToImplementationsMapper( - IGetAllImplementations getAllImplementations) => + IGetAllImplementations getAllImplementations, + ICheckTypeProperties checkTypeProperties) => _map = getAllImplementations .AllImplementations + .Where(t => !checkTypeProperties.IsDecorator(t.OriginalDefinition)) .SelectMany(i => { return i.AllInterfaces.OfType().Select(ii => (ii, i)).Prepend((i, i)); }) .GroupBy(t => t.Item1, t => t.Item2) - .ToDictionary(g => g.Key, g => g.Distinct().ToList()); + .ToDictionary(g => g.Key, g => g.Distinct(SymbolEqualityComparer.Default).OfType().ToList()); public IList Map(ITypeSymbol typeSymbol) => _map.TryGetValue(typeSymbol, out var implementations) diff --git a/Main/TypesFromAttributes.cs b/Main/TypesFromAttributes.cs index 3dcdc5a4..fb934c24 100644 --- a/Main/TypesFromAttributes.cs +++ b/Main/TypesFromAttributes.cs @@ -7,6 +7,7 @@ public interface ITypesFromAttributes IReadOnlyList SingleInstance { get; } IReadOnlyList ScopedInstance { get; } IReadOnlyList ScopeRoot { get; } + IReadOnlyList Decorator { get; } } internal class TypesFromAttributes : ITypesFromAttributes @@ -20,6 +21,7 @@ public TypesFromAttributes( SingleInstance = GetTypesFromAttribute(wellKnownTypes.SingleInstanceAttribute).ToList(); ScopedInstance = GetTypesFromAttribute(wellKnownTypes.ScopedInstanceAttribute).ToList(); ScopeRoot = GetTypesFromAttribute(wellKnownTypes.ScopeRootAttribute).ToList(); + Decorator = GetTypesFromAttribute(wellKnownTypes.DecoratorAttribute).ToList(); IEnumerable GetTypesFromAttribute(INamedTypeSymbol attribute) => getAssemblyAttributes .AllAssemblyAttributes @@ -41,15 +43,14 @@ IEnumerable GetTypesFromAttribute(INamedTypeSymbol attribute) return type; }) .Where(t => t is not null) - .OfType(); + .OfType() + .Select(t => t.OriginalDefinition); bool CheckValidType(TypedConstant typedConstant, out INamedTypeSymbol type) { type = (typedConstant.Value as INamedTypeSymbol)!; if (typedConstant.Value is null) return false; - if (type.IsUnboundGenericType) - return false; return true; } @@ -60,4 +61,5 @@ bool CheckValidType(TypedConstant typedConstant, out INamedTypeSymbol type) public IReadOnlyList SingleInstance { get; } public IReadOnlyList ScopedInstance { get; } public IReadOnlyList ScopeRoot { get; } + public IReadOnlyList Decorator { get; } } \ No newline at end of file diff --git a/Main/WellKnownTypes.cs b/Main/WellKnownTypes.cs index 234bc56c..cf52e4af 100644 --- a/Main/WellKnownTypes.cs +++ b/Main/WellKnownTypes.cs @@ -7,6 +7,7 @@ internal record WellKnownTypes( INamedTypeSymbol SingleInstanceAttribute, INamedTypeSymbol ScopedInstanceAttribute, INamedTypeSymbol ScopeRootAttribute, + INamedTypeSymbol DecoratorAttribute, INamedTypeSymbol Disposable, INamedTypeSymbol AsyncDisposable, INamedTypeSymbol Lazy1, @@ -60,12 +61,16 @@ public static bool TryCreate(Compilation compilation, out WellKnownTypes wellKno var scopeRootAttribute = compilation .GetTypeByMetadataName(typeof(ScopeRootAttribute).FullName ?? ""); + var decoratorAttribute = compilation + .GetTypeByMetadataName(typeof(DecoratorAttribute).FullName ?? ""); + if (iContainer is null || spyAttribute is null || transientAttribute is null || singleInstanceAttribute is null || scopedInstanceAttribute is null || scopeRootAttribute is null + || decoratorAttribute is null || iDisposable is null || iAsyncDisposable is null || lazy1 is null @@ -93,6 +98,7 @@ public static bool TryCreate(Compilation compilation, out WellKnownTypes wellKno SingleInstanceAttribute: singleInstanceAttribute, ScopedInstanceAttribute: scopedInstanceAttribute, ScopeRootAttribute: scopeRootAttribute, + DecoratorAttribute: decoratorAttribute, Disposable: iDisposable, AsyncDisposable: iAsyncDisposable, Lazy1: lazy1, diff --git a/MrMeeseeks.DIE.sln b/MrMeeseeks.DIE.sln index 4c439f53..33809b7a 100644 --- a/MrMeeseeks.DIE.sln +++ b/MrMeeseeks.DIE.sln @@ -12,10 +12,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Misc", "Misc", "{4BFDBE50-2 Directory.build.props = Directory.build.props EndProjectSection EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SampleChild", "SampleChild\SampleChild.csproj", "{6925C30D-D532-46FD-9DE8-80317129EDC9}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Spy", "Spy\Spy.csproj", "{441E6E31-2472-42C0-AE6F-2676CB15ACDF}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test", "Test\Test.csproj", "{5075D83B-EF12-4372-8210-CEB5D81A4FE2}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -30,14 +30,14 @@ Global {5DFB446B-AAC8-450A-95A1-A55EF6BB37DB}.Debug|Any CPU.Build.0 = Debug|Any CPU {5DFB446B-AAC8-450A-95A1-A55EF6BB37DB}.Release|Any CPU.ActiveCfg = Release|Any CPU {5DFB446B-AAC8-450A-95A1-A55EF6BB37DB}.Release|Any CPU.Build.0 = Release|Any CPU - {6925C30D-D532-46FD-9DE8-80317129EDC9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6925C30D-D532-46FD-9DE8-80317129EDC9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6925C30D-D532-46FD-9DE8-80317129EDC9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6925C30D-D532-46FD-9DE8-80317129EDC9}.Release|Any CPU.Build.0 = Release|Any CPU {441E6E31-2472-42C0-AE6F-2676CB15ACDF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {441E6E31-2472-42C0-AE6F-2676CB15ACDF}.Debug|Any CPU.Build.0 = Debug|Any CPU {441E6E31-2472-42C0-AE6F-2676CB15ACDF}.Release|Any CPU.ActiveCfg = Release|Any CPU {441E6E31-2472-42C0-AE6F-2676CB15ACDF}.Release|Any CPU.Build.0 = Release|Any CPU + {5075D83B-EF12-4372-8210-CEB5D81A4FE2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5075D83B-EF12-4372-8210-CEB5D81A4FE2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5075D83B-EF12-4372-8210-CEB5D81A4FE2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5075D83B-EF12-4372-8210-CEB5D81A4FE2}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Sample/Container.cs b/Sample/Container.cs index 13307e9f..8abd1ea7 100644 --- a/Sample/Container.cs +++ b/Sample/Container.cs @@ -1,15 +1,9 @@ using MrMeeseeks.DIE; -using MrMeeseeks.DIE.SampleChild; -using SampleChild; +using MrMeeseeks.DIE.Sample; -[assembly:Spy(typeof(IPublicTypeReport), typeof(IInternalTypeReport))] +//[assembly:Spy(typeof(IPublicTypeReport), typeof(IInternalTypeReport))] [assembly:SingleInstance(typeof(ISingleInstance))] [assembly:ScopedInstance(typeof(IScopedInstance))] [assembly:ScopeRoot(typeof(IScopeRoot))] [assembly:Transient(typeof(ITransient))] - -namespace MrMeeseeks.DIE.Sample; - -internal partial class Container : IContainer -{ -} \ No newline at end of file +[assembly:Decorator(typeof(IDecorator<>))] \ No newline at end of file diff --git a/Sample/Context.cs b/Sample/Context.cs index 4a7a48f3..576ee084 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -1,23 +1,24 @@ -using System; -using System.Collections.Generic; -using MrMeeseeks.DIE.SampleChild; +namespace MrMeeseeks.DIE.Sample; -namespace MrMeeseeks.DIE.Sample; +internal interface IDecoratedScopeRoot +{ + IDecoratedScopeRoot Decorated { get; } +} -internal interface IContext +internal class DecoratorScopeRootBasis : IDecoratedScopeRoot, IScopeRoot { - string Text { get; } + public IDecoratedScopeRoot Decorated => this; } -internal class Context : IContext, IDisposable, ISingleInstance +internal class DecoratorScopeRoot : IDecoratedScopeRoot, IDecorator { - public string Text => "Hello, world!"; - public Context(IReadOnlyList child) - { + public DecoratorScopeRoot(IDecoratedScopeRoot decorated) => + Decorated = decorated; - } + public IDecoratedScopeRoot Decorated { get; } +} - public void Dispose() - { - } +internal partial class DecoratorScopeRootContainer : IContainer +{ + } \ No newline at end of file diff --git a/SampleChild/MarkerInterfaces.cs b/Sample/MarkerInterfaces.cs similarity index 51% rename from SampleChild/MarkerInterfaces.cs rename to Sample/MarkerInterfaces.cs index 7295b29c..f103956b 100644 --- a/SampleChild/MarkerInterfaces.cs +++ b/Sample/MarkerInterfaces.cs @@ -1,6 +1,7 @@ -namespace MrMeeseeks.DIE.SampleChild; +namespace MrMeeseeks.DIE.Sample; public interface ISingleInstance { } public interface IScopedInstance { } public interface IScopeRoot { } -public interface ITransient { } \ No newline at end of file +public interface ITransient { } +public interface IDecorator { } \ No newline at end of file diff --git a/Sample/Program.cs b/Sample/Program.cs index 9ba9269f..a6025558 100644 --- a/Sample/Program.cs +++ b/Sample/Program.cs @@ -1,16 +1,5 @@ using MrMeeseeks.DIE.Sample; -using StrongInject; System.Console.WriteLine("Hello, world!"); -{ - using var container = new Container(); - System.Console.WriteLine(((MrMeeseeks.DIE.IContainer) container).Resolve().Text); -} -{ - /* - using var strongInjectContainer = new StrongInjectContainer(); - using var owned = strongInjectContainer.Resolve(); - System.Console.WriteLine(owned.Value.Text); - */ -} - +using var container = new DecoratorScopeRootContainer(); +System.Console.WriteLine(((MrMeeseeks.DIE.IContainer) container).Resolve()); \ No newline at end of file diff --git a/Sample/Sample.csproj b/Sample/Sample.csproj index 9876144f..2f5c9bad 100644 --- a/Sample/Sample.csproj +++ b/Sample/Sample.csproj @@ -2,7 +2,7 @@ Exe - net5.0 + net6.0 MrMeeseeks.DIE.Sample true @@ -14,7 +14,6 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - @@ -23,7 +22,6 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - diff --git a/Sample/StrongInjectContainer.cs b/Sample/StrongInjectContainer.cs deleted file mode 100644 index 1d405d72..00000000 --- a/Sample/StrongInjectContainer.cs +++ /dev/null @@ -1,19 +0,0 @@ -using MrMeeseeks.DIE.SampleChild; -using StrongInject; -using StrongInject.Modules; - -namespace MrMeeseeks.DIE.Sample; -//* -[Register(typeof(Context), Scope.SingleInstance, typeof(Context), typeof(IContext))] -[Register(typeof(Child), Scope.SingleInstance, typeof(Child), typeof(IChild))] -[Register(typeof(InternalChild), typeof(IInternalChild))] -[Register(typeof(YetAnotherInternalChild), typeof(IYetAnotherInternalChild))] -[Register(typeof(AndThenSingleInstance), Scope.SingleInstance, typeof(IAndThenSingleInstance))] -[Register(typeof(AndThenAnotherScope), typeof(IAndThenAnotherScope))] -[Register(typeof(A), typeof(IA))] -[Register(typeof(B), typeof(IB))] -[RegisterModule(typeof(StandardModule))] -internal partial class StrongInjectContainer : StrongInject.IContainer -{ - -}//*/ \ No newline at end of file diff --git a/SampleChild/AssemblyInfo.cs b/SampleChild/AssemblyInfo.cs deleted file mode 100644 index 8a25a86d..00000000 --- a/SampleChild/AssemblyInfo.cs +++ /dev/null @@ -1,3 +0,0 @@ -using System.Runtime.CompilerServices; - -[assembly:InternalsVisibleTo("Sample")] \ No newline at end of file diff --git a/SampleChild/Child.cs b/SampleChild/Child.cs deleted file mode 100644 index c73605cc..00000000 --- a/SampleChild/Child.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; - -namespace MrMeeseeks.DIE.SampleChild; - -public interface IChild -{ } - -public class Child : IChild, IDisposable, IScopeRoot -{ - public Child( - IInternalChild innerChild){} - - public void Dispose() - { - } -} \ No newline at end of file diff --git a/SampleChild/InternalChild.cs b/SampleChild/InternalChild.cs deleted file mode 100644 index 0877357e..00000000 --- a/SampleChild/InternalChild.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System; - -namespace MrMeeseeks.DIE.SampleChild; - -public interface IInternalChild -{} -internal class InternalChild : IInternalChild, IDisposable, IScopedInstance -{ - public InternalChild( - Lazy yetAnotherInternalChild, - Func andThenAnotherScopeA, - Func andThenAnotherScopeB) - { - - } - - public void Dispose() - { - } -} - -public interface IAndThenAnotherScope -{} -internal class AndThenAnotherScope : IAndThenAnotherScope, IDisposable, IScopedInstance, IScopeRoot -{ - public AndThenAnotherScope( - IA a, - IB b){} - public void Dispose() - { - } -} - -public interface IYetAnotherInternalChild -{} -internal class YetAnotherInternalChild : IYetAnotherInternalChild, IDisposable, IScopedInstance -{ - public YetAnotherInternalChild( - Func andThenSingleInstanceA, - Func andThenSingleInstanceB) - {} - public void Dispose() - { - } -} - -public interface IAndThenSingleInstance -{} -internal class AndThenSingleInstance : IAndThenSingleInstance, IDisposable, ISingleInstance -{ - public AndThenSingleInstance( - IA a, - IB b){} - public void Dispose() - { - } -} - -public interface IA {} -public interface IB {} - -public class A : IA {} -public class B : IB {} \ No newline at end of file diff --git a/SampleChild/SampleChild.csproj b/SampleChild/SampleChild.csproj deleted file mode 100644 index d0ab0682..00000000 --- a/SampleChild/SampleChild.csproj +++ /dev/null @@ -1,19 +0,0 @@ - - - - net5.0 - - MrMeeseeks.DIE.SampleChild - true - $(BaseIntermediateOutputPath)\GeneratedFiles - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - diff --git a/Test/DecoratorTests.cs b/Test/DecoratorTests.cs new file mode 100644 index 00000000..d846a8f3 --- /dev/null +++ b/Test/DecoratorTests.cs @@ -0,0 +1,126 @@ +using MrMeeseeks.DIE; +using MrMeeseeks.DIE.Sample; +using Xunit; + +[assembly:SingleInstance(typeof(ISingleInstance))] +[assembly:ScopedInstance(typeof(IScopedInstance))] +[assembly:ScopeRoot(typeof(IScopeRoot))] +[assembly:Transient(typeof(ITransient))] +[assembly:Decorator(typeof(IDecorator<>))] + +namespace MrMeeseeks.DIE.Sample; + +internal interface IDecoratedNormal +{ + IDecoratedNormal Decorated { get; } +} + +internal class DecoratorNormalBasis : IDecoratedNormal +{ + public IDecoratedNormal Decorated => this; +} + +internal class DecoratorNormal : IDecoratedNormal, IDecorator +{ + public DecoratorNormal(IDecoratedNormal decoratedNormal) => + Decorated = decoratedNormal; + + public IDecoratedNormal Decorated { get; } +} + +internal partial class DecoratorNormalContainer : IContainer +{ + +} + +public partial class DecoratorTests +{ + [Fact] + public void Normal() + { + using var container = new DecoratorNormalContainer(); + var decorated = ((IContainer) container).Resolve(); + Assert.NotEqual(decorated, decorated.Decorated); + Assert.IsType(decorated); + Assert.IsType(decorated.Decorated); + } +} + +internal interface IDecoratedSingleInstance +{ + IDecoratedSingleInstance Decorated { get; } +} + +internal class DecoratorSingleInstanceBasis : IDecoratedSingleInstance, ISingleInstance +{ + public IDecoratedSingleInstance Decorated => this; +} + +internal class DecoratorSingleInstance : IDecoratedSingleInstance, IDecorator +{ + public DecoratorSingleInstance(IDecoratedSingleInstance decoratedSingleInstance) => + Decorated = decoratedSingleInstance; + + public IDecoratedSingleInstance Decorated { get; } +} + +internal partial class DecoratorSingleInstanceContainer : IContainer +{ + +} + +public partial class DecoratorTests +{ + [Fact] + public void SingleInstance() + { + using var container = new DecoratorSingleInstanceContainer(); + var decorated = ((IContainer) container).Resolve(); + Assert.NotEqual(decorated, decorated.Decorated); + Assert.IsType(decorated); + Assert.IsType(decorated.Decorated); + + var decoratedNextReference = ((IContainer) container).Resolve(); + Assert.Equal(decorated, decoratedNextReference); + Assert.Equal(decorated.Decorated, decoratedNextReference.Decorated); + } +} + +internal interface IDecoratedScopeRoot +{ + IDecoratedScopeRoot Decorated { get; } +} + +internal class DecoratorScopeRootBasis : IDecoratedScopeRoot, IScopeRoot +{ + public IDecoratedScopeRoot Decorated => this; +} + +internal class DecoratorScopeRoot : IDecoratedScopeRoot, IDecorator +{ + public DecoratorScopeRoot(IDecoratedScopeRoot decorated) => + Decorated = decorated; + + public IDecoratedScopeRoot Decorated { get; } +} + +internal partial class DecoratorScopeRootContainer : IContainer +{ + +} + +public partial class DecoratorTests +{ + [Fact] + public void ScopeRoot() + { + using var container = new DecoratorScopeRootContainer(); + var decorated = ((IContainer) container).Resolve(); + Assert.NotEqual(decorated, decorated.Decorated); + Assert.IsType(decorated); + Assert.IsType(decorated.Decorated); + + // There is yet no way to check scopes externally + Assert.True(false); + } +} \ No newline at end of file diff --git a/Test/MarkerInterfaces.cs b/Test/MarkerInterfaces.cs new file mode 100644 index 00000000..f103956b --- /dev/null +++ b/Test/MarkerInterfaces.cs @@ -0,0 +1,7 @@ +namespace MrMeeseeks.DIE.Sample; + +public interface ISingleInstance { } +public interface IScopedInstance { } +public interface IScopeRoot { } +public interface ITransient { } +public interface IDecorator { } \ No newline at end of file diff --git a/Test/Test.csproj b/Test/Test.csproj new file mode 100644 index 00000000..cb21ddf4 --- /dev/null +++ b/Test/Test.csproj @@ -0,0 +1,33 @@ + + + + net6.0 + + MrMeeseeks.DIE.Sample + false + true + $(BaseIntermediateOutputPath)\GeneratedFiles + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + From e06ab8b894917e6099587af99a8af7bc10e40dfb Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Thu, 2 Dec 2021 10:35:36 +0100 Subject: [PATCH 025/162] Decoration of collected dependencies --- .../RangeResolutionBaseBuilder.cs | 33 ++++-- Test/DecoratorTests.cs | 101 ++++++++++++++++++ 2 files changed, 126 insertions(+), 8 deletions(-) diff --git a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs index 462b9191..1ae26146 100644 --- a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs +++ b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs @@ -100,7 +100,7 @@ protected Resolvable Create( _ => $"[{namedTypeSymbol.FullName()}] Lazy: {namedTypeSymbol.TypeArguments[0].FullName()} is not a named type symbol" }); } - + var dependency = Create( genericType, ReferenceGeneratorFactory.Create(), @@ -141,10 +141,14 @@ protected Resolvable Create( }); } var itemFullName = itemType.FullName(); + var itemTypeIsInterface = itemType.TypeKind == TypeKind.Interface; var items = TypeToImplementationsMapper .Map(itemType) - .Select(i => Create(i, referenceGenerator, currentFuncParameters)) + .Select(i => itemTypeIsInterface + ? CreateInterfaceResolution(itemType, i, referenceGenerator, currentFuncParameters) + : Create(i, referenceGenerator, currentFuncParameters)) .ToList(); + return new CollectionResolution( referenceGenerator.Generate(type), type.FullName(), @@ -203,6 +207,19 @@ private Resolvable CreateInterfaceResolution( }); } + return CreateInterfaceResolution( + interfaceType, + implementationType, + referenceGenerator, + currentParameters); + } + + private Resolvable CreateInterfaceResolution( + INamedTypeSymbol interfaceType, + INamedTypeSymbol implementationType, + IReferenceGenerator referenceGenerator, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) + { var shouldBeDecorated = CheckTypeProperties.ShouldBeDecorated(interfaceType); if (shouldBeDecorated && CheckTypeProperties.ShouldBeScopeRoot(implementationType)) @@ -214,14 +231,14 @@ private Resolvable CreateInterfaceResolution( currentParameters, new DecorationScopeRoot(interfaceType, implementationType)); return new InterfaceResolution( - referenceGenerator.Generate(typeSymbol), - typeSymbol.FullName(), + referenceGenerator.Generate(interfaceType), + interfaceType.FullName(), rootResolution); } var currentInterfaceResolution = new InterfaceResolution( - referenceGenerator.Generate(typeSymbol), - typeSymbol.FullName(), + referenceGenerator.Generate(interfaceType), + interfaceType.FullName(), Create(implementationType, referenceGenerator, currentParameters)); if (shouldBeDecorated) @@ -236,8 +253,8 @@ private Resolvable CreateInterfaceResolution( currentParameters, Skip.None); currentInterfaceResolution = new InterfaceResolution( - referenceGenerator.Generate(typeSymbol), - typeSymbol.FullName(), + referenceGenerator.Generate(interfaceType), + interfaceType.FullName(), decoratorResolution); } } diff --git a/Test/DecoratorTests.cs b/Test/DecoratorTests.cs index d846a8f3..e5d5236f 100644 --- a/Test/DecoratorTests.cs +++ b/Test/DecoratorTests.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using MrMeeseeks.DIE; using MrMeeseeks.DIE.Sample; using Xunit; @@ -123,4 +124,104 @@ public void ScopeRoot() // There is yet no way to check scopes externally Assert.True(false); } +} + +internal interface IDecoratedMulti +{ + IDecoratedMulti Decorated { get; } +} + +internal class DecoratorMultiBasis : IDecoratedMulti +{ + public IDecoratedMulti Decorated => this; +} + +internal class DecoratorMultiA : IDecoratedMulti, IDecorator +{ + public DecoratorMultiA(IDecoratedMulti decorated) => + Decorated = decorated; + + public IDecoratedMulti Decorated { get; } +} + +internal class DecoratorMultiB : IDecoratedMulti, IDecorator +{ + public DecoratorMultiB(IDecoratedMulti decorated) => + Decorated = decorated; + + public IDecoratedMulti Decorated { get; } +} + +internal partial class DecoratorMultiContainer : IContainer +{ + +} + +public partial class DecoratorTests +{ + [Fact] + public void Multi() + { + using var container = new DecoratorMultiContainer(); + var decorated = ((IContainer) container).Resolve(); + var decoratedB = decorated; + var decoratedA = decorated.Decorated; + var decoratedBasis = decoratedA.Decorated; + Assert.NotEqual(decoratedBasis, decoratedA); + Assert.NotEqual(decoratedBasis, decoratedB); + Assert.NotEqual(decoratedA, decoratedB); + Assert.IsType(decoratedBasis); + Assert.IsType(decoratedA); + Assert.IsType(decoratedB); + } +} + +internal interface IDecoratedList +{ + IDecoratedList Decorated { get; } +} + +internal class DecoratedListBasisA : IDecoratedList +{ + public IDecoratedList Decorated => this; +} + +internal class DecoratedListBasisB : IDecoratedList +{ + public IDecoratedList Decorated => this; +} + +internal class DecoratorList : IDecoratedList, IDecorator +{ + public DecoratorList(IDecoratedList decorated) => + Decorated = decorated; + + public IDecoratedList Decorated { get; } +} + +internal partial class DecoratorListContainer : IContainer> +{ + +} + +public partial class DecoratorTests +{ + [Fact] + public void List() + { + using var container = new DecoratorListContainer(); + var decorated = ((IContainer>) container).Resolve(); + var decoratedOfA = decorated[0]; + var decoratedOfB = decorated[1]; + var decoratedBasisA = decoratedOfA.Decorated; + var decoratedBasisB = decoratedOfB.Decorated; + Assert.NotEqual(decoratedOfA, decoratedBasisA); + Assert.NotEqual(decoratedOfB, decoratedBasisB); + Assert.NotEqual(decoratedOfA, decoratedOfB); + Assert.NotEqual(decoratedBasisA, decoratedBasisB); + Assert.IsType(decoratedOfA); + Assert.IsType(decoratedOfB); + Assert.IsType(decoratedBasisA); + Assert.IsType(decoratedBasisB); + } } \ No newline at end of file From 284d8d6fee7a1fb248b20e4d8a38e0e1b04e28ed Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Thu, 2 Dec 2021 15:47:21 +0100 Subject: [PATCH 026/162] Implemented ability to chose decorator sequence in order to prevent ambiguity in case of multiple decorators for an interface --- Main/Attributes.cs | 31 ++++--- Main/CheckDecorators.cs | 81 +++++++++++++++++++ Main/CheckTypeProperties.cs | 59 ++------------ Main/GetAllImplementations.cs | 4 +- Main/GetSetOfTypesWithProperties.cs | 46 +++++++++++ .../ContainerResolutionBuilder.cs | 9 ++- .../RangeResolutionBaseBuilder.cs | 13 +-- .../ScopeResolutionBuilder.cs | 14 +++- Main/SourceGenerator.cs | 14 ++-- Main/TypeToImplementationMapper.cs | 4 +- ... => TypesFromTypeAggregatingAttributes.cs} | 18 ++--- Main/WellKnownTypes.cs | 66 ++++++++------- Sample/Container.cs | 12 +-- Sample/Context.cs | 33 +++++--- Sample/Program.cs | 7 +- Test/DecoratorTests.cs | 15 ++-- 16 files changed, 280 insertions(+), 146 deletions(-) create mode 100644 Main/CheckDecorators.cs create mode 100644 Main/GetSetOfTypesWithProperties.cs rename Main/{TypesFromAttributes.cs => TypesFromTypeAggregatingAttributes.cs} (84%) diff --git a/Main/Attributes.cs b/Main/Attributes.cs index 5c60ab97..7866d66b 100644 --- a/Main/Attributes.cs +++ b/Main/Attributes.cs @@ -1,43 +1,50 @@ namespace MrMeeseeks.DIE; [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] -public class SpyAttribute : Attribute +public class SpyAggregationAttribute : Attribute { // ReSharper disable once UnusedParameter.Local *** Is used in the generator - public SpyAttribute(params Type[] type) {} + public SpyAggregationAttribute(params Type[] types) {} } [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] -public class TransientAttribute : Attribute +public class TransientAggregationAttribute : Attribute { // ReSharper disable once UnusedParameter.Local *** Is used in the generator - public TransientAttribute(params Type[] type) {} + public TransientAggregationAttribute(params Type[] types) {} } [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] -public class SingleInstanceAttribute : Attribute +public class SingleInstanceAggregationAttribute : Attribute { // ReSharper disable once UnusedParameter.Local *** Is used in the generator - public SingleInstanceAttribute(params Type[] type) {} + public SingleInstanceAggregationAttribute(params Type[] types) {} } [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] -public class ScopedInstanceAttribute : Attribute +public class ScopedInstanceAggregationAttribute : Attribute { // ReSharper disable once UnusedParameter.Local *** Is used in the generator - public ScopedInstanceAttribute(params Type[] type) {} + public ScopedInstanceAggregationAttribute(params Type[] types) {} } [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] -public class ScopeRootAttribute : Attribute +public class ScopeRootAggregationAttribute : Attribute { // ReSharper disable once UnusedParameter.Local *** Is used in the generator - public ScopeRootAttribute(params Type[] type) {} + public ScopeRootAggregationAttribute(params Type[] types) {} } [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] -public class DecoratorAttribute : Attribute +public class DecoratorAggregationAttribute : Attribute { // ReSharper disable once UnusedParameter.Local *** Is used in the generator - public DecoratorAttribute(params Type[] type) {} + public DecoratorAggregationAttribute(params Type[] types) {} +} + +[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] +public class DecoratorSequenceChoiceAttribute : Attribute +{ + // ReSharper disable once UnusedParameter.Local *** Is used in the generator + public DecoratorSequenceChoiceAttribute(Type decoratedType, params Type[] types) {} } \ No newline at end of file diff --git a/Main/CheckDecorators.cs b/Main/CheckDecorators.cs new file mode 100644 index 00000000..93c87d76 --- /dev/null +++ b/Main/CheckDecorators.cs @@ -0,0 +1,81 @@ +namespace MrMeeseeks.DIE; + +public interface ICheckDecorators +{ + bool ShouldBeDecorated(INamedTypeSymbol interfaceType); + bool IsDecorator(INamedTypeSymbol implementationType); + IReadOnlyList GetSequenceFor(INamedTypeSymbol interfaceType, INamedTypeSymbol implementationType); +} + +internal class CheckDecorators : ICheckDecorators +{ + private readonly IImmutableSet _decoratorTypes; + private readonly IDictionary> _interfaceToDecorators; + private readonly IDictionary> _interfaceSequenceChoices; + private readonly IDictionary> _implementationSequenceChoices; + + public CheckDecorators( + WellKnownTypes wellKnownTypes, + IGetAssemblyAttributes getAssemblyAttributes, + ITypesFromTypeAggregatingAttributes typesFromTypeAggregatingAttributes, + IGetSetOfTypesWithProperties getSetOfTypesWithProperties) + { + _decoratorTypes = getSetOfTypesWithProperties.Get(typesFromTypeAggregatingAttributes.Decorator); + _interfaceToDecorators = _decoratorTypes + .OfType() + .GroupBy(nts => + { + var namedTypeSymbol = nts.AllInterfaces + .Single(t => + typesFromTypeAggregatingAttributes.Decorator.Contains(t.OriginalDefinition, SymbolEqualityComparer.Default)); + return namedTypeSymbol.TypeArguments.First(); + }, SymbolEqualityComparer.Default) + .ToDictionary(g => g.Key, g => g.ToList(), SymbolEqualityComparer.Default); + var sequenceChoices = getAssemblyAttributes + .AllAssemblyAttributes + .Where(ad => + ad.AttributeClass?.Equals(wellKnownTypes.DecoratorSequenceChoiceAttribute, + SymbolEqualityComparer.Default) ?? false) + .Select(ad => + { + if (ad.ConstructorArguments.Length < 2) + return null; + var decoratedType = ad.ConstructorArguments[0].Value; + var decorators = ad + .ConstructorArguments[1] + .Values + .Select(tc => tc.Value) + .OfType() + .ToList(); + + return decoratedType is null + ? null + : ((INamedTypeSymbol, IReadOnlyList)?) (decoratedType, decorators); + }) + .OfType<(INamedTypeSymbol, IReadOnlyList)>() + .ToList(); + + _interfaceSequenceChoices = sequenceChoices + .Where(t => t.Item1.TypeKind == TypeKind.Interface) + .ToDictionary(t => t.Item1, t => t.Item2); + + _implementationSequenceChoices = sequenceChoices + .Where(t => t.Item1.TypeKind == TypeKind.Class || t.Item1.TypeKind == TypeKind.Struct) + .ToDictionary(t => t.Item1, t => t.Item2); + } + + public bool ShouldBeDecorated(INamedTypeSymbol interfaceType) => _interfaceToDecorators.ContainsKey(interfaceType); + public bool IsDecorator(INamedTypeSymbol implementationType) => _decoratorTypes.Contains(implementationType); + + public IReadOnlyList GetSequenceFor(INamedTypeSymbol interfaceType, INamedTypeSymbol implementationType) + { + if (_implementationSequenceChoices.TryGetValue(implementationType, out var implementationSequence)) + return implementationSequence; + if (_interfaceSequenceChoices.TryGetValue(interfaceType, out var interfaceSequence)) + return interfaceSequence; + if (_interfaceToDecorators.TryGetValue(interfaceType, out var allDecorators) + && allDecorators.Count == 1) + return allDecorators; + throw new Exception("Couldn't find unambiguous sequence of decorators"); + } +} \ No newline at end of file diff --git a/Main/CheckTypeProperties.cs b/Main/CheckTypeProperties.cs index ab3035aa..5c281dd0 100644 --- a/Main/CheckTypeProperties.cs +++ b/Main/CheckTypeProperties.cs @@ -6,9 +6,6 @@ public interface ICheckTypeProperties bool ShouldBeSingleInstance(INamedTypeSymbol implementationType); bool ShouldBeScopedInstance(INamedTypeSymbol implementationType); bool ShouldBeScopeRoot(INamedTypeSymbol implementationType); - bool ShouldBeDecorated(INamedTypeSymbol interfaceType); - bool IsDecorator(INamedTypeSymbol implementationType); - IReadOnlyList GetDecorators(INamedTypeSymbol interfaceType); } internal class CheckTypeProperties : ICheckTypeProperties @@ -17,63 +14,19 @@ internal class CheckTypeProperties : ICheckTypeProperties private readonly IImmutableSet _singleInstanceTypes; private readonly IImmutableSet _scopedInstanceTypes; private readonly IImmutableSet _scopeRootTypes; - private readonly IImmutableSet _decoratorTypes; - private readonly IDictionary> _interfaceToDecorators; public CheckTypeProperties( - IGetAllImplementations getAllImplementations, - ITypesFromAttributes typesFromAttributes) + ITypesFromTypeAggregatingAttributes typesFromTypeAggregatingAttributes, + IGetSetOfTypesWithProperties getSetOfTypesWithProperties) { - _transientTypes = GetSetOfTypesWithProperties(typesFromAttributes.Transient); - _singleInstanceTypes = GetSetOfTypesWithProperties(typesFromAttributes.SingleInstance); - _scopedInstanceTypes = GetSetOfTypesWithProperties(typesFromAttributes.ScopedInstance); - _scopeRootTypes = GetSetOfTypesWithProperties(typesFromAttributes.ScopeRoot); - _decoratorTypes = GetSetOfTypesWithProperties(typesFromAttributes.Decorator); - _interfaceToDecorators = _decoratorTypes - .OfType() - .GroupBy(nts => - { - var namedTypeSymbol = nts.AllInterfaces - .Single(t => - typesFromAttributes.Decorator.Contains(t.OriginalDefinition, SymbolEqualityComparer.Default)); - return namedTypeSymbol.TypeArguments.First(); - }, SymbolEqualityComparer.Default) - .ToDictionary(g => g.Key, g => g.ToList(), SymbolEqualityComparer.Default); - - IImmutableSet GetSetOfTypesWithProperties(IReadOnlyList propertyGivingTypes) => getAllImplementations - .AllImplementations - .Where(i => - { - var derivedTypes = AllDerivedTypes(i).Select(t => t.OriginalDefinition).ToList(); - return propertyGivingTypes.Any(t => derivedTypes.Contains(t.OriginalDefinition, SymbolEqualityComparer.Default)); - }) - .Distinct(SymbolEqualityComparer.Default) - .ToImmutableHashSet(SymbolEqualityComparer.Default); - - IEnumerable AllDerivedTypes(INamedTypeSymbol type) - { - var concreteTypes = new List(); - var temp = type; - while (temp is {}) - { - concreteTypes.Add(temp); - temp = temp.BaseType; - } - return type - .AllInterfaces - .Append(type) - .Concat(concreteTypes); - } + _transientTypes = getSetOfTypesWithProperties.Get(typesFromTypeAggregatingAttributes.Transient); + _singleInstanceTypes = getSetOfTypesWithProperties.Get(typesFromTypeAggregatingAttributes.SingleInstance); + _scopedInstanceTypes = getSetOfTypesWithProperties.Get(typesFromTypeAggregatingAttributes.ScopedInstance); + _scopeRootTypes = getSetOfTypesWithProperties.Get(typesFromTypeAggregatingAttributes.ScopeRoot); } public bool ShouldBeManaged(INamedTypeSymbol implementationType) => !_transientTypes.Contains(implementationType); public bool ShouldBeSingleInstance(INamedTypeSymbol implementationType) => _singleInstanceTypes.Contains(implementationType); public bool ShouldBeScopedInstance(INamedTypeSymbol implementationType) => _scopedInstanceTypes.Contains(implementationType); public bool ShouldBeScopeRoot(INamedTypeSymbol implementationType) => _scopeRootTypes.Contains(implementationType); - public bool ShouldBeDecorated(INamedTypeSymbol interfaceType) => _interfaceToDecorators.ContainsKey(interfaceType); - public bool IsDecorator(INamedTypeSymbol implementationType) => _decoratorTypes.Contains(implementationType); - public IReadOnlyList GetDecorators(INamedTypeSymbol interfaceType) => - _interfaceToDecorators.TryGetValue(interfaceType, out var ret) - ? ret - : Array.Empty(); } \ No newline at end of file diff --git a/Main/GetAllImplementations.cs b/Main/GetAllImplementations.cs index c9ae9ee5..051f7c7e 100644 --- a/Main/GetAllImplementations.cs +++ b/Main/GetAllImplementations.cs @@ -11,7 +11,7 @@ internal class GetAllImplementations : IGetAllImplementations { public GetAllImplementations( GeneratorExecutionContext context, - ITypesFromAttributes typesFromAttributes) + ITypesFromTypeAggregatingAttributes typesFromTypeAggregatingAttributes) { var implementationsOfThisAssembly = context.Compilation.SyntaxTrees .Select(st => (st, context.Compilation.GetSemanticModel(st))) @@ -23,7 +23,7 @@ public GetAllImplementations( .Where(c => c is not null) .OfType()); - var spiedImplementations = typesFromAttributes + var spiedImplementations = typesFromTypeAggregatingAttributes .Spy .SelectMany(t => t?.GetMembers() .OfType() diff --git a/Main/GetSetOfTypesWithProperties.cs b/Main/GetSetOfTypesWithProperties.cs new file mode 100644 index 00000000..e613325d --- /dev/null +++ b/Main/GetSetOfTypesWithProperties.cs @@ -0,0 +1,46 @@ +namespace MrMeeseeks.DIE; + +public interface IGetSetOfTypesWithProperties +{ + IImmutableSet Get(IReadOnlyList propertyGivingTypes); +} + +internal class GetSetOfTypesWithProperties : IGetSetOfTypesWithProperties +{ + private readonly IGetAllImplementations _getAllImplementations; + + public GetSetOfTypesWithProperties(IGetAllImplementations getAllImplementations) + { + _getAllImplementations = getAllImplementations; + } + + public IImmutableSet Get(IReadOnlyList propertyGivingTypes) + { + return _getAllImplementations + .AllImplementations + .Where(i => + { + var derivedTypes = AllDerivedTypes(i).Select(t => t.OriginalDefinition).ToList(); + return propertyGivingTypes.Any(t => + derivedTypes.Contains(t.OriginalDefinition, SymbolEqualityComparer.Default)); + }) + .Distinct(SymbolEqualityComparer.Default) + .ToImmutableHashSet(SymbolEqualityComparer.Default); + + + IEnumerable AllDerivedTypes(INamedTypeSymbol type) + { + var concreteTypes = new List(); + var temp = type; + while (temp is {}) + { + concreteTypes.Add(temp); + temp = temp.BaseType; + } + return type + .AllInterfaces + .Append(type) + .Concat(concreteTypes); + } + } +} \ No newline at end of file diff --git a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs index 75ac3dff..6239fddb 100644 --- a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs @@ -29,9 +29,16 @@ public ContainerResolutionBuilder( ITypeToImplementationsMapper typeToImplementationsMapper, IReferenceGeneratorFactory referenceGeneratorFactory, ICheckTypeProperties checkTypeProperties, + ICheckDecorators checkDecorators, WellKnownTypes wellKnownTypes, Func scopeResolutionBuilderFactory) - : base((containerInfo.Name, false), wellKnownTypes, typeToImplementationsMapper, referenceGeneratorFactory, checkTypeProperties) + : base( + (containerInfo.Name, false), + wellKnownTypes, + typeToImplementationsMapper, + referenceGeneratorFactory, + checkTypeProperties, + checkDecorators) { _containerInfo = containerInfo; _scopeResolutionBuilder = scopeResolutionBuilderFactory(this); diff --git a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs index 1ae26146..315ffc91 100644 --- a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs +++ b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs @@ -23,7 +23,8 @@ public enum Skip protected readonly ITypeToImplementationsMapper TypeToImplementationsMapper; protected readonly IReferenceGeneratorFactory ReferenceGeneratorFactory; protected readonly ICheckTypeProperties CheckTypeProperties; - + protected readonly ICheckDecorators CheckDecorators; + protected readonly IReferenceGenerator RootReferenceGenerator; protected readonly IDictionary RangedInstanceReferenceResolutions = new Dictionary(); @@ -43,12 +44,14 @@ protected RangeResolutionBaseBuilder( WellKnownTypes wellKnownTypes, ITypeToImplementationsMapper typeToImplementationsMapper, IReferenceGeneratorFactory referenceGeneratorFactory, - ICheckTypeProperties checkTypeProperties) + ICheckTypeProperties checkTypeProperties, + ICheckDecorators checkDecorators) { WellKnownTypes = wellKnownTypes; TypeToImplementationsMapper = typeToImplementationsMapper; ReferenceGeneratorFactory = referenceGeneratorFactory; CheckTypeProperties = checkTypeProperties; + CheckDecorators = checkDecorators; RootReferenceGenerator = referenceGeneratorFactory.Create(); DisposableCollectionResolution = new DisposableCollectionResolution( @@ -220,7 +223,7 @@ private Resolvable CreateInterfaceResolution( IReferenceGenerator referenceGenerator, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) { - var shouldBeDecorated = CheckTypeProperties.ShouldBeDecorated(interfaceType); + var shouldBeDecorated = CheckDecorators.ShouldBeDecorated(interfaceType); if (shouldBeDecorated && CheckTypeProperties.ShouldBeScopeRoot(implementationType)) { @@ -243,10 +246,10 @@ private Resolvable CreateInterfaceResolution( if (shouldBeDecorated) { - var decorators = new Stack(CheckTypeProperties.GetDecorators(interfaceType)); + var decorators = new Queue(CheckDecorators.GetSequenceFor(interfaceType, implementationType)); while (decorators.Any()) { - var decorator = decorators.Pop(); + var decorator = decorators.Dequeue(); var decoratorResolution = CreateDecoratorConstructorResolution( new Decoration(interfaceType, implementationType, decorator, currentInterfaceResolution), referenceGenerator, diff --git a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs index b88e9b46..35ef4b3c 100644 --- a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs @@ -36,7 +36,15 @@ public ScopeResolutionBuilder( WellKnownTypes wellKnownTypes, ITypeToImplementationsMapper typeToImplementationsMapper, IReferenceGeneratorFactory referenceGeneratorFactory, - ICheckTypeProperties checkTypeProperties) : base(("DefaultScope", true), wellKnownTypes, typeToImplementationsMapper, referenceGeneratorFactory, checkTypeProperties) + ICheckTypeProperties checkTypeProperties, + ICheckDecorators checkDecorators) + : base( + ("DefaultScope", true), + wellKnownTypes, + typeToImplementationsMapper, + referenceGeneratorFactory, + checkTypeProperties, + checkDecorators) { _containerResolutionBuilder = containerResolutionBuilder; _containerReference = RootReferenceGenerator.Generate("_container"); @@ -137,10 +145,10 @@ public void DoWork() referenceGenerator.Generate(interfaceType), interfaceType.FullName(), resolvable); - var decorators = new Stack(CheckTypeProperties.GetDecorators(interfaceType)); + var decorators = new Queue(CheckDecorators.GetSequenceFor(interfaceType, implementationType)); while (decorators.Any()) { - var decorator = decorators.Pop(); + var decorator = decorators.Dequeue(); var decoratorResolution = CreateDecoratorConstructorResolution( new Decoration( interfaceType, diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index 0873a2f4..c0d428da 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -17,10 +17,12 @@ public void Execute(GeneratorExecutionContext context) var diagLogger = new DiagLogger(context); var _ = WellKnownTypes.TryCreate(context.Compilation, out var wellKnownTypes); var getAssemblyAttributes = new GetAssemblyAttributes(context); - var typesFromAttributes = new TypesFromAttributes(wellKnownTypes, getAssemblyAttributes); - var getAllImplementations = new GetAllImplementations(context, typesFromAttributes); - var checkTypeProperties = new CheckTypeProperties(getAllImplementations, typesFromAttributes); - var typeToImplementationMapper = new TypeToImplementationsMapper(getAllImplementations, checkTypeProperties); + var typesFromTypeAggregatingAttributes = new TypesFromTypeAggregatingAttributes(wellKnownTypes, getAssemblyAttributes); + var getAllImplementations = new GetAllImplementations(context, typesFromTypeAggregatingAttributes); + var getSetOfTypesWithProperties = new GetSetOfTypesWithProperties(getAllImplementations); + var checkDecorators = new CheckDecorators(wellKnownTypes, getAssemblyAttributes, typesFromTypeAggregatingAttributes, getSetOfTypesWithProperties); + var checkTypeProperties = new CheckTypeProperties(typesFromTypeAggregatingAttributes, getSetOfTypesWithProperties); + var typeToImplementationMapper = new TypeToImplementationsMapper(getAllImplementations, checkDecorators); var containerGenerator = new ContainerGenerator(context, wellKnownTypes, diagLogger); var referenceGeneratorFactory = new ReferenceGeneratorFactory(ReferenceGeneratorFactory); var containerErrorGenerator = new ContainerErrorGenerator(context); @@ -40,6 +42,7 @@ public void Execute(GeneratorExecutionContext context) typeToImplementationMapper, referenceGeneratorFactory, checkTypeProperties, + checkDecorators, wellKnownTypes, ScopeResolutionBuilderFactory); IScopeResolutionBuilder ScopeResolutionBuilderFactory(IContainerResolutionBuilder containerBuilder) => new ScopeResolutionBuilder( @@ -47,7 +50,8 @@ public void Execute(GeneratorExecutionContext context) wellKnownTypes, typeToImplementationMapper, referenceGeneratorFactory, - checkTypeProperties); + checkTypeProperties, + checkDecorators); IContainerInfo ContainerInfoFactory(INamedTypeSymbol type) => new ContainerInfo(type, wellKnownTypes); IReferenceGenerator ReferenceGeneratorFactory(int j) => new ReferenceGenerator(j); } diff --git a/Main/TypeToImplementationMapper.cs b/Main/TypeToImplementationMapper.cs index 773fef52..a7cd8a75 100644 --- a/Main/TypeToImplementationMapper.cs +++ b/Main/TypeToImplementationMapper.cs @@ -11,10 +11,10 @@ internal class TypeToImplementationsMapper : ITypeToImplementationsMapper public TypeToImplementationsMapper( IGetAllImplementations getAllImplementations, - ICheckTypeProperties checkTypeProperties) => + ICheckDecorators checkDecorators) => _map = getAllImplementations .AllImplementations - .Where(t => !checkTypeProperties.IsDecorator(t.OriginalDefinition)) + .Where(t => !checkDecorators.IsDecorator(t.OriginalDefinition)) .SelectMany(i => { return i.AllInterfaces.OfType().Select(ii => (ii, i)).Prepend((i, i)); }) .GroupBy(t => t.Item1, t => t.Item2) .ToDictionary(g => g.Key, g => g.Distinct(SymbolEqualityComparer.Default).OfType().ToList()); diff --git a/Main/TypesFromAttributes.cs b/Main/TypesFromTypeAggregatingAttributes.cs similarity index 84% rename from Main/TypesFromAttributes.cs rename to Main/TypesFromTypeAggregatingAttributes.cs index fb934c24..1e5014b5 100644 --- a/Main/TypesFromAttributes.cs +++ b/Main/TypesFromTypeAggregatingAttributes.cs @@ -1,6 +1,6 @@ namespace MrMeeseeks.DIE; -public interface ITypesFromAttributes +public interface ITypesFromTypeAggregatingAttributes { IReadOnlyList Spy { get; } IReadOnlyList Transient { get; } @@ -10,18 +10,18 @@ public interface ITypesFromAttributes IReadOnlyList Decorator { get; } } -internal class TypesFromAttributes : ITypesFromAttributes +internal class TypesFromTypeAggregatingAttributes : ITypesFromTypeAggregatingAttributes { - public TypesFromAttributes( + public TypesFromTypeAggregatingAttributes( WellKnownTypes wellKnownTypes, IGetAssemblyAttributes getAssemblyAttributes) { - Spy = GetTypesFromAttribute(wellKnownTypes.SpyAttribute).ToList(); - Transient = GetTypesFromAttribute(wellKnownTypes.TransientAttribute).ToList(); - SingleInstance = GetTypesFromAttribute(wellKnownTypes.SingleInstanceAttribute).ToList(); - ScopedInstance = GetTypesFromAttribute(wellKnownTypes.ScopedInstanceAttribute).ToList(); - ScopeRoot = GetTypesFromAttribute(wellKnownTypes.ScopeRootAttribute).ToList(); - Decorator = GetTypesFromAttribute(wellKnownTypes.DecoratorAttribute).ToList(); + Spy = GetTypesFromAttribute(wellKnownTypes.SpyAggregationAttribute).ToList(); + Transient = GetTypesFromAttribute(wellKnownTypes.TransientAggregationAttribute).ToList(); + SingleInstance = GetTypesFromAttribute(wellKnownTypes.SingleInstanceAggregationAttribute).ToList(); + ScopedInstance = GetTypesFromAttribute(wellKnownTypes.ScopedInstanceAggregationAttribute).ToList(); + ScopeRoot = GetTypesFromAttribute(wellKnownTypes.ScopeRootAggregationAttribute).ToList(); + Decorator = GetTypesFromAttribute(wellKnownTypes.DecoratorAggregationAttribute).ToList(); IEnumerable GetTypesFromAttribute(INamedTypeSymbol attribute) => getAssemblyAttributes .AllAssemblyAttributes diff --git a/Main/WellKnownTypes.cs b/Main/WellKnownTypes.cs index cf52e4af..ec247ac0 100644 --- a/Main/WellKnownTypes.cs +++ b/Main/WellKnownTypes.cs @@ -2,12 +2,13 @@ internal record WellKnownTypes( INamedTypeSymbol Container, - INamedTypeSymbol SpyAttribute, - INamedTypeSymbol TransientAttribute, - INamedTypeSymbol SingleInstanceAttribute, - INamedTypeSymbol ScopedInstanceAttribute, - INamedTypeSymbol ScopeRootAttribute, - INamedTypeSymbol DecoratorAttribute, + INamedTypeSymbol SpyAggregationAttribute, + INamedTypeSymbol TransientAggregationAttribute, + INamedTypeSymbol SingleInstanceAggregationAttribute, + INamedTypeSymbol ScopedInstanceAggregationAttribute, + INamedTypeSymbol ScopeRootAggregationAttribute, + INamedTypeSymbol DecoratorAggregationAttribute, + INamedTypeSymbol DecoratorSequenceChoiceAttribute, INamedTypeSymbol Disposable, INamedTypeSymbol AsyncDisposable, INamedTypeSymbol Lazy1, @@ -46,31 +47,35 @@ public static bool TryCreate(Compilation compilation, out WellKnownTypes wellKno var exception = compilation.GetTypeOrReport("System.Exception"); var semaphoreSlim = compilation.GetTypeOrReport("System.Threading.SemaphoreSlim"); - var spyAttribute = compilation - .GetTypeByMetadataName(typeof(SpyAttribute).FullName ?? ""); + var spyAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(SpyAggregationAttribute).FullName ?? ""); - var transientAttribute = compilation - .GetTypeByMetadataName(typeof(TransientAttribute).FullName ?? ""); + var transientAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(TransientAggregationAttribute).FullName ?? ""); - var singleInstanceAttribute = compilation - .GetTypeByMetadataName(typeof(SingleInstanceAttribute).FullName ?? ""); + var singleInstanceAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(SingleInstanceAggregationAttribute).FullName ?? ""); - var scopedInstanceAttribute = compilation - .GetTypeByMetadataName(typeof(ScopedInstanceAttribute).FullName ?? ""); + var scopedInstanceAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(ScopedInstanceAggregationAttribute).FullName ?? ""); - var scopeRootAttribute = compilation - .GetTypeByMetadataName(typeof(ScopeRootAttribute).FullName ?? ""); + var scopeRootAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(ScopeRootAggregationAttribute).FullName ?? ""); - var decoratorAttribute = compilation - .GetTypeByMetadataName(typeof(DecoratorAttribute).FullName ?? ""); + var decoratorAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(DecoratorAggregationAttribute).FullName ?? ""); + + var decoratorSequenceChoiceAttribute = compilation + .GetTypeByMetadataName(typeof(DecoratorSequenceChoiceAttribute).FullName ?? ""); if (iContainer is null - || spyAttribute is null - || transientAttribute is null - || singleInstanceAttribute is null - || scopedInstanceAttribute is null - || scopeRootAttribute is null - || decoratorAttribute is null + || spyAggregationAttribute is null + || transientAggregationAttribute is null + || singleInstanceAggregationAttribute is null + || scopedInstanceAggregationAttribute is null + || scopeRootAggregationAttribute is null + || decoratorAggregationAttribute is null + || decoratorSequenceChoiceAttribute is null || iDisposable is null || iAsyncDisposable is null || lazy1 is null @@ -93,12 +98,13 @@ public static bool TryCreate(Compilation compilation, out WellKnownTypes wellKno wellKnownTypes = new WellKnownTypes( Container: iContainer, - SpyAttribute: spyAttribute, - TransientAttribute: transientAttribute, - SingleInstanceAttribute: singleInstanceAttribute, - ScopedInstanceAttribute: scopedInstanceAttribute, - ScopeRootAttribute: scopeRootAttribute, - DecoratorAttribute: decoratorAttribute, + SpyAggregationAttribute: spyAggregationAttribute, + TransientAggregationAttribute: transientAggregationAttribute, + SingleInstanceAggregationAttribute: singleInstanceAggregationAttribute, + ScopedInstanceAggregationAttribute: scopedInstanceAggregationAttribute, + ScopeRootAggregationAttribute: scopeRootAggregationAttribute, + DecoratorAggregationAttribute: decoratorAggregationAttribute, + DecoratorSequenceChoiceAttribute: decoratorSequenceChoiceAttribute, Disposable: iDisposable, AsyncDisposable: iAsyncDisposable, Lazy1: lazy1, diff --git a/Sample/Container.cs b/Sample/Container.cs index 8abd1ea7..d9f00896 100644 --- a/Sample/Container.cs +++ b/Sample/Container.cs @@ -2,8 +2,10 @@ using MrMeeseeks.DIE.Sample; //[assembly:Spy(typeof(IPublicTypeReport), typeof(IInternalTypeReport))] -[assembly:SingleInstance(typeof(ISingleInstance))] -[assembly:ScopedInstance(typeof(IScopedInstance))] -[assembly:ScopeRoot(typeof(IScopeRoot))] -[assembly:Transient(typeof(ITransient))] -[assembly:Decorator(typeof(IDecorator<>))] \ No newline at end of file +[assembly:SingleInstanceAggregation(typeof(ISingleInstance))] +[assembly:ScopedInstanceAggregation(typeof(IScopedInstance))] +[assembly:ScopeRootAggregation(typeof(IScopeRoot))] +[assembly:TransientAggregation(typeof(ITransient))] +[assembly:DecoratorAggregation(typeof(IDecorator<>))] +[assembly:DecoratorSequenceChoice(typeof(IDecoratedMulti))] +[assembly:DecoratorSequenceChoice(typeof(DecoratorMultiBasisB), typeof(DecoratorMultiA), typeof(DecoratorMultiB))] \ No newline at end of file diff --git a/Sample/Context.cs b/Sample/Context.cs index 576ee084..c14ba3aa 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -1,24 +1,39 @@ -namespace MrMeeseeks.DIE.Sample; +using System.Collections.Generic; -internal interface IDecoratedScopeRoot +namespace MrMeeseeks.DIE.Sample; + +internal interface IDecoratedMulti { - IDecoratedScopeRoot Decorated { get; } + IDecoratedMulti Decorated { get; } } -internal class DecoratorScopeRootBasis : IDecoratedScopeRoot, IScopeRoot +internal class DecoratorMultiBasisA : IDecoratedMulti { - public IDecoratedScopeRoot Decorated => this; + public IDecoratedMulti Decorated => this; +} + +internal class DecoratorMultiBasisB : IDecoratedMulti +{ + public IDecoratedMulti Decorated => this; +} + +internal class DecoratorMultiA : IDecoratedMulti, IDecorator +{ + public DecoratorMultiA(IDecoratedMulti decorated) => + Decorated = decorated; + + public IDecoratedMulti Decorated { get; } } -internal class DecoratorScopeRoot : IDecoratedScopeRoot, IDecorator +internal class DecoratorMultiB : IDecoratedMulti, IDecorator { - public DecoratorScopeRoot(IDecoratedScopeRoot decorated) => + public DecoratorMultiB(IDecoratedMulti decorated) => Decorated = decorated; - public IDecoratedScopeRoot Decorated { get; } + public IDecoratedMulti Decorated { get; } } -internal partial class DecoratorScopeRootContainer : IContainer +internal partial class DecoratorMultiContainer : IContainer> { } \ No newline at end of file diff --git a/Sample/Program.cs b/Sample/Program.cs index a6025558..7931cf85 100644 --- a/Sample/Program.cs +++ b/Sample/Program.cs @@ -1,5 +1,6 @@ -using MrMeeseeks.DIE.Sample; +using System.Collections.Generic; +using MrMeeseeks.DIE.Sample; System.Console.WriteLine("Hello, world!"); -using var container = new DecoratorScopeRootContainer(); -System.Console.WriteLine(((MrMeeseeks.DIE.IContainer) container).Resolve()); \ No newline at end of file +using var container = new DecoratorMultiContainer(); +System.Console.WriteLine(((MrMeeseeks.DIE.IContainer>) container).Resolve()); \ No newline at end of file diff --git a/Test/DecoratorTests.cs b/Test/DecoratorTests.cs index e5d5236f..db41e720 100644 --- a/Test/DecoratorTests.cs +++ b/Test/DecoratorTests.cs @@ -3,11 +3,12 @@ using MrMeeseeks.DIE.Sample; using Xunit; -[assembly:SingleInstance(typeof(ISingleInstance))] -[assembly:ScopedInstance(typeof(IScopedInstance))] -[assembly:ScopeRoot(typeof(IScopeRoot))] -[assembly:Transient(typeof(ITransient))] -[assembly:Decorator(typeof(IDecorator<>))] +[assembly:SingleInstanceAggregation(typeof(ISingleInstance))] +[assembly:ScopedInstanceAggregation(typeof(IScopedInstance))] +[assembly:ScopeRootAggregation(typeof(IScopeRoot))] +[assembly:TransientAggregation(typeof(ITransient))] +[assembly:DecoratorAggregation(typeof(IDecorator<>))] +[assembly:DecoratorSequenceChoice(typeof(IDecoratedMulti), typeof(DecoratorMultiA), typeof(DecoratorMultiB))] namespace MrMeeseeks.DIE.Sample; @@ -138,7 +139,7 @@ internal class DecoratorMultiBasis : IDecoratedMulti internal class DecoratorMultiA : IDecoratedMulti, IDecorator { - public DecoratorMultiA(IDecoratedMulti decorated) => + public DecoratorMultiA(IDecoratedMulti decorated) => Decorated = decorated; public IDecoratedMulti Decorated { get; } @@ -146,7 +147,7 @@ public DecoratorMultiA(IDecoratedMulti decorated) => internal class DecoratorMultiB : IDecoratedMulti, IDecorator { - public DecoratorMultiB(IDecoratedMulti decorated) => + public DecoratorMultiB(IDecoratedMulti decorated) => Decorated = decorated; public IDecoratedMulti Decorated { get; } From c766a3d36d9fc7fd954f30c723abea67fa325459 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sun, 5 Dec 2021 23:02:32 +0100 Subject: [PATCH 027/162] Implemented Composite feature and improved code base --- Main/Attributes.cs | 7 + Main/CheckDecorators.cs | 4 +- Main/CheckTypeProperties.cs | 46 +- Main/ContainerErrorGenerator.cs | 2 +- Main/ContainerGenerator.cs | 2 +- Main/ContainerInfo.cs | 4 +- Main/DiagLogger.cs | 2 +- Main/ExecuteImpl.cs | 2 +- Main/GetAllImplementations.cs | 6 +- Main/GetAssemblyAttributes.cs | 4 +- Main/GetSetOfTypesWithProperties.cs | 4 +- Main/InitializeImpl.cs | 2 +- Main/ReferenceGenerator.cs | 6 +- .../ContainerResolutionBuilder.cs | 46 +- .../RangeResolutionBaseBuilder.cs | 541 ++++++++++++------ .../ScopeResolutionBuilder.cs | 100 +--- Main/RoslynExtensions.cs | 10 +- Main/SourceGenerator.cs | 2 +- Main/TypeToImplementationMapper.cs | 6 +- Main/TypesFromTypeAggregatingAttributes.cs | 7 +- Main/WellKnownTypes.cs | 8 +- Sample/Container.cs | 5 +- Sample/Context.cs | 42 +- Sample/MarkerInterfaces.cs | 3 +- Sample/Program.cs | 7 +- Test/AssemblyInfo.cs | 16 + Test/CompositeTests.cs | 353 ++++++++++++ Test/DecoratorTests.cs | 29 +- Test/MarkerInterfaces.cs | 3 +- 29 files changed, 907 insertions(+), 362 deletions(-) create mode 100644 Test/AssemblyInfo.cs create mode 100644 Test/CompositeTests.cs diff --git a/Main/Attributes.cs b/Main/Attributes.cs index 7866d66b..70f6a67b 100644 --- a/Main/Attributes.cs +++ b/Main/Attributes.cs @@ -42,6 +42,13 @@ public class DecoratorAggregationAttribute : Attribute public DecoratorAggregationAttribute(params Type[] types) {} } +[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] +public class CompositeAggregationAttribute : Attribute +{ + // ReSharper disable once UnusedParameter.Local *** Is used in the generator + public CompositeAggregationAttribute(params Type[] types) {} +} + [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] public class DecoratorSequenceChoiceAttribute : Attribute { diff --git a/Main/CheckDecorators.cs b/Main/CheckDecorators.cs index 93c87d76..0b61a31e 100644 --- a/Main/CheckDecorators.cs +++ b/Main/CheckDecorators.cs @@ -1,6 +1,6 @@ namespace MrMeeseeks.DIE; -public interface ICheckDecorators +internal interface ICheckDecorators { bool ShouldBeDecorated(INamedTypeSymbol interfaceType); bool IsDecorator(INamedTypeSymbol implementationType); @@ -14,7 +14,7 @@ internal class CheckDecorators : ICheckDecorators private readonly IDictionary> _interfaceSequenceChoices; private readonly IDictionary> _implementationSequenceChoices; - public CheckDecorators( + internal CheckDecorators( WellKnownTypes wellKnownTypes, IGetAssemblyAttributes getAssemblyAttributes, ITypesFromTypeAggregatingAttributes typesFromTypeAggregatingAttributes, diff --git a/Main/CheckTypeProperties.cs b/Main/CheckTypeProperties.cs index 5c281dd0..57dc1cf5 100644 --- a/Main/CheckTypeProperties.cs +++ b/Main/CheckTypeProperties.cs @@ -1,11 +1,21 @@ namespace MrMeeseeks.DIE; -public interface ICheckTypeProperties +internal enum ScopeLevel +{ + None, + Scope, + TransientScope, + SingleInstance +} + +internal interface ICheckTypeProperties { bool ShouldBeManaged(INamedTypeSymbol implementationType); - bool ShouldBeSingleInstance(INamedTypeSymbol implementationType); - bool ShouldBeScopedInstance(INamedTypeSymbol implementationType); bool ShouldBeScopeRoot(INamedTypeSymbol implementationType); + bool ShouldBeComposite(INamedTypeSymbol interfaceType); + ScopeLevel GetScopeLevelFor(INamedTypeSymbol implementationType); + INamedTypeSymbol GetCompositeFor(INamedTypeSymbol interfaceType); + bool IsComposite(INamedTypeSymbol implementationType); } internal class CheckTypeProperties : ICheckTypeProperties @@ -14,8 +24,10 @@ internal class CheckTypeProperties : ICheckTypeProperties private readonly IImmutableSet _singleInstanceTypes; private readonly IImmutableSet _scopedInstanceTypes; private readonly IImmutableSet _scopeRootTypes; + private readonly IImmutableSet _compositeTypes; + private readonly Dictionary _interfaceToComposite; - public CheckTypeProperties( + internal CheckTypeProperties( ITypesFromTypeAggregatingAttributes typesFromTypeAggregatingAttributes, IGetSetOfTypesWithProperties getSetOfTypesWithProperties) { @@ -23,10 +35,32 @@ public CheckTypeProperties( _singleInstanceTypes = getSetOfTypesWithProperties.Get(typesFromTypeAggregatingAttributes.SingleInstance); _scopedInstanceTypes = getSetOfTypesWithProperties.Get(typesFromTypeAggregatingAttributes.ScopedInstance); _scopeRootTypes = getSetOfTypesWithProperties.Get(typesFromTypeAggregatingAttributes.ScopeRoot); + _compositeTypes = getSetOfTypesWithProperties.Get(typesFromTypeAggregatingAttributes.Composite); + _interfaceToComposite = _compositeTypes + .OfType() + .GroupBy(nts => + { + var namedTypeSymbol = nts.AllInterfaces + .Single(t => + typesFromTypeAggregatingAttributes.Composite.Contains(t.OriginalDefinition, SymbolEqualityComparer.Default)); + return namedTypeSymbol.TypeArguments.First(); + }, SymbolEqualityComparer.Default) + .Where(g => g.Count() == 1) + .ToDictionary(g => g.Key, g => g.Single(), SymbolEqualityComparer.Default); } public bool ShouldBeManaged(INamedTypeSymbol implementationType) => !_transientTypes.Contains(implementationType); - public bool ShouldBeSingleInstance(INamedTypeSymbol implementationType) => _singleInstanceTypes.Contains(implementationType); - public bool ShouldBeScopedInstance(INamedTypeSymbol implementationType) => _scopedInstanceTypes.Contains(implementationType); public bool ShouldBeScopeRoot(INamedTypeSymbol implementationType) => _scopeRootTypes.Contains(implementationType); + public bool ShouldBeComposite(INamedTypeSymbol interfaceType) => _interfaceToComposite.ContainsKey(interfaceType); + public ScopeLevel GetScopeLevelFor(INamedTypeSymbol implementationType) + { + if (_singleInstanceTypes.Contains(implementationType)) + return ScopeLevel.SingleInstance; + if (_scopedInstanceTypes.Contains(implementationType)) + return ScopeLevel.Scope; + return ScopeLevel.None; + } + + public INamedTypeSymbol GetCompositeFor(INamedTypeSymbol interfaceType) => _interfaceToComposite[interfaceType]; + public bool IsComposite(INamedTypeSymbol implementationType) => _compositeTypes.Contains(implementationType); } \ No newline at end of file diff --git a/Main/ContainerErrorGenerator.cs b/Main/ContainerErrorGenerator.cs index 1f26a30a..26642a14 100644 --- a/Main/ContainerErrorGenerator.cs +++ b/Main/ContainerErrorGenerator.cs @@ -12,7 +12,7 @@ internal class ContainerErrorGenerator : IContainerErrorGenerator { private readonly GeneratorExecutionContext _context; - public ContainerErrorGenerator( + internal ContainerErrorGenerator( GeneratorExecutionContext context) => _context = context; diff --git a/Main/ContainerGenerator.cs b/Main/ContainerGenerator.cs index 62562300..ebbf468f 100644 --- a/Main/ContainerGenerator.cs +++ b/Main/ContainerGenerator.cs @@ -14,7 +14,7 @@ internal class ContainerGenerator : IContainerGenerator private readonly WellKnownTypes _wellKnownTypes; private readonly IDiagLogger _diagLogger; - public ContainerGenerator( + internal ContainerGenerator( GeneratorExecutionContext context, WellKnownTypes wellKnownTypes, IDiagLogger diagLogger) diff --git a/Main/ContainerInfo.cs b/Main/ContainerInfo.cs index 44372bea..d5bef098 100644 --- a/Main/ContainerInfo.cs +++ b/Main/ContainerInfo.cs @@ -1,6 +1,6 @@ namespace MrMeeseeks.DIE; -public interface IContainerInfo +internal interface IContainerInfo { string Name { get; } string Namespace { get; } @@ -11,7 +11,7 @@ public interface IContainerInfo internal class ContainerInfo : IContainerInfo { - public ContainerInfo( + internal ContainerInfo( // parameters INamedTypeSymbol containerClass, diff --git a/Main/DiagLogger.cs b/Main/DiagLogger.cs index c5fd3139..5ea274a0 100644 --- a/Main/DiagLogger.cs +++ b/Main/DiagLogger.cs @@ -11,7 +11,7 @@ internal class DiagLogger : IDiagLogger { private readonly GeneratorExecutionContext _context; - public DiagLogger( + internal DiagLogger( GeneratorExecutionContext context) { _context = context; diff --git a/Main/ExecuteImpl.cs b/Main/ExecuteImpl.cs index 831b8f4f..a46c44e5 100644 --- a/Main/ExecuteImpl.cs +++ b/Main/ExecuteImpl.cs @@ -19,7 +19,7 @@ internal class ExecuteImpl : IExecute private readonly Func _containerInfoFactory; private readonly IDiagLogger _diagLogger; - public ExecuteImpl( + internal ExecuteImpl( GeneratorExecutionContext context, WellKnownTypes wellKnownTypes, IContainerGenerator containerGenerator, diff --git a/Main/GetAllImplementations.cs b/Main/GetAllImplementations.cs index 051f7c7e..19317968 100644 --- a/Main/GetAllImplementations.cs +++ b/Main/GetAllImplementations.cs @@ -9,7 +9,7 @@ internal interface IGetAllImplementations internal class GetAllImplementations : IGetAllImplementations { - public GetAllImplementations( + internal GetAllImplementations( GeneratorExecutionContext context, ITypesFromTypeAggregatingAttributes typesFromTypeAggregatingAttributes) { @@ -18,7 +18,9 @@ public GetAllImplementations( .SelectMany(t => t.st .GetRoot() .DescendantNodesAndSelf() - .OfType() + .Where(e => typeof(ClassDeclarationSyntax) == e.GetType() + || typeof(StructDeclarationSyntax) == e.GetType() + || typeof(RecordDeclarationSyntax) == e.GetType()) .Select(c => t.Item2.GetDeclaredSymbol(c)) .Where(c => c is not null) .OfType()); diff --git a/Main/GetAssemblyAttributes.cs b/Main/GetAssemblyAttributes.cs index 34db54f0..0a2193d9 100644 --- a/Main/GetAssemblyAttributes.cs +++ b/Main/GetAssemblyAttributes.cs @@ -1,6 +1,6 @@ namespace MrMeeseeks.DIE; -public interface IGetAssemblyAttributes +internal interface IGetAssemblyAttributes { IReadOnlyList AllAssemblyAttributes { get; } } @@ -9,7 +9,7 @@ internal class GetAssemblyAttributes : IGetAssemblyAttributes { private readonly GeneratorExecutionContext _context; - public GetAssemblyAttributes(GeneratorExecutionContext context) + internal GetAssemblyAttributes(GeneratorExecutionContext context) { _context = context; } diff --git a/Main/GetSetOfTypesWithProperties.cs b/Main/GetSetOfTypesWithProperties.cs index e613325d..ecb275aa 100644 --- a/Main/GetSetOfTypesWithProperties.cs +++ b/Main/GetSetOfTypesWithProperties.cs @@ -1,6 +1,6 @@ namespace MrMeeseeks.DIE; -public interface IGetSetOfTypesWithProperties +internal interface IGetSetOfTypesWithProperties { IImmutableSet Get(IReadOnlyList propertyGivingTypes); } @@ -9,7 +9,7 @@ internal class GetSetOfTypesWithProperties : IGetSetOfTypesWithProperties { private readonly IGetAllImplementations _getAllImplementations; - public GetSetOfTypesWithProperties(IGetAllImplementations getAllImplementations) + internal GetSetOfTypesWithProperties(IGetAllImplementations getAllImplementations) { _getAllImplementations = getAllImplementations; } diff --git a/Main/InitializeImpl.cs b/Main/InitializeImpl.cs index a3f7aeef..e51d56d5 100644 --- a/Main/InitializeImpl.cs +++ b/Main/InitializeImpl.cs @@ -10,7 +10,7 @@ internal class InitializeImpl : IInitialize private readonly GeneratorInitializationContext _context; private readonly Func _syntaxReceiverFactory; - public InitializeImpl( + internal InitializeImpl( GeneratorInitializationContext context, Func syntaxReceiverFactory) { diff --git a/Main/ReferenceGenerator.cs b/Main/ReferenceGenerator.cs index c3d73cce..98757b46 100644 --- a/Main/ReferenceGenerator.cs +++ b/Main/ReferenceGenerator.cs @@ -1,6 +1,6 @@ namespace MrMeeseeks.DIE; -public interface IReferenceGenerator +internal interface IReferenceGenerator { string Generate(ITypeSymbol type); string Generate(string prefix, ITypeSymbol type); @@ -13,7 +13,7 @@ internal class ReferenceGenerator : IReferenceGenerator private int _i = -1; private readonly int _j; - public ReferenceGenerator(int j) => _j = j; + internal ReferenceGenerator(int j) => _j = j; public string Generate(ITypeSymbol type) => GenerateInner(string.Empty, $"{char.ToLower(type.Name[0])}{type.Name.Substring(1)}", string.Empty); @@ -31,7 +31,7 @@ private string GenerateInner(string prefix, string inner, string suffix) => $"{prefix}{inner}{suffix}_{_j}_{++_i}"; } -public interface IReferenceGeneratorFactory +internal interface IReferenceGeneratorFactory { IReferenceGenerator Create(); } diff --git a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs index 6239fddb..38eae73e 100644 --- a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs @@ -5,11 +5,8 @@ internal interface IContainerResolutionBuilder void AddCreateResolveFunctions(IReadOnlyList rootTypes); RangedInstanceReferenceResolution CreateSingleInstanceReferenceResolution( - INamedTypeSymbol implementationType, - IReferenceGenerator referenceGenerator, - string containerReference, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters, - RangeResolutionBaseBuilder.Decoration? decoration); + RangeResolutionBaseBuilder.ForConstructorParameter parameter, + string containerReference); ContainerResolution Build(); } @@ -21,7 +18,7 @@ internal class ContainerResolutionBuilder : RangeResolutionBaseBuilder, IContain private readonly List _rootResolutions = new (); private readonly IScopeResolutionBuilder _scopeResolutionBuilder; - public ContainerResolutionBuilder( + internal ContainerResolutionBuilder( // parameters IContainerInfo containerInfo, @@ -51,50 +48,35 @@ public void AddCreateResolveFunctions(IReadOnlyList rootTypes) nameof(IContainer.Resolve), typeSymbol.FullName(), "", - Create( + SwitchType(new SwitchTypeParameter( typeSymbol, - ReferenceGeneratorFactory.Create(), - Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>()), + Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>())), Array.Empty(), WellKnownTypes.Container.Construct(typeSymbol).FullName(), _containerInfo.Name, DisposalHandling)); } - public RangedInstanceReferenceResolution CreateSingleInstanceReferenceResolution( - INamedTypeSymbol implementationType, - IReferenceGenerator referenceGenerator, - string containerReference, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters, - Decoration? decoration) => + public RangedInstanceReferenceResolution CreateSingleInstanceReferenceResolution(ForConstructorParameter parameter, string containerReference) => CreateRangedInstanceReferenceResolution( - implementationType, - referenceGenerator, - currentParameters, + parameter, "Single", - containerReference, - decoration); + containerReference); - protected override RangedInstanceReferenceResolution CreateSingleInstanceReferenceResolution( - INamedTypeSymbol implementationType, - IReferenceGenerator referenceGenerator, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters, - Decoration? decoration) => - CreateSingleInstanceReferenceResolution(implementationType, referenceGenerator, "this", currentParameters, decoration); + protected override RangedInstanceReferenceResolution CreateSingleInstanceReferenceResolution(ForConstructorParameter parameter) => + CreateSingleInstanceReferenceResolution(parameter, "this"); protected override ScopeRootResolution CreateScopeRootResolution( + IScopeRootParameter parameter, INamedTypeSymbol rootType, - IReferenceGenerator referenceGenerator, DisposableCollectionResolution disposableCollectionResolution, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters, - DecorationScopeRoot? decoration) => + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) => _scopeResolutionBuilder.AddCreateResolveFunction( + parameter, rootType, - referenceGenerator, "this", disposableCollectionResolution, - currentParameters, - decoration); + currentParameters); public ContainerResolution Build() { diff --git a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs index 315ffc91..bd832e99 100644 --- a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs +++ b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs @@ -2,26 +2,41 @@ namespace MrMeeseeks.DIE.ResolutionBuilding; internal abstract class RangeResolutionBaseBuilder { - public record DecorationScopeRoot( - INamedTypeSymbol InterfaceType, - INamedTypeSymbol ImplementationType); - public record Decoration( - INamedTypeSymbol InterfaceType, - INamedTypeSymbol ImplementationType, - INamedTypeSymbol DecoratorType, - InterfaceResolution CurrentInterfaceResolution); - [Flags] - public enum Skip + internal abstract record InterfaceExtension( + INamedTypeSymbol InterfaceType) { - None = 1<<0, - RangedInstanceCheck = 1<<1, - ScopeRootCheck = 1<<2 + internal string KeySuffix() => + this switch + { + DecorationInterfaceExtension decoration => $":::{decoration.ImplementationType.FullName()}", + CompositionInterfaceExtension composition => string.Join(":::", composition.ImplementationTypes.Select(i => i.FullName())), + _ => throw new ArgumentException() + }; + + internal string RangedNameSuffix() => + this switch + { + DecorationInterfaceExtension decoration => $"_{decoration.ImplementationType.Name}", + CompositionInterfaceExtension => "_Composite", + _ => throw new ArgumentException() + }; } + internal record DecorationInterfaceExtension( + INamedTypeSymbol InterfaceType, + INamedTypeSymbol ImplementationType, + INamedTypeSymbol DecoratorType, + InterfaceResolution CurrentInterfaceResolution) + : InterfaceExtension(InterfaceType); + internal record CompositionInterfaceExtension( + INamedTypeSymbol InterfaceType, + IReadOnlyList ImplementationTypes, + INamedTypeSymbol CompositeType, + IReadOnlyList InterfaceResolutionComposition) + : InterfaceExtension(InterfaceType); protected readonly WellKnownTypes WellKnownTypes; protected readonly ITypeToImplementationsMapper TypeToImplementationsMapper; - protected readonly IReferenceGeneratorFactory ReferenceGeneratorFactory; protected readonly ICheckTypeProperties CheckTypeProperties; protected readonly ICheckDecorators CheckDecorators; @@ -29,7 +44,7 @@ public enum Skip protected readonly IDictionary RangedInstanceReferenceResolutions = new Dictionary(); protected readonly HashSet<(RangedInstanceFunction, string)> RangedInstanceQueuedOverloads = new (); - protected readonly Queue<(RangedInstanceFunction, IReadOnlyList<(ITypeSymbol, ParameterResolution)>, INamedTypeSymbol, Decoration?)> RangedInstanceResolutionsQueue = new(); + protected readonly Queue<(RangedInstanceFunction, IReadOnlyList<(ITypeSymbol, ParameterResolution)>, INamedTypeSymbol, InterfaceExtension?)> RangedInstanceResolutionsQueue = new(); protected readonly List<(RangedInstanceFunction, RangedInstanceFunctionOverload)> RangedInstances = new (); protected readonly DisposableCollectionResolution DisposableCollectionResolution; @@ -49,7 +64,6 @@ protected RangeResolutionBaseBuilder( { WellKnownTypes = wellKnownTypes; TypeToImplementationsMapper = typeToImplementationsMapper; - ReferenceGeneratorFactory = referenceGeneratorFactory; CheckTypeProperties = checkTypeProperties; CheckDecorators = checkDecorators; @@ -68,24 +82,24 @@ protected RangeResolutionBaseBuilder( RootReferenceGenerator.Generate("disposable")); } - protected abstract RangedInstanceReferenceResolution CreateSingleInstanceReferenceResolution( - INamedTypeSymbol implementationType, - IReferenceGenerator referenceGenerator, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters, - Decoration? decoration); + protected abstract RangedInstanceReferenceResolution CreateSingleInstanceReferenceResolution(ForConstructorParameter parameter); protected abstract ScopeRootResolution CreateScopeRootResolution( + IScopeRootParameter parameter, INamedTypeSymbol rootType, - IReferenceGenerator referenceGenerator, DisposableCollectionResolution disposableCollectionResolution, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters, - DecorationScopeRoot? decoration); + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters); + + internal record Parameter; - protected Resolvable Create( - ITypeSymbol type, - IReferenceGenerator referenceGenerator, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentFuncParameters) + internal record SwitchTypeParameter( + ITypeSymbol Type, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentFuncParameters) + : Parameter; + + protected Resolvable SwitchType(SwitchTypeParameter parameter) { + var (type, currentFuncParameters) = parameter; if (currentFuncParameters.FirstOrDefault(t => SymbolEqualityComparer.Default.Equals(t.Type.OriginalDefinition, type.OriginalDefinition)) is { Type: not null, Resolution: not null } funcParameter) { return funcParameter.Resolution; @@ -104,12 +118,11 @@ protected Resolvable Create( }); } - var dependency = Create( + var dependency = SwitchType(new SwitchTypeParameter( genericType, - ReferenceGeneratorFactory.Create(), - Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>()); + Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>())); return new ConstructorResolution( - referenceGenerator.Generate(namedTypeSymbol), + RootReferenceGenerator.Generate(namedTypeSymbol), namedTypeSymbol.FullName(), ImplementsIDisposable(namedTypeSymbol, WellKnownTypes, DisposableCollectionResolution, CheckTypeProperties), new ReadOnlyCollection<(string Name, Resolvable Dependency)>( @@ -118,7 +131,7 @@ protected Resolvable Create( ( "valueFactory", new FuncResolution( - referenceGenerator.Generate("func"), + RootReferenceGenerator.Generate("func"), $"global::System.Func<{genericType.FullName()}>", Array.Empty(), dependency) @@ -148,41 +161,39 @@ protected Resolvable Create( var items = TypeToImplementationsMapper .Map(itemType) .Select(i => itemTypeIsInterface - ? CreateInterfaceResolution(itemType, i, referenceGenerator, currentFuncParameters) - : Create(i, referenceGenerator, currentFuncParameters)) + ? SwitchInterfaceForSpecificImplementation(new SwitchInterfaceForSpecificImplementationParameter(itemType, i, currentFuncParameters)) + : SwitchClass(new SwitchClassParameter(i, currentFuncParameters))) .ToList(); return new CollectionResolution( - referenceGenerator.Generate(type), + RootReferenceGenerator.Generate(type), type.FullName(), itemFullName, items); } if (type.TypeKind == TypeKind.Interface) - return CreateInterfaceResolution(type, referenceGenerator, currentFuncParameters); + return SwitchInterface(new SwitchInterfaceParameter(type, currentFuncParameters)); if (type.TypeKind == TypeKind.Class) - return CreateConstructorResolution(type, referenceGenerator, currentFuncParameters, Skip.None); + return SwitchClass(new SwitchClassParameter(type, currentFuncParameters)); if (type.TypeKind == TypeKind.Delegate && type.FullName().StartsWith("global::System.Func<") && type is INamedTypeSymbol namedTypeSymbol0) { var returnType = namedTypeSymbol0.TypeArguments.Last(); - var innerReferenceGenerator = ReferenceGeneratorFactory.Create(); var parameterTypes = namedTypeSymbol0 .TypeArguments .Take(namedTypeSymbol0.TypeArguments.Length - 1) - .Select(ts => (Type: ts, Resolution: new ParameterResolution(innerReferenceGenerator.Generate(ts), ts.FullName()))) + .Select(ts => (Type: ts, Resolution: new ParameterResolution(RootReferenceGenerator.Generate(ts), ts.FullName()))) .ToArray(); - var dependency = Create( + var dependency = SwitchType(new SwitchTypeParameter( returnType, - innerReferenceGenerator, - parameterTypes); + parameterTypes)); return new FuncResolution( - referenceGenerator.Generate(type), + RootReferenceGenerator.Generate(type), type.FullName(), parameterTypes.Select(t => t.Resolution).ToArray(), dependency); @@ -191,58 +202,163 @@ protected Resolvable Create( return new ErrorTreeItem($"[{type.FullName()}] Couldn't process in resolution tree creation."); } - private Resolvable CreateInterfaceResolution( - ITypeSymbol typeSymbol, - IReferenceGenerator referenceGenerator, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) + internal record SwitchInterfaceParameter( + ITypeSymbol Type, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentFuncParameters) + : Parameter; + + private Resolvable SwitchInterface(SwitchInterfaceParameter parameter) { + var (typeSymbol, currentParameters) = parameter; var interfaceType = (INamedTypeSymbol) typeSymbol; var implementations = TypeToImplementationsMapper .Map(typeSymbol); - if (implementations - .SingleOrDefault() is not { } implementationType) + var shouldBeScopeRoot = implementations.Any(i => CheckTypeProperties.ShouldBeScopeRoot(i)); + + var nextParameter = new SwitchInterfaceAfterScopeRootParameter( + interfaceType, + implementations, + currentParameters); + + if (shouldBeScopeRoot) + { + return CreateScopeRootResolution( + nextParameter, + interfaceType, + DisposableCollectionResolution, + currentParameters); + } + + return SwitchInterfaceAfterScopeRoot(nextParameter); + } + + internal interface IScopeRootParameter + { + string KeySuffix(); + string RootFunctionSuffix(); + } + + internal record SwitchInterfaceAfterScopeRootParameter( + INamedTypeSymbol InterfaceType, + IList ImplementationTypes, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters) + : IScopeRootParameter + { + public string KeySuffix() => ":::InterfaceAfterRoot"; + + public string RootFunctionSuffix() => "_InterfaceAfterRoot"; + } + + protected Resolvable SwitchInterfaceAfterScopeRoot( + SwitchInterfaceAfterScopeRootParameter parameter) + { + var (interfaceType, implementations, currentParameters) = parameter; + if (CheckTypeProperties.ShouldBeComposite(interfaceType)) + { + var compositeImplementationType = CheckTypeProperties.GetCompositeFor(interfaceType); + var interfaceResolutions = implementations.Select(i => CreateInterface(new CreateInterfaceParameter( + interfaceType, + i, + currentParameters))).ToList(); + var composition = new CompositionInterfaceExtension( + interfaceType, + implementations.ToList(), + compositeImplementationType, + interfaceResolutions); + return CreateInterface(new CreateInterfaceParameterAsComposition( + interfaceType, + compositeImplementationType, + currentParameters, + composition)); + } + if (implementations.SingleOrDefault() is not { } implementationType) { return new ErrorTreeItem(implementations.Count switch { - 0 => $"[{typeSymbol.FullName()}] Interface: No implementation found", - > 1 => $"[{typeSymbol.FullName()}] Interface: more than one implementation found", - _ => $"[{typeSymbol.FullName()}] Interface: Found single implementation {implementations[0].FullName()} is not a named type symbol" + 0 => $"[{interfaceType.FullName()}] Interface: No implementation found", + > 1 => $"[{interfaceType.FullName()}] Interface: more than one implementation found", + _ => + $"[{interfaceType.FullName()}] Interface: Found single implementation {implementations[0].FullName()} is not a named type symbol" }); } - return CreateInterfaceResolution( + return CreateInterface(new CreateInterfaceParameter( + interfaceType, + implementationType, + currentParameters)); + } + + + internal record SwitchInterfaceForSpecificImplementationParameter( + INamedTypeSymbol InterfaceType, + INamedTypeSymbol ImplementationType, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters); + + private Resolvable SwitchInterfaceForSpecificImplementation( + SwitchInterfaceForSpecificImplementationParameter parameter) + { + var (interfaceType, implementationType, currentParameters) = parameter; + + var nextParameter = new CreateInterfaceParameter( interfaceType, implementationType, - referenceGenerator, currentParameters); + + if (CheckTypeProperties.ShouldBeScopeRoot(implementationType)) + { + return CreateScopeRootResolution( + nextParameter, + interfaceType, + DisposableCollectionResolution, + currentParameters); + } + + return CreateInterface(nextParameter); } - private Resolvable CreateInterfaceResolution( - INamedTypeSymbol interfaceType, - INamedTypeSymbol implementationType, - IReferenceGenerator referenceGenerator, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) + internal record CreateInterfaceParameter( + INamedTypeSymbol InterfaceType, + INamedTypeSymbol ImplementationType, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters) + : IScopeRootParameter + { + public virtual string KeySuffix() => ":::NormalInterface"; + + public virtual string RootFunctionSuffix() => "_NormalInterface"; + } + + internal record CreateInterfaceParameterAsComposition( + INamedTypeSymbol InterfaceType, + INamedTypeSymbol ImplementationType, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters, + CompositionInterfaceExtension Composition) + : CreateInterfaceParameter(InterfaceType, ImplementationType, CurrentParameters) { + public override string KeySuffix() => ":::CompositeInterface"; + + public override string RootFunctionSuffix() => "_CompositeInterface"; + } + + internal InterfaceResolution CreateInterface(CreateInterfaceParameter parameter) + { + var (interfaceType, implementationType, currentParameters) = parameter; var shouldBeDecorated = CheckDecorators.ShouldBeDecorated(interfaceType); - if (shouldBeDecorated && CheckTypeProperties.ShouldBeScopeRoot(implementationType)) + var nextParameter = parameter switch { - var rootResolution = CreateScopeRootResolution( - interfaceType, - referenceGenerator, - DisposableCollectionResolution, + CreateInterfaceParameterAsComposition asComposition => new SwitchImplementationParameterWithComposition( + asComposition.Composition.CompositeType, currentParameters, - new DecorationScopeRoot(interfaceType, implementationType)); - return new InterfaceResolution( - referenceGenerator.Generate(interfaceType), - interfaceType.FullName(), - rootResolution); - } + asComposition.Composition), + _ => new SwitchImplementationParameter( + implementationType, + currentParameters) + }; var currentInterfaceResolution = new InterfaceResolution( - referenceGenerator.Generate(interfaceType), + RootReferenceGenerator.Generate(interfaceType), interfaceType.FullName(), - Create(implementationType, referenceGenerator, currentParameters)); + SwitchImplementation(nextParameter)); if (shouldBeDecorated) { @@ -250,13 +366,14 @@ private Resolvable CreateInterfaceResolution( while (decorators.Any()) { var decorator = decorators.Dequeue(); - var decoratorResolution = CreateDecoratorConstructorResolution( - new Decoration(interfaceType, implementationType, decorator, currentInterfaceResolution), - referenceGenerator, + var decoration = new DecorationInterfaceExtension(interfaceType, implementationType, decorator, + currentInterfaceResolution); + var decoratorResolution = SwitchImplementation(new SwitchImplementationParameterWithDecoration( + decorator, currentParameters, - Skip.None); + decoration)); currentInterfaceResolution = new InterfaceResolution( - referenceGenerator.Generate(interfaceType), + RootReferenceGenerator.Generate(interfaceType), interfaceType.FullName(), decoratorResolution); } @@ -265,12 +382,13 @@ private Resolvable CreateInterfaceResolution( return currentInterfaceResolution; } - protected Resolvable CreateConstructorResolution( - ITypeSymbol typeSymbol, - IReferenceGenerator referenceGenerator, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters, - Skip skip) + internal record SwitchClassParameter( + ITypeSymbol TypeSymbol, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters); + + protected Resolvable SwitchClass(SwitchClassParameter parameter) { + var (typeSymbol, currentParameters) = parameter; var implementations = TypeToImplementationsMapper .Map(typeSymbol); var implementationType = implementations.SingleOrDefault(); @@ -285,87 +403,129 @@ protected Resolvable CreateConstructorResolution( }); } - if (!skip.HasFlag(Skip.RangedInstanceCheck) && CheckTypeProperties.ShouldBeSingleInstance(implementationType)) - return CreateSingleInstanceReferenceResolution(implementationType, referenceGenerator, currentParameters, null); - - if (!skip.HasFlag(Skip.ScopeRootCheck) && CheckTypeProperties.ShouldBeScopeRoot(implementationType)) - return CreateScopeRootResolution(implementationType, referenceGenerator, DisposableCollectionResolution, currentParameters, null); - - if (!skip.HasFlag(Skip.RangedInstanceCheck) && CheckTypeProperties.ShouldBeScopedInstance(implementationType)) - return CreateScopedInstanceReferenceResolution(implementationType, referenceGenerator, currentParameters, null); + var nextParameter = new SwitchImplementationParameter( + implementationType, + currentParameters); - if (implementationType.Constructors.SingleOrDefault() is not { } constructor) - { - return new ErrorTreeItem(implementationType.Constructors.Length switch - { - 0 => $"[{typeSymbol.FullName()}] Class.Constructor: No constructor found for implementation {implementationType.FullName()}", - > 1 => $"[{typeSymbol.FullName()}] Class.Constructor: More than one constructor found for implementation {implementationType.FullName()}", - _ => $"[{typeSymbol.FullName()}] Class.Constructor: {implementationType.Constructors[0].Name} is not a method symbol" - }); - } + if (CheckTypeProperties.ShouldBeScopeRoot(implementationType)) + return CreateScopeRootResolution(nextParameter, implementationType, DisposableCollectionResolution, currentParameters); - return new ConstructorResolution( - referenceGenerator.Generate(implementationType), - implementationType.FullName(), - ImplementsIDisposable( - implementationType, - WellKnownTypes, - DisposableCollectionResolution, - CheckTypeProperties), - new ReadOnlyCollection<(string Name, Resolvable Dependency)>(constructor - .Parameters - .Select(p => - { - if (p.Type is not INamedTypeSymbol parameterType) - { - return ("", - new ErrorTreeItem( - $"[{typeSymbol.FullName()}] Class.Constructor.Parameter: Parameter type {p.Type.FullName()} is not a named type symbol")); - } + return SwitchImplementation(nextParameter); + } + + internal record SwitchImplementationParameter( + INamedTypeSymbol ImplementationType, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters) + : IScopeRootParameter + { + public virtual string KeySuffix() => ":::Implementation"; - return ( - p.Name, - Create(parameterType, - referenceGenerator, - currentParameters)); - }) - .ToList())); + public virtual string RootFunctionSuffix() => ""; } + + internal record SwitchImplementationParameterWithDecoration( + INamedTypeSymbol ImplementationType, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters, + DecorationInterfaceExtension Decoration) + : SwitchImplementationParameter(ImplementationType, CurrentParameters); + + internal record SwitchImplementationParameterWithComposition( + INamedTypeSymbol ImplementationType, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters, + CompositionInterfaceExtension Composition) + : SwitchImplementationParameter(ImplementationType, CurrentParameters); - protected Resolvable CreateDecoratorConstructorResolution( - Decoration decoration, - IReferenceGenerator referenceGenerator, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters, - Skip skip) + protected Resolvable SwitchImplementation(SwitchImplementationParameter parameter) { - var decoratorType = decoration.DecoratorType; - if (!skip.HasFlag(Skip.RangedInstanceCheck) && CheckTypeProperties.ShouldBeSingleInstance(decoration.ImplementationType)) - return CreateSingleInstanceReferenceResolution(decoratorType, referenceGenerator, currentParameters, decoration); + var (implementationType, currentParameters) = parameter; + var scopeLevel = parameter switch + { + SwitchImplementationParameterWithComposition withComposition => + withComposition.Composition.ImplementationTypes.Select(i => CheckTypeProperties.GetScopeLevelFor(i)) + .Min(), + SwitchImplementationParameterWithDecoration withDecoration => CheckTypeProperties.GetScopeLevelFor( + withDecoration.Decoration.ImplementationType), + _ => CheckTypeProperties.GetScopeLevelFor(parameter.ImplementationType) + }; + var nextParameter = parameter switch + { + SwitchImplementationParameterWithComposition withComposition => new ForConstructorParameterWithComposition( + withComposition.Composition.CompositeType, + currentParameters, + withComposition.Composition), + SwitchImplementationParameterWithDecoration withDecoration => new ForConstructorParameterWithDecoration( + withDecoration.Decoration.DecoratorType, + currentParameters, + withDecoration.Decoration), + _ => new ForConstructorParameter(implementationType, currentParameters) + }; + return scopeLevel switch + { + ScopeLevel.SingleInstance => CreateSingleInstanceReferenceResolution(nextParameter), + ScopeLevel.Scope => CreateScopedInstanceReferenceResolution(nextParameter), + _ => CreateConstructorResolution(nextParameter) + }; + } - //if (!skipScopeRootCheck && CheckTypeProperties.ShouldBeScopeRoot(implementationType)) - // return CreateScopeRootResolution(implementationType, referenceGenerator, DisposableCollectionResolution, currentParameters); - - if (!skip.HasFlag(Skip.RangedInstanceCheck) && CheckTypeProperties.ShouldBeScopedInstance(decoration.ImplementationType)) - return CreateScopedInstanceReferenceResolution(decoratorType, referenceGenerator, currentParameters, decoration); + internal record ForConstructorParameter( + INamedTypeSymbol ImplementationType, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentFuncParameters); - if (decoratorType.Constructors.SingleOrDefault() is not { } constructor) + internal abstract record ForConstructorParameterWithInterfaceExtension( + INamedTypeSymbol ImplementationType, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentFuncParameters, + InterfaceExtension InterfaceExtension) + : ForConstructorParameter(ImplementationType, CurrentFuncParameters); + + internal record ForConstructorParameterWithDecoration( + INamedTypeSymbol ImplementationType, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentFuncParameters, + DecorationInterfaceExtension Decoration) + : ForConstructorParameterWithInterfaceExtension(ImplementationType, CurrentFuncParameters, Decoration); + + internal record ForConstructorParameterWithComposition( + INamedTypeSymbol ImplementationType, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentFuncParameters, + CompositionInterfaceExtension Composition) + : ForConstructorParameterWithInterfaceExtension(ImplementationType, CurrentFuncParameters, Composition); + + protected Resolvable CreateConstructorResolution(ForConstructorParameter parameter) + { + var (implementationType, currentParameters) = parameter; + + if (implementationType.Constructors.SingleOrDefault() is not { } constructor) { - return new ErrorTreeItem(decoratorType.Constructors.Length switch + return new ErrorTreeItem(implementationType.Constructors.Length switch { - 0 => - $"[{decoratorType.FullName()}] Class.Constructor: No constructor found for implementation {decoratorType.FullName()}", - > 1 => - $"[{decoratorType.FullName()}] Class.Constructor: More than one constructor found for implementation {decoratorType.FullName()}", - _ => - $"[{decoratorType.FullName()}] Class.Constructor: {decoratorType.Constructors[0].Name} is not a method symbol" + 0 => $"[{implementationType.FullName()}] Class.Constructor: No constructor found for implementation {implementationType.FullName()}", + > 1 => $"[{implementationType.FullName()}] Class.Constructor: More than one constructor found for implementation {implementationType.FullName()}", + _ => $"[{implementationType.FullName()}] Class.Constructor: {implementationType.Constructors[0].Name} is not a method symbol" }); } + var checkForDecoration = false; + DecorationInterfaceExtension? decoration = null; + + if (parameter is ForConstructorParameterWithDecoration withDecoration) + { + checkForDecoration = true; + decoration = withDecoration.Decoration; + } + + var checkForComposition = false; + CompositionInterfaceExtension? composition = null; + + if (parameter is ForConstructorParameterWithComposition withComposition) + { + checkForComposition = true; + composition = withComposition.Composition; + } + return new ConstructorResolution( - referenceGenerator.Generate(decoratorType), - decoratorType.FullName(), + RootReferenceGenerator.Generate(implementationType), + implementationType.FullName(), ImplementsIDisposable( - decoratorType, + implementationType, WellKnownTypes, DisposableCollectionResolution, CheckTypeProperties), @@ -373,58 +533,65 @@ protected Resolvable CreateDecoratorConstructorResolution( .Parameters .Select(p => { - if (p.Type.Equals(decoration.InterfaceType, SymbolEqualityComparer.Default)) + if (checkForDecoration && p.Type.Equals(decoration?.InterfaceType, SymbolEqualityComparer.Default)) { return (p.Name, decoration.CurrentInterfaceResolution); } + if (checkForComposition + && composition is {} + && (p.Type.Equals(WellKnownTypes.Enumerable1.Construct(composition.InterfaceType), SymbolEqualityComparer.Default) + || p.Type.Equals(WellKnownTypes.ReadOnlyCollection1.Construct(composition.InterfaceType), SymbolEqualityComparer.Default) + || p.Type.Equals(WellKnownTypes.ReadOnlyList1.Construct(composition.InterfaceType), SymbolEqualityComparer.Default))) + { + + return (p.Name, new CollectionResolution( + RootReferenceGenerator.Generate(p.Type), + p.Type.FullName(), + composition.InterfaceType.FullName(), + composition.InterfaceResolutionComposition)); + } if (p.Type is not INamedTypeSymbol parameterType) { return ("", new ErrorTreeItem( - $"[{decoratorType.FullName()}] Class.Constructor.Parameter: Parameter type {p.Type.FullName()} is not a named type symbol")); + $"[{implementationType.FullName()}] Class.Constructor.Parameter: Parameter type {p.Type.FullName()} is not a named type symbol")); } return ( p.Name, - Create(parameterType, - referenceGenerator, - currentParameters)); + SwitchType(new SwitchTypeParameter( + parameterType, + currentParameters))); }) .ToList())); } + private RangedInstanceReferenceResolution CreateScopedInstanceReferenceResolution( - INamedTypeSymbol implementationType, - IReferenceGenerator referenceGenerator, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters, - Decoration? decoration) => + ForConstructorParameter parameter) => CreateRangedInstanceReferenceResolution( - implementationType, - referenceGenerator, - currentParameters, + parameter, "Scoped", - "this", - decoration); + "this"); protected RangedInstanceReferenceResolution CreateRangedInstanceReferenceResolution( - INamedTypeSymbol implementationType, - IReferenceGenerator referenceGenerator, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters, + ForConstructorParameter parameter, string label, - string owningObjectReference, - Decoration? decoration) + string owningObjectReference) { - var decorationKeySuffix = decoration is { } - ? $":::{decoration.ImplementationType}" - : ""; - var key = $"{implementationType.FullName()}{decorationKeySuffix}"; + var (implementationType, currentParameters) = parameter; + InterfaceExtension? interfaceExtension = parameter switch + { + ForConstructorParameterWithComposition withComposition => withComposition.Composition, + ForConstructorParameterWithDecoration withDecoration => withDecoration.Decoration, + _ => null + }; + var key = $"{implementationType.FullName()}{interfaceExtension?.KeySuffix() ?? ""}"; if (!RangedInstanceReferenceResolutions.TryGetValue( key, out RangedInstanceFunction function)) { - var decorationSuffix = decoration is { } - ? $"_{decoration.ImplementationType.Name}" - : ""; + var decorationSuffix = interfaceExtension?.RangedNameSuffix() ?? ""; function = new RangedInstanceFunction( RootReferenceGenerator.Generate($"Get{label}Instance", implementationType, decorationSuffix), implementationType.FullName(), @@ -436,15 +603,15 @@ protected RangedInstanceReferenceResolution CreateRangedInstanceReferenceResolut var listedParameterTypes = string.Join(",", currentParameters.Select(p => p.Item2.TypeFullName)); if (!RangedInstanceQueuedOverloads.Contains((function, listedParameterTypes))) { - var parameter = currentParameters + var tempParameter = currentParameters .Select(t => (t.Type, new ParameterResolution(RootReferenceGenerator.Generate(t.Type), t.Type.FullName()))) .ToList(); - RangedInstanceResolutionsQueue.Enqueue((function, parameter, implementationType, decoration)); + RangedInstanceResolutionsQueue.Enqueue((function, tempParameter, implementationType, interfaceExtension)); RangedInstanceQueuedOverloads.Add((function, listedParameterTypes)); } return new RangedInstanceReferenceResolution( - referenceGenerator.Generate(implementationType), + RootReferenceGenerator.Generate(implementationType), function, currentParameters.Select(t => t.Resolution).ToList(), owningObjectReference); @@ -454,15 +621,15 @@ protected void DoRangedInstancesWork() { while (RangedInstanceResolutionsQueue.Any()) { - var (scopedInstanceFunction, parameter, type, decoration) = RangedInstanceResolutionsQueue.Dequeue(); - var referenceGenerator = ReferenceGeneratorFactory.Create(); - var resolvable = decoration is {} - ? CreateDecoratorConstructorResolution(decoration, referenceGenerator, parameter, Skip.RangedInstanceCheck) - : CreateConstructorResolution( - type, - referenceGenerator, - parameter, - Skip.RangedInstanceCheck); + var (scopedInstanceFunction, parameter, type, interfaceExtension) = RangedInstanceResolutionsQueue.Dequeue(); + var resolvable = interfaceExtension switch + { + DecorationInterfaceExtension decoration => CreateConstructorResolution(new ForConstructorParameterWithDecoration( + decoration.DecoratorType, parameter, decoration)), + CompositionInterfaceExtension composition => CreateConstructorResolution(new ForConstructorParameterWithComposition( + composition.CompositeType, parameter, composition)), + _ => CreateConstructorResolution(new ForConstructorParameter(type, parameter)) + }; RangedInstances.Add(( scopedInstanceFunction, new RangedInstanceFunctionOverload( diff --git a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs index 35ef4b3c..55f6ee90 100644 --- a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs @@ -5,12 +5,11 @@ internal interface IScopeResolutionBuilder bool HasWorkToDo { get; } ScopeRootResolution AddCreateResolveFunction( + RangeResolutionBaseBuilder.IScopeRootParameter parameter, INamedTypeSymbol rootType, - IReferenceGenerator referenceGenerator, string singleInstanceScopeReference, DisposableCollectionResolution disposableCollectionResolution, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters, - RangeResolutionBaseBuilder.DecorationScopeRoot? decoration); + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters); void DoWork(); @@ -26,9 +25,9 @@ internal class ScopeResolutionBuilder : RangeResolutionBaseBuilder, IScopeResolu private readonly Dictionary _scopeRootFunctionResolutions = new (); private readonly HashSet<(ScopeRootFunction, string)> _scopeRootFunctionQueuedOverloads = new (); - private readonly Queue<(ScopeRootFunction, IReadOnlyList<(ITypeSymbol, ParameterResolution)>, INamedTypeSymbol, DecorationScopeRoot?)> _scopeRootFunctionResolutionsQueue = new(); + private readonly Queue<(ScopeRootFunction, IReadOnlyList, INamedTypeSymbol, IScopeRootParameter)> _scopeRootFunctionResolutionsQueue = new(); - public ScopeResolutionBuilder( + internal ScopeResolutionBuilder( // parameter IContainerResolutionBuilder containerResolutionBuilder, @@ -52,54 +51,39 @@ public ScopeResolutionBuilder( } protected override RangedInstanceReferenceResolution CreateSingleInstanceReferenceResolution( - INamedTypeSymbol implementationType, - IReferenceGenerator referenceGenerator, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters, - Decoration? decoration) => + ForConstructorParameter parameter) => _containerResolutionBuilder.CreateSingleInstanceReferenceResolution( - implementationType, - referenceGenerator, - _containerReference, - currentParameters, - decoration); + parameter, + _containerReference); protected override ScopeRootResolution CreateScopeRootResolution( + IScopeRootParameter parameter, INamedTypeSymbol rootType, - IReferenceGenerator referenceGenerator, DisposableCollectionResolution disposableCollectionResolution, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters, - DecorationScopeRoot? decoration) => + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) => AddCreateResolveFunction( + parameter, rootType, - referenceGenerator, _containerReference, disposableCollectionResolution, - currentParameters, - decoration); + currentParameters); public bool HasWorkToDo => _scopeRootFunctionResolutionsQueue.Any() || RangedInstanceResolutionsQueue.Any(); public ScopeRootResolution AddCreateResolveFunction( + IScopeRootParameter parameter, INamedTypeSymbol rootType, - IReferenceGenerator referenceGenerator, string singleInstanceScopeReference, DisposableCollectionResolution disposableCollectionResolution, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters, - DecorationScopeRoot? decoration) + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) { - var decorationKeySuffix = decoration is { } - ? $":::{decoration.ImplementationType}" - : ""; - var key = $"{rootType.FullName()}{decorationKeySuffix}"; + var key = $"{rootType.FullName()}{parameter.KeySuffix()}"; if (!_scopeRootFunctionResolutions.TryGetValue( key, out ScopeRootFunction function)) { - var decorationSuffix = decoration is { } - ? $"_{decoration.ImplementationType.Name}" - : ""; function = new ScopeRootFunction( - RootReferenceGenerator.Generate("Create", rootType, decorationSuffix), + RootReferenceGenerator.Generate("Create", rootType, parameter.RootFunctionSuffix()), rootType.FullName()); _scopeRootFunctionResolutions[key] = function; } @@ -107,17 +91,17 @@ public ScopeRootResolution AddCreateResolveFunction( var listedParameterTypes = string.Join(",", currentParameters.Select(p => p.Item2.TypeFullName)); if (!_scopeRootFunctionQueuedOverloads.Contains((function, listedParameterTypes))) { - var parameter = currentParameters - .Select(t => (t.Type, new ParameterResolution(RootReferenceGenerator.Generate(t.Type), t.Type.FullName()))) + var currParameter = currentParameters + .Select(t => new ParameterResolution(RootReferenceGenerator.Generate(t.Type), t.Type.FullName())) .ToList(); - _scopeRootFunctionResolutionsQueue.Enqueue((function, parameter, rootType, decoration)); + _scopeRootFunctionResolutionsQueue.Enqueue((function, currParameter, rootType, parameter)); _scopeRootFunctionQueuedOverloads.Add((function, listedParameterTypes)); } return new ScopeRootResolution( - referenceGenerator.Generate(rootType), + RootReferenceGenerator.Generate(rootType), rootType.FullName(), - referenceGenerator.Generate("scopeRoot"), + RootReferenceGenerator.Generate("scopeRoot"), Name, singleInstanceScopeReference, currentParameters.Select(t => t.Resolution).ToList(), @@ -131,48 +115,22 @@ public void DoWork() { while (_scopeRootFunctionResolutionsQueue.Any()) { - var (scopeRootFunction, parameter, type, decorationScopeRoot) = _scopeRootFunctionResolutionsQueue.Dequeue(); - var referenceGenerator = ReferenceGeneratorFactory.Create(); - var resolvable = CreateConstructorResolution( - decorationScopeRoot?.ImplementationType ?? type, - referenceGenerator, - parameter, - Skip.ScopeRootCheck); - - if (decorationScopeRoot is {InterfaceType: {} interfaceType, ImplementationType: {} implementationType}) - { - var currentInterfaceResolution = new InterfaceResolution( - referenceGenerator.Generate(interfaceType), - interfaceType.FullName(), - resolvable); - var decorators = new Queue(CheckDecorators.GetSequenceFor(interfaceType, implementationType)); - while (decorators.Any()) - { - var decorator = decorators.Dequeue(); - var decoratorResolution = CreateDecoratorConstructorResolution( - new Decoration( - interfaceType, - implementationType, - decorator, - currentInterfaceResolution), - referenceGenerator, - parameter, - Skip.None); - currentInterfaceResolution = new InterfaceResolution( - referenceGenerator.Generate(interfaceType), - interfaceType.FullName(), - decoratorResolution); - } + var (scopeRootFunction, parameter, type, functionParameter) = _scopeRootFunctionResolutionsQueue.Dequeue(); - resolvable = currentInterfaceResolution; - } + var resolvable = functionParameter switch + { + CreateInterfaceParameter createInterfaceParameter => CreateInterface(createInterfaceParameter), + SwitchImplementationParameter switchImplementationParameter => SwitchImplementation(switchImplementationParameter), + SwitchInterfaceAfterScopeRootParameter switchInterfaceAfterScopeRootParameter => SwitchInterfaceAfterScopeRoot(switchInterfaceAfterScopeRootParameter), + _ => throw new ArgumentOutOfRangeException(nameof(functionParameter)) + }; _rootResolutions.Add(new RootResolutionFunction( scopeRootFunction.Reference, type.FullName(), "internal", resolvable, - parameter.Select(t => t.Item2).ToList(), + parameter, "", Name, DisposalHandling)); diff --git a/Main/RoslynExtensions.cs b/Main/RoslynExtensions.cs index e91dc81d..5204369f 100644 --- a/Main/RoslynExtensions.cs +++ b/Main/RoslynExtensions.cs @@ -2,13 +2,13 @@ internal static class RoslynExtensions { - public static INamedTypeSymbol? GetTypeOrReport(this Compilation compilation, string metadataName) + internal static INamedTypeSymbol? GetTypeOrReport(this Compilation compilation, string metadataName) { var typeSymbol = compilation.GetTypeByMetadataName(metadataName); return typeSymbol; } // Picked from https://github.com/YairHalberstadt/stronginject Thank you! - public static bool IsOrReferencesErrorType(this ITypeSymbol type) + internal static bool IsOrReferencesErrorType(this ITypeSymbol type) { if (!type.ContainingType?.IsOrReferencesErrorType() ?? false) return false; @@ -23,7 +23,7 @@ public static bool IsOrReferencesErrorType(this ITypeSymbol type) } // Picked from https://github.com/YairHalberstadt/stronginject Thank you! - public static bool IsAccessibleInternally(this ITypeSymbol type) + internal static bool IsAccessibleInternally(this ITypeSymbol type) { if (type is ITypeParameterSymbol) return true; @@ -40,7 +40,7 @@ public static bool IsAccessibleInternally(this ITypeSymbol type) } // Picked from https://github.com/YairHalberstadt/stronginject Thank you! - public static string FullName(this ITypeSymbol type) => + internal static string FullName(this ITypeSymbol type) => type.ToDisplayString(new SymbolDisplayFormat( globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Included, typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces, @@ -49,6 +49,6 @@ public static string FullName(this ITypeSymbol type) => memberOptions: SymbolDisplayMemberOptions.IncludeRef)); // Picked from https://github.com/YairHalberstadt/stronginject Thank you! - public static string FullName(this INamespaceSymbol @namespace) => + internal static string FullName(this INamespaceSymbol @namespace) => @namespace.ToDisplayString(new SymbolDisplayFormat(typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces)); } \ No newline at end of file diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index c0d428da..f56a5210 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -22,7 +22,7 @@ public void Execute(GeneratorExecutionContext context) var getSetOfTypesWithProperties = new GetSetOfTypesWithProperties(getAllImplementations); var checkDecorators = new CheckDecorators(wellKnownTypes, getAssemblyAttributes, typesFromTypeAggregatingAttributes, getSetOfTypesWithProperties); var checkTypeProperties = new CheckTypeProperties(typesFromTypeAggregatingAttributes, getSetOfTypesWithProperties); - var typeToImplementationMapper = new TypeToImplementationsMapper(getAllImplementations, checkDecorators); + var typeToImplementationMapper = new TypeToImplementationsMapper(getAllImplementations, checkDecorators, checkTypeProperties); var containerGenerator = new ContainerGenerator(context, wellKnownTypes, diagLogger); var referenceGeneratorFactory = new ReferenceGeneratorFactory(ReferenceGeneratorFactory); var containerErrorGenerator = new ContainerErrorGenerator(context); diff --git a/Main/TypeToImplementationMapper.cs b/Main/TypeToImplementationMapper.cs index a7cd8a75..f7a5bcc0 100644 --- a/Main/TypeToImplementationMapper.cs +++ b/Main/TypeToImplementationMapper.cs @@ -9,12 +9,14 @@ internal class TypeToImplementationsMapper : ITypeToImplementationsMapper { private readonly Dictionary> _map; - public TypeToImplementationsMapper( + internal TypeToImplementationsMapper( IGetAllImplementations getAllImplementations, - ICheckDecorators checkDecorators) => + ICheckDecorators checkDecorators, + ICheckTypeProperties checkTypeProperties) => _map = getAllImplementations .AllImplementations .Where(t => !checkDecorators.IsDecorator(t.OriginalDefinition)) + .Where(t => !checkTypeProperties.IsComposite(t.OriginalDefinition)) .SelectMany(i => { return i.AllInterfaces.OfType().Select(ii => (ii, i)).Prepend((i, i)); }) .GroupBy(t => t.Item1, t => t.Item2) .ToDictionary(g => g.Key, g => g.Distinct(SymbolEqualityComparer.Default).OfType().ToList()); diff --git a/Main/TypesFromTypeAggregatingAttributes.cs b/Main/TypesFromTypeAggregatingAttributes.cs index 1e5014b5..cf9c98cf 100644 --- a/Main/TypesFromTypeAggregatingAttributes.cs +++ b/Main/TypesFromTypeAggregatingAttributes.cs @@ -1,6 +1,6 @@ namespace MrMeeseeks.DIE; -public interface ITypesFromTypeAggregatingAttributes +internal interface ITypesFromTypeAggregatingAttributes { IReadOnlyList Spy { get; } IReadOnlyList Transient { get; } @@ -8,11 +8,12 @@ public interface ITypesFromTypeAggregatingAttributes IReadOnlyList ScopedInstance { get; } IReadOnlyList ScopeRoot { get; } IReadOnlyList Decorator { get; } + IReadOnlyList Composite { get; } } internal class TypesFromTypeAggregatingAttributes : ITypesFromTypeAggregatingAttributes { - public TypesFromTypeAggregatingAttributes( + internal TypesFromTypeAggregatingAttributes( WellKnownTypes wellKnownTypes, IGetAssemblyAttributes getAssemblyAttributes) { @@ -22,6 +23,7 @@ public TypesFromTypeAggregatingAttributes( ScopedInstance = GetTypesFromAttribute(wellKnownTypes.ScopedInstanceAggregationAttribute).ToList(); ScopeRoot = GetTypesFromAttribute(wellKnownTypes.ScopeRootAggregationAttribute).ToList(); Decorator = GetTypesFromAttribute(wellKnownTypes.DecoratorAggregationAttribute).ToList(); + Composite = GetTypesFromAttribute(wellKnownTypes.CompositeAggregationAttribute).ToList(); IEnumerable GetTypesFromAttribute(INamedTypeSymbol attribute) => getAssemblyAttributes .AllAssemblyAttributes @@ -62,4 +64,5 @@ bool CheckValidType(TypedConstant typedConstant, out INamedTypeSymbol type) public IReadOnlyList ScopedInstance { get; } public IReadOnlyList ScopeRoot { get; } public IReadOnlyList Decorator { get; } + public IReadOnlyList Composite { get; } } \ No newline at end of file diff --git a/Main/WellKnownTypes.cs b/Main/WellKnownTypes.cs index ec247ac0..42e878f2 100644 --- a/Main/WellKnownTypes.cs +++ b/Main/WellKnownTypes.cs @@ -8,6 +8,7 @@ internal record WellKnownTypes( INamedTypeSymbol ScopedInstanceAggregationAttribute, INamedTypeSymbol ScopeRootAggregationAttribute, INamedTypeSymbol DecoratorAggregationAttribute, + INamedTypeSymbol CompositeAggregationAttribute, INamedTypeSymbol DecoratorSequenceChoiceAttribute, INamedTypeSymbol Disposable, INamedTypeSymbol AsyncDisposable, @@ -25,7 +26,7 @@ internal record WellKnownTypes( INamedTypeSymbol Exception, INamedTypeSymbol SemaphoreSlim) { - public static bool TryCreate(Compilation compilation, out WellKnownTypes wellKnownTypes) + internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellKnownTypes) { var iContainer = compilation.GetTypeOrReport("MrMeeseeks.DIE.IContainer`1"); var iDisposable = compilation.GetTypeOrReport("System.IDisposable"); @@ -65,6 +66,9 @@ public static bool TryCreate(Compilation compilation, out WellKnownTypes wellKno var decoratorAggregationAttribute = compilation .GetTypeByMetadataName(typeof(DecoratorAggregationAttribute).FullName ?? ""); + var compositeAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(CompositeAggregationAttribute).FullName ?? ""); + var decoratorSequenceChoiceAttribute = compilation .GetTypeByMetadataName(typeof(DecoratorSequenceChoiceAttribute).FullName ?? ""); @@ -75,6 +79,7 @@ public static bool TryCreate(Compilation compilation, out WellKnownTypes wellKno || scopedInstanceAggregationAttribute is null || scopeRootAggregationAttribute is null || decoratorAggregationAttribute is null + || compositeAggregationAttribute is null || decoratorSequenceChoiceAttribute is null || iDisposable is null || iAsyncDisposable is null @@ -104,6 +109,7 @@ public static bool TryCreate(Compilation compilation, out WellKnownTypes wellKno ScopedInstanceAggregationAttribute: scopedInstanceAggregationAttribute, ScopeRootAggregationAttribute: scopeRootAggregationAttribute, DecoratorAggregationAttribute: decoratorAggregationAttribute, + CompositeAggregationAttribute: compositeAggregationAttribute, DecoratorSequenceChoiceAttribute: decoratorSequenceChoiceAttribute, Disposable: iDisposable, AsyncDisposable: iAsyncDisposable, diff --git a/Sample/Container.cs b/Sample/Container.cs index d9f00896..ef5707c2 100644 --- a/Sample/Container.cs +++ b/Sample/Container.cs @@ -7,5 +7,6 @@ [assembly:ScopeRootAggregation(typeof(IScopeRoot))] [assembly:TransientAggregation(typeof(ITransient))] [assembly:DecoratorAggregation(typeof(IDecorator<>))] -[assembly:DecoratorSequenceChoice(typeof(IDecoratedMulti))] -[assembly:DecoratorSequenceChoice(typeof(DecoratorMultiBasisB), typeof(DecoratorMultiA), typeof(DecoratorMultiB))] \ No newline at end of file +[assembly:CompositeAggregation(typeof(IComposite<>))] +//[assembly:DecoratorSequenceChoice(typeof(IDecoratedMulti))] +//[assembly:DecoratorSequenceChoice(typeof(DecoratorMultiBasisB), typeof(DecoratorMultiA), typeof(DecoratorMultiB))] \ No newline at end of file diff --git a/Sample/Context.cs b/Sample/Context.cs index c14ba3aa..b846b3a4 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -1,39 +1,39 @@ -using System.Collections.Generic; +namespace MrMeeseeks.DIE.Sample; -namespace MrMeeseeks.DIE.Sample; - -internal interface IDecoratedMulti +internal interface IDecoratedScopeRoot { - IDecoratedMulti Decorated { get; } + IDecoratedScopeRootDependency Dependency { get; } + IDecoratedScopeRoot Decorated { get; } } -internal class DecoratorMultiBasisA : IDecoratedMulti -{ - public IDecoratedMulti Decorated => this; -} +internal interface IDecoratedScopeRootDependency {} -internal class DecoratorMultiBasisB : IDecoratedMulti -{ - public IDecoratedMulti Decorated => this; -} +internal class DecoratedScopeRootDependency : IDecoratedScopeRootDependency, IScopedInstance { } -internal class DecoratorMultiA : IDecoratedMulti, IDecorator +internal class DecoratorScopeRootBasis : IDecoratedScopeRoot, IScopeRoot, IScopedInstance { - public DecoratorMultiA(IDecoratedMulti decorated) => - Decorated = decorated; + public IDecoratedScopeRootDependency Dependency { get; } + + public IDecoratedScopeRoot Decorated => this; - public IDecoratedMulti Decorated { get; } + public DecoratorScopeRootBasis( + IDecoratedScopeRootDependency dependency) => + Dependency = dependency; } -internal class DecoratorMultiB : IDecoratedMulti, IDecorator +internal class DecoratorScopeRoot : IDecoratedScopeRoot, IDecorator { - public DecoratorMultiB(IDecoratedMulti decorated) => + public DecoratorScopeRoot(IDecoratedScopeRoot decorated, IDecoratedScopeRootDependency dependency) + { Decorated = decorated; + Dependency = dependency; + } - public IDecoratedMulti Decorated { get; } + public IDecoratedScopeRootDependency Dependency { get; } + public IDecoratedScopeRoot Decorated { get; } } -internal partial class DecoratorMultiContainer : IContainer> +internal partial class DecoratorScopeRootContainer : IContainer { } \ No newline at end of file diff --git a/Sample/MarkerInterfaces.cs b/Sample/MarkerInterfaces.cs index f103956b..b7993d38 100644 --- a/Sample/MarkerInterfaces.cs +++ b/Sample/MarkerInterfaces.cs @@ -4,4 +4,5 @@ public interface ISingleInstance { } public interface IScopedInstance { } public interface IScopeRoot { } public interface ITransient { } -public interface IDecorator { } \ No newline at end of file +public interface IDecorator { } +public interface IComposite { } \ No newline at end of file diff --git a/Sample/Program.cs b/Sample/Program.cs index 7931cf85..a6025558 100644 --- a/Sample/Program.cs +++ b/Sample/Program.cs @@ -1,6 +1,5 @@ -using System.Collections.Generic; -using MrMeeseeks.DIE.Sample; +using MrMeeseeks.DIE.Sample; System.Console.WriteLine("Hello, world!"); -using var container = new DecoratorMultiContainer(); -System.Console.WriteLine(((MrMeeseeks.DIE.IContainer>) container).Resolve()); \ No newline at end of file +using var container = new DecoratorScopeRootContainer(); +System.Console.WriteLine(((MrMeeseeks.DIE.IContainer) container).Resolve()); \ No newline at end of file diff --git a/Test/AssemblyInfo.cs b/Test/AssemblyInfo.cs new file mode 100644 index 00000000..f29596ae --- /dev/null +++ b/Test/AssemblyInfo.cs @@ -0,0 +1,16 @@ +using MrMeeseeks.DIE; +using MrMeeseeks.DIE.Sample; + +[assembly:SingleInstanceAggregation(typeof(ISingleInstance))] +[assembly:ScopedInstanceAggregation(typeof(IScopedInstance))] +[assembly:ScopeRootAggregation(typeof(IScopeRoot))] +[assembly:TransientAggregation(typeof(ITransient))] +[assembly:DecoratorAggregation(typeof(IDecorator<>))] +[assembly:CompositeAggregation(typeof(IComposite<>))] + +namespace MrMeeseeks.DIE.Sample; + +public class AssemblyInfo +{ + +} \ No newline at end of file diff --git a/Test/CompositeTests.cs b/Test/CompositeTests.cs new file mode 100644 index 00000000..33a4b810 --- /dev/null +++ b/Test/CompositeTests.cs @@ -0,0 +1,353 @@ +using System.Collections.Generic; +using MrMeeseeks.DIE; +using MrMeeseeks.DIE.Sample; +using Xunit; + +[assembly:DecoratorSequenceChoice(typeof(ICompositeDecorated), typeof(CompositeDecoratedDecoratorA), typeof(CompositeDecoratedDecoratorB))] +[assembly:DecoratorSequenceChoice(typeof(CompositeDecorated), typeof(CompositeDecoratedDecoratorB))] + +namespace MrMeeseeks.DIE.Sample; + +internal interface ICompositeNormal +{ + IReadOnlyList Composites { get; } +} + +internal class CompositeNormalBasisA : ICompositeNormal +{ + public IReadOnlyList Composites => new List { this }; +} + +internal class CompositeNormalBasisB : ICompositeNormal +{ + public IReadOnlyList Composites => new List { this }; +} + +internal class CompositeNormal : ICompositeNormal, IComposite +{ + public CompositeNormal(IReadOnlyList composites) => + Composites = composites; + + public IReadOnlyList Composites { get; } +} + +internal partial class CompositeNormalContainer : IContainer, IContainer> +{ + +} + +public partial class CompositeTests +{ + [Fact] + public void Normal() + { + using var container = new CompositeNormalContainer(); + var composite = ((IContainer) container).Resolve(); + foreach (var compositeComposite in composite.Composites) + { + Assert.NotEqual(composite, compositeComposite); + var type = compositeComposite.GetType(); + Assert.True(type == typeof(CompositeNormalBasisA) || type == typeof(CompositeNormalBasisB)); + } + } + + [Fact] + public void NormalList() + { + using var container = new CompositeNormalContainer(); + var composites = ((IContainer>) container).Resolve(); + foreach (var compositeComposite in composites) + { + var type = compositeComposite.GetType(); + Assert.True(type == typeof(CompositeNormalBasisA) || type == typeof(CompositeNormalBasisB)); + } + Assert.Equal(2, composites.Count); + } +} + +internal interface ICompositeSingleInstance +{ + IReadOnlyList Composites { get; } +} + +internal class CompositeSingleInstanceBasisA : ICompositeSingleInstance, ISingleInstance +{ + public IReadOnlyList Composites => new List { this }; +} + +internal class CompositeSingleInstanceBasisB : ICompositeSingleInstance, ISingleInstance +{ + public IReadOnlyList Composites => new List { this }; +} + +internal class CompositeSingleInstance : ICompositeSingleInstance, IComposite +{ + public CompositeSingleInstance(IReadOnlyList composites) => + Composites = composites; + + public IReadOnlyList Composites { get; } +} + +internal partial class CompositeSingleInstanceContainer : IContainer, IContainer> +{ + +} + +public partial class CompositeTests +{ + [Fact] + public void SingleInstance() + { + using var container = new CompositeSingleInstanceContainer(); + var composite = ((IContainer) container).Resolve(); + foreach (var compositeComposite in composite.Composites) + { + Assert.NotEqual(composite, compositeComposite); + var type = compositeComposite.GetType(); + Assert.True(type == typeof(CompositeSingleInstanceBasisA) || type == typeof(CompositeSingleInstanceBasisB)); + } + var nextComposite = ((IContainer) container).Resolve(); + Assert.Equal(composite, nextComposite); + } + + [Fact] + public void SingleInstanceList() + { + using var container = new CompositeSingleInstanceContainer(); + var composites = ((IContainer>) container).Resolve(); + foreach (var compositeComposite in composites) + { + var type = compositeComposite.GetType(); + Assert.True(type == typeof(CompositeSingleInstanceBasisA) || type == typeof(CompositeSingleInstanceBasisB)); + } + Assert.Equal(2, composites.Count); + var nextComposites = ((IContainer>) container).Resolve(); + Assert.Equal(composites[0], nextComposites[0]); + Assert.Equal(composites[1], nextComposites[1]); + } +} + +internal interface ICompositeMixedScoping +{ + IReadOnlyList Composites { get; } +} + +internal class CompositeMixedScopingBasisA : ICompositeMixedScoping, ISingleInstance +{ + public IReadOnlyList Composites => new List { this }; +} + +internal class CompositeMixedScopingBasisB : ICompositeMixedScoping +{ + public IReadOnlyList Composites => new List { this }; +} + +internal class CompositeMixedScoping : ICompositeMixedScoping, IComposite +{ + public CompositeMixedScoping(IReadOnlyList composites) => + Composites = composites; + + public IReadOnlyList Composites { get; } +} + +internal partial class CompositeMixedScopingContainer : IContainer, IContainer> +{ + +} + +public partial class CompositeTests +{ + [Fact] + public void MixedScoping() + { + using var container = new CompositeMixedScopingContainer(); + var composite = ((IContainer) container).Resolve(); + foreach (var compositeComposite in composite.Composites) + { + Assert.NotEqual(composite, compositeComposite); + var type = compositeComposite.GetType(); + Assert.True(type == typeof(CompositeMixedScopingBasisA) || type == typeof(CompositeMixedScopingBasisB)); + } + var nextComposite = ((IContainer) container).Resolve(); + Assert.NotEqual(composite, nextComposite); + } + + [Fact] + public void MixedScopingList() + { + using var container = new CompositeMixedScopingContainer(); + var composites = ((IContainer>) container).Resolve(); + foreach (var compositeComposite in composites) + { + var type = compositeComposite.GetType(); + Assert.True(type == typeof(CompositeMixedScopingBasisA) || type == typeof(CompositeMixedScopingBasisB)); + } + Assert.Equal(2, composites.Count); + var nextComposites = ((IContainer>) container).Resolve(); + Assert.True(composites[0].Equals(nextComposites[0]) && !composites[1].Equals(nextComposites[1]) + || composites[1].Equals(nextComposites[1]) && !composites[0].Equals(nextComposites[0])); + } +} + +internal interface ICompositeScopeRoot +{ + IReadOnlyList Composites { get; } + ICompositeScopeRootDependency Dependency { get; } +} + +internal interface ICompositeScopeRootDependency { } + +internal class CompositeScopeRootDependency : ICompositeScopeRootDependency, IScopedInstance { } + +internal class CompositeScopeRootBasisA : ICompositeScopeRoot, IScopeRoot +{ + public CompositeScopeRootBasisA(ICompositeScopeRootDependency dependency) => Dependency = dependency; + + public IReadOnlyList Composites => new List { this }; + public ICompositeScopeRootDependency Dependency { get; } +} + +internal class CompositeScopeRootBasisB : ICompositeScopeRoot +{ + public CompositeScopeRootBasisB(ICompositeScopeRootDependency dependency) => Dependency = dependency; + + public IReadOnlyList Composites => new List { this }; + public ICompositeScopeRootDependency Dependency { get; } +} + +internal class CompositeScopeRoot : ICompositeScopeRoot, IComposite +{ + public CompositeScopeRoot(IReadOnlyList composites, ICompositeScopeRootDependency dependency) + { + Composites = composites; + Dependency = dependency; + } + + public IReadOnlyList Composites { get; } + public ICompositeScopeRootDependency Dependency { get; } +} + +internal partial class CompositeScopeRootContainer : IContainer, IContainer> +{ + +} + +public partial class CompositeTests +{ + [Fact] + public void ScopeRoot() + { + using var container = new CompositeScopeRootContainer(); + var composite = ((IContainer) container).Resolve(); + foreach (var compositeComposite in composite.Composites) + { + Assert.NotEqual(composite, compositeComposite); + var type = compositeComposite.GetType(); + Assert.True(type == typeof(CompositeScopeRootBasisA) || type == typeof(CompositeScopeRootBasisB)); + Assert.Equal(composite.Dependency, compositeComposite.Dependency); + } + var next = ((IContainer) container).Resolve(); + Assert.NotEqual(composite.Dependency, next.Dependency); + } + + [Fact] + public void ScopeRootList() + { + using var container = new CompositeScopeRootContainer(); + var composites = ((IContainer>) container).Resolve(); + foreach (var compositeComposite in composites) + { + var type = compositeComposite.GetType(); + Assert.True(type == typeof(CompositeScopeRootBasisA) || type == typeof(CompositeScopeRootBasisB)); + } + Assert.Equal(2, composites.Count); + Assert.NotEqual(composites[0].Dependency, composites[1].Dependency); + } +} + +internal interface ICompositeDecorated +{ + IReadOnlyList Composites { get; } + ICompositeDecorated Decorated { get; } +} + +internal class CompositeDecoratedDecoratorA : ICompositeDecorated, IDecorator +{ + public IReadOnlyList Composites => Decorated.Composites; + public ICompositeDecorated Decorated { get; } + + public CompositeDecoratedDecoratorA( + ICompositeDecorated decorated) => + Decorated = decorated; +} + +internal class CompositeDecoratedDecoratorB : ICompositeDecorated, IDecorator +{ + public IReadOnlyList Composites => Decorated.Composites; + public ICompositeDecorated Decorated { get; } + + public CompositeDecoratedDecoratorB( + ICompositeDecorated decorated) => + Decorated = decorated; +} + +internal class CompositeDecoratedBasisA : ICompositeDecorated +{ + public IReadOnlyList Composites => new List { this }; + public ICompositeDecorated Decorated => this; +} + +internal class CompositeDecoratedBasisB : ICompositeDecorated +{ + public IReadOnlyList Composites => new List { this }; + public ICompositeDecorated Decorated => this; +} + +internal class CompositeDecorated : ICompositeDecorated, IComposite +{ + public CompositeDecorated(IReadOnlyList composites) => + Composites = composites; + + public IReadOnlyList Composites { get; } + public ICompositeDecorated Decorated => this; +} + +internal partial class CompositeDecoratedContainer : IContainer, IContainer> +{ + +} + +public partial class CompositeTests +{ + [Fact] + public void Decorated() + { + using var container = new CompositeDecoratedContainer(); + var composite = ((IContainer) container).Resolve(); + Assert.IsType(composite); + Assert.IsType(composite.Decorated); + foreach (var compositeComposite in composite.Composites) + { + Assert.NotEqual(composite, compositeComposite); + Assert.IsType(compositeComposite); + Assert.IsType(compositeComposite.Decorated); + var baseImpl = compositeComposite.Decorated.Decorated; + Assert.True(baseImpl.GetType() == typeof(CompositeDecoratedBasisA) || baseImpl.GetType() == typeof(CompositeDecoratedBasisB)); + } + } + + [Fact] + public void DecoratedList() + { + using var container = new CompositeDecoratedContainer(); + var composites = ((IContainer>) container).Resolve(); + foreach (var compositeComposite in composites) + { + Assert.IsType(compositeComposite); + Assert.IsType(compositeComposite.Decorated); + var baseImpl = compositeComposite.Decorated.Decorated; + Assert.True(baseImpl.GetType() == typeof(CompositeDecoratedBasisA) || baseImpl.GetType() == typeof(CompositeDecoratedBasisB)); + } + Assert.Equal(2, composites.Count); + } +} \ No newline at end of file diff --git a/Test/DecoratorTests.cs b/Test/DecoratorTests.cs index db41e720..4e2fc8e3 100644 --- a/Test/DecoratorTests.cs +++ b/Test/DecoratorTests.cs @@ -3,11 +3,6 @@ using MrMeeseeks.DIE.Sample; using Xunit; -[assembly:SingleInstanceAggregation(typeof(ISingleInstance))] -[assembly:ScopedInstanceAggregation(typeof(IScopedInstance))] -[assembly:ScopeRootAggregation(typeof(IScopeRoot))] -[assembly:TransientAggregation(typeof(ITransient))] -[assembly:DecoratorAggregation(typeof(IDecorator<>))] [assembly:DecoratorSequenceChoice(typeof(IDecoratedMulti), typeof(DecoratorMultiA), typeof(DecoratorMultiB))] namespace MrMeeseeks.DIE.Sample; @@ -90,19 +85,34 @@ public void SingleInstance() internal interface IDecoratedScopeRoot { + IDecoratedScopeRootDependency Dependency { get; } IDecoratedScopeRoot Decorated { get; } } -internal class DecoratorScopeRootBasis : IDecoratedScopeRoot, IScopeRoot +internal interface IDecoratedScopeRootDependency {} + +internal class DecoratedScopeRootDependency : IDecoratedScopeRootDependency, IScopedInstance {} + +internal class DecoratorScopeRootBasis : IDecoratedScopeRoot, IScopeRoot, IScopedInstance { + public IDecoratedScopeRootDependency Dependency { get; } + public IDecoratedScopeRoot Decorated => this; + + public DecoratorScopeRootBasis( + IDecoratedScopeRootDependency dependency) => + Dependency = dependency; } internal class DecoratorScopeRoot : IDecoratedScopeRoot, IDecorator { - public DecoratorScopeRoot(IDecoratedScopeRoot decorated) => + public DecoratorScopeRoot(IDecoratedScopeRoot decorated, IDecoratedScopeRootDependency dependency) + { Decorated = decorated; + Dependency = dependency; + } + public IDecoratedScopeRootDependency Dependency { get; } public IDecoratedScopeRoot Decorated { get; } } @@ -119,11 +129,14 @@ public void ScopeRoot() using var container = new DecoratorScopeRootContainer(); var decorated = ((IContainer) container).Resolve(); Assert.NotEqual(decorated, decorated.Decorated); + Assert.Equal(decorated.Dependency, decorated.Decorated.Dependency); Assert.IsType(decorated); Assert.IsType(decorated.Decorated); // There is yet no way to check scopes externally - Assert.True(false); + var next = ((IContainer) container).Resolve(); + Assert.NotEqual(decorated, next); + Assert.NotEqual(decorated.Dependency, next.Dependency); } } diff --git a/Test/MarkerInterfaces.cs b/Test/MarkerInterfaces.cs index f103956b..b7993d38 100644 --- a/Test/MarkerInterfaces.cs +++ b/Test/MarkerInterfaces.cs @@ -4,4 +4,5 @@ public interface ISingleInstance { } public interface IScopedInstance { } public interface IScopeRoot { } public interface ITransient { } -public interface IDecorator { } \ No newline at end of file +public interface IDecorator { } +public interface IComposite { } \ No newline at end of file From a4f097abd6afde707a5f5bf43f16353e2e24705e Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Mon, 6 Dec 2021 19:36:45 +0100 Subject: [PATCH 028/162] Implemented ImplementationAggregationAttribute --- Main/Attributes.cs | 7 ++++++ Main/GetAllImplementations.cs | 5 ++--- Main/TypesFromTypeAggregatingAttributes.cs | 3 +++ Main/WellKnownTypes.cs | 6 ++++++ Test/ImplementationAggregationTests.cs | 25 ++++++++++++++++++++++ 5 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 Test/ImplementationAggregationTests.cs diff --git a/Main/Attributes.cs b/Main/Attributes.cs index 70f6a67b..93c13d78 100644 --- a/Main/Attributes.cs +++ b/Main/Attributes.cs @@ -6,6 +6,13 @@ public class SpyAggregationAttribute : Attribute // ReSharper disable once UnusedParameter.Local *** Is used in the generator public SpyAggregationAttribute(params Type[] types) {} } + +[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] +public class ImplementationAggregationAttribute : Attribute +{ + // ReSharper disable once UnusedParameter.Local *** Is used in the generator + public ImplementationAggregationAttribute(params Type[] types) {} +} [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] public class TransientAggregationAttribute : Attribute diff --git a/Main/GetAllImplementations.cs b/Main/GetAllImplementations.cs index 19317968..d1eb618c 100644 --- a/Main/GetAllImplementations.cs +++ b/Main/GetAllImplementations.cs @@ -18,9 +18,7 @@ internal GetAllImplementations( .SelectMany(t => t.st .GetRoot() .DescendantNodesAndSelf() - .Where(e => typeof(ClassDeclarationSyntax) == e.GetType() - || typeof(StructDeclarationSyntax) == e.GetType() - || typeof(RecordDeclarationSyntax) == e.GetType()) + .Where(e => e is ClassDeclarationSyntax or StructDeclarationSyntax or RecordDeclarationSyntax) .Select(c => t.Item2.GetDeclaredSymbol(c)) .Where(c => c is not null) .OfType()); @@ -34,6 +32,7 @@ internal GetAllImplementations( .OfType()); AllImplementations = implementationsOfThisAssembly + .Concat(typesFromTypeAggregatingAttributes.Implementation) .Concat(spiedImplementations) .ToList(); } diff --git a/Main/TypesFromTypeAggregatingAttributes.cs b/Main/TypesFromTypeAggregatingAttributes.cs index cf9c98cf..cb5908ff 100644 --- a/Main/TypesFromTypeAggregatingAttributes.cs +++ b/Main/TypesFromTypeAggregatingAttributes.cs @@ -3,6 +3,7 @@ namespace MrMeeseeks.DIE; internal interface ITypesFromTypeAggregatingAttributes { IReadOnlyList Spy { get; } + IReadOnlyList Implementation { get; } IReadOnlyList Transient { get; } IReadOnlyList SingleInstance { get; } IReadOnlyList ScopedInstance { get; } @@ -18,6 +19,7 @@ internal TypesFromTypeAggregatingAttributes( IGetAssemblyAttributes getAssemblyAttributes) { Spy = GetTypesFromAttribute(wellKnownTypes.SpyAggregationAttribute).ToList(); + Implementation = GetTypesFromAttribute(wellKnownTypes.ImplementationAggregationAttribute).ToList(); Transient = GetTypesFromAttribute(wellKnownTypes.TransientAggregationAttribute).ToList(); SingleInstance = GetTypesFromAttribute(wellKnownTypes.SingleInstanceAggregationAttribute).ToList(); ScopedInstance = GetTypesFromAttribute(wellKnownTypes.ScopedInstanceAggregationAttribute).ToList(); @@ -59,6 +61,7 @@ bool CheckValidType(TypedConstant typedConstant, out INamedTypeSymbol type) } public IReadOnlyList Spy { get; } + public IReadOnlyList Implementation { get; } public IReadOnlyList Transient { get; } public IReadOnlyList SingleInstance { get; } public IReadOnlyList ScopedInstance { get; } diff --git a/Main/WellKnownTypes.cs b/Main/WellKnownTypes.cs index 42e878f2..d46b510e 100644 --- a/Main/WellKnownTypes.cs +++ b/Main/WellKnownTypes.cs @@ -3,6 +3,7 @@ internal record WellKnownTypes( INamedTypeSymbol Container, INamedTypeSymbol SpyAggregationAttribute, + INamedTypeSymbol ImplementationAggregationAttribute, INamedTypeSymbol TransientAggregationAttribute, INamedTypeSymbol SingleInstanceAggregationAttribute, INamedTypeSymbol ScopedInstanceAggregationAttribute, @@ -51,6 +52,9 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK var spyAggregationAttribute = compilation .GetTypeByMetadataName(typeof(SpyAggregationAttribute).FullName ?? ""); + var implementationAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(ImplementationAggregationAttribute).FullName ?? ""); + var transientAggregationAttribute = compilation .GetTypeByMetadataName(typeof(TransientAggregationAttribute).FullName ?? ""); @@ -74,6 +78,7 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK if (iContainer is null || spyAggregationAttribute is null + || implementationAggregationAttribute is null || transientAggregationAttribute is null || singleInstanceAggregationAttribute is null || scopedInstanceAggregationAttribute is null @@ -104,6 +109,7 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK wellKnownTypes = new WellKnownTypes( Container: iContainer, SpyAggregationAttribute: spyAggregationAttribute, + ImplementationAggregationAttribute: implementationAggregationAttribute, TransientAggregationAttribute: transientAggregationAttribute, SingleInstanceAggregationAttribute: singleInstanceAggregationAttribute, ScopedInstanceAggregationAttribute: scopedInstanceAggregationAttribute, diff --git a/Test/ImplementationAggregationTests.cs b/Test/ImplementationAggregationTests.cs new file mode 100644 index 00000000..8ec21850 --- /dev/null +++ b/Test/ImplementationAggregationTests.cs @@ -0,0 +1,25 @@ +using System; +using System.IO; +using MrMeeseeks.DIE; +using Xunit; + +[assembly:ImplementationAggregation(typeof(FileInfo))] + +namespace MrMeeseeks.DIE.Sample; + +internal partial class ImplementationAggregationContainer : IContainer> +{ + +} + +public partial class ImplementationAggregationTests +{ + [Fact] + public void ResolveExternalType() + { + using var container = new ImplementationAggregationContainer(); + var fileInfo = ((IContainer>) container).Resolve()(@"C:\HelloWorld.txt"); + Assert.NotNull(fileInfo); + Assert.IsType(fileInfo); + } +} \ No newline at end of file From a5cb524526e86ce78deec17a12202852f0fd2bb0 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sat, 20 Nov 2021 12:49:17 +0100 Subject: [PATCH 029/162] Initial commit on spying constructors --- Main/Attributes.cs | 8 +++++++ Main/RoslynExtensions.cs | 2 +- SampleChild/SampleChild.csproj | 21 +++++++++++++++++ Spy/Spy.csproj | 8 +++++-- Spy/TypeReportGenerator.cs | 41 ++++++++++++++++++++++++++++------ 5 files changed, 70 insertions(+), 10 deletions(-) create mode 100644 SampleChild/SampleChild.csproj diff --git a/Main/Attributes.cs b/Main/Attributes.cs index 93c13d78..9471dc73 100644 --- a/Main/Attributes.cs +++ b/Main/Attributes.cs @@ -61,4 +61,12 @@ public class DecoratorSequenceChoiceAttribute : Attribute { // ReSharper disable once UnusedParameter.Local *** Is used in the generator public DecoratorSequenceChoiceAttribute(Type decoratedType, params Type[] types) {} +} + +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Assembly | AttributeTargets.Class)] +public class ConstructorReferenceAttribute : Attribute +{ + public ConstructorReferenceAttribute(Type implementationType, params Type[] parameterTypes) + { + } } \ No newline at end of file diff --git a/Main/RoslynExtensions.cs b/Main/RoslynExtensions.cs index 5204369f..0711ecc5 100644 --- a/Main/RoslynExtensions.cs +++ b/Main/RoslynExtensions.cs @@ -1,6 +1,6 @@ namespace MrMeeseeks.DIE; -internal static class RoslynExtensions +public static class RoslynExtensions { internal static INamedTypeSymbol? GetTypeOrReport(this Compilation compilation, string metadataName) { diff --git a/SampleChild/SampleChild.csproj b/SampleChild/SampleChild.csproj new file mode 100644 index 00000000..4c2b7f02 --- /dev/null +++ b/SampleChild/SampleChild.csproj @@ -0,0 +1,21 @@ + + + + net5.0 + + MrMeeseeks.DIE.SampleChild + true + $(BaseIntermediateOutputPath)\GeneratedFiles + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + diff --git a/Spy/Spy.csproj b/Spy/Spy.csproj index c9f01e3f..f7f889d5 100644 --- a/Spy/Spy.csproj +++ b/Spy/Spy.csproj @@ -23,9 +23,9 @@ - + - + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -34,6 +34,10 @@ + + + + diff --git a/Spy/TypeReportGenerator.cs b/Spy/TypeReportGenerator.cs index 1d37f897..4bbe9df4 100644 --- a/Spy/TypeReportGenerator.cs +++ b/Spy/TypeReportGenerator.cs @@ -1,4 +1,6 @@ -using Microsoft.CodeAnalysis.CSharp; +using System; +using System.Runtime.Serialization; +using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Text; namespace MrMeeseeks.DIE.Spy; @@ -23,13 +25,16 @@ public TypeReportGenerator( public void Generate(string namespaceName) { + var allNonStaticImplementations = _getAllImplementations + .AllNonStaticImplementations + .ToList(); var generatedContainer = new StringBuilder() .AppendLine($"namespace {namespaceName}") .AppendLine("{"); - generatedContainer = GenerateBody(Accessibility.Public, _getAllImplementations, generatedContainer); + generatedContainer = GenerateBody(Accessibility.Public, allNonStaticImplementations, generatedContainer); - generatedContainer = GenerateBody(Accessibility.Internal, _getAllImplementations, generatedContainer); + generatedContainer = GenerateBody(Accessibility.Internal, allNonStaticImplementations, generatedContainer); generatedContainer = generatedContainer .AppendLine("}"); @@ -42,13 +47,12 @@ public void Generate(string namespaceName) .GetText(); _context.AddSource("TypeReport.g.cs", containerSource); - static StringBuilder GenerateBody(Accessibility accessModifier, IGetAllImplementations getAllImplementations, StringBuilder generatedContainer) + static StringBuilder GenerateBody(Accessibility accessModifier, IList allNonStaticImplementations, StringBuilder generatedContainer) { var lowerCaseAccessModifier = accessModifier.ToString().ToLower(); var pascalCaseAccessModifier = accessModifier.ToString(); - var types = getAllImplementations - .AllNonStaticImplementations + var types = allNonStaticImplementations .Where(t => t.DeclaredAccessibility == accessModifier) .ToList(); @@ -63,7 +67,30 @@ static StringBuilder GenerateBody(Accessibility accessModifier, IGetAllImplement $"{FullName(type)} Type{++i}{(type.TypeArguments.Length > 0 ? $"<{string.Join(", ", type.TypeArguments.Select(t => t.Name))}>" : "")}(){TypeArgumentsConstraintsString(type)};")); generatedContainer = generatedContainer - .AppendLine("}"); + .AppendLine("}") + .AppendLine($"{lowerCaseAccessModifier} enum {pascalCaseAccessModifier}ConstructorReport") + .AppendLine("{"); + + generatedContainer = allNonStaticImplementations + .SelectMany(i => i.Constructors) + .Where(c => c.DeclaredAccessibility == accessModifier) + .Select(c => (c, $"{c.ContainingType.Name}{(c.Parameters.Any() ? $"_{string.Join("_", c.Parameters.Select(p => p.Type.Name))}" : "")}")) + .GroupBy(t => t.Item2) + .SelectMany(g => !g.Any() + ? Array.Empty<(IMethodSymbol, string)>() + : g.Count() == 1 + ? new (IMethodSymbol, string)[] { (g.First().c, g.Key) } + : g.Select((t, i) => (t.c, $"{t.Item2}_{i}"))) + .Select(t => @$" +[global::{typeof(EnumMemberAttribute).FullName}({nameof(EnumMemberAttribute.Value)} = ""{t.c.ToDisplayString()}"")] +[global::{typeof(ConstructorReferenceAttribute).FullName}(typeof({t.c.ContainingType.FullName()}){(t.c.Parameters.Any() ? $", {string.Join(", ", t.c.Parameters.Select(p => $"typeof({p.Type.FullName()})"))}" : "")})] +{t.Item2},") + .Aggregate( + generatedContainer, + (current, line) => current.AppendLine(line)); + + generatedContainer = generatedContainer + .AppendLine("}"); return generatedContainer; } From 51827492bcb01e7ea1f84b059646447f397e9c8c Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Tue, 7 Dec 2021 11:09:14 +0100 Subject: [PATCH 030/162] WIP --- Main/Attributes.cs | 25 ++++---- Main/CheckTypeProperties.cs | 62 ++++++++++++++++++- Main/ExecuteImpl.cs | 29 +++++---- Main/Main.csproj | 2 +- Main/Properties/launchSettings.json | 3 - .../RangeResolutionBaseBuilder.cs | 4 +- Main/RoslynExtensions.cs | 2 +- Main/SourceGenerator.cs | 2 +- Main/WellKnownTypes.cs | 12 ++++ MrMeeseeks.DIE.sln | 12 ++++ Sample/Context.cs | 43 +++---------- Sample/Program.cs | 10 +-- SampleChild/Class1.cs | 30 +++++++++ SampleChild/SampleChild.csproj | 29 ++++----- Spy/Attributes.cs | 11 ++++ Spy/Properties/launchSettings.json | 8 +++ Spy/RoslynExtensions.cs | 13 ++++ Spy/Spy.csproj | 4 -- Spy/TypeReportGenerator.cs | 2 +- Test/AssemblyInfo.cs | 5 +- Test/CompositeTests.cs | 4 +- Test/ConstructorChoiceTests.cs | 26 ++++++++ Test/DecoratorTests.cs | 4 +- Test/ImplementationAggregationTests.cs | 8 ++- Test/MarkerInterfaces.cs | 2 +- Test/Test.csproj | 3 +- TestChild/Class.cs | 31 ++++++++++ TestChild/TestChild.csproj | 19 ++++++ 28 files changed, 302 insertions(+), 103 deletions(-) create mode 100644 SampleChild/Class1.cs create mode 100644 Spy/Attributes.cs create mode 100644 Spy/Properties/launchSettings.json create mode 100644 Spy/RoslynExtensions.cs create mode 100644 Test/ConstructorChoiceTests.cs create mode 100644 TestChild/Class.cs create mode 100644 TestChild/TestChild.csproj diff --git a/Main/Attributes.cs b/Main/Attributes.cs index 9471dc73..67f4ec3f 100644 --- a/Main/Attributes.cs +++ b/Main/Attributes.cs @@ -1,72 +1,71 @@ namespace MrMeeseeks.DIE; +// ReSharper disable UnusedParameter.Local *** The constructor parameters of the attributes will be used. Trust me, imma dev. [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] public class SpyAggregationAttribute : Attribute { - // ReSharper disable once UnusedParameter.Local *** Is used in the generator public SpyAggregationAttribute(params Type[] types) {} } +[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] +public class SpyConstructorChoiceAggregationAttribute : Attribute +{ + public SpyConstructorChoiceAggregationAttribute(params Enum[] references) {} +} + [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] public class ImplementationAggregationAttribute : Attribute { - // ReSharper disable once UnusedParameter.Local *** Is used in the generator public ImplementationAggregationAttribute(params Type[] types) {} } [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] public class TransientAggregationAttribute : Attribute { - // ReSharper disable once UnusedParameter.Local *** Is used in the generator public TransientAggregationAttribute(params Type[] types) {} } [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] public class SingleInstanceAggregationAttribute : Attribute { - // ReSharper disable once UnusedParameter.Local *** Is used in the generator public SingleInstanceAggregationAttribute(params Type[] types) {} } [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] public class ScopedInstanceAggregationAttribute : Attribute { - // ReSharper disable once UnusedParameter.Local *** Is used in the generator public ScopedInstanceAggregationAttribute(params Type[] types) {} } [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] public class ScopeRootAggregationAttribute : Attribute { - // ReSharper disable once UnusedParameter.Local *** Is used in the generator public ScopeRootAggregationAttribute(params Type[] types) {} } [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] public class DecoratorAggregationAttribute : Attribute { - // ReSharper disable once UnusedParameter.Local *** Is used in the generator public DecoratorAggregationAttribute(params Type[] types) {} } [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] public class CompositeAggregationAttribute : Attribute { - // ReSharper disable once UnusedParameter.Local *** Is used in the generator public CompositeAggregationAttribute(params Type[] types) {} } [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] public class DecoratorSequenceChoiceAttribute : Attribute { - // ReSharper disable once UnusedParameter.Local *** Is used in the generator public DecoratorSequenceChoiceAttribute(Type decoratedType, params Type[] types) {} } -[AttributeUsage(AttributeTargets.Field | AttributeTargets.Assembly | AttributeTargets.Class)] -public class ConstructorReferenceAttribute : Attribute +[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] +public class ConstructorChoiceAttribute : Attribute { - public ConstructorReferenceAttribute(Type implementationType, params Type[] parameterTypes) + public ConstructorChoiceAttribute(Type implementationType, params Type[] parameterTypes) { } -} \ No newline at end of file +} +// ReSharper enable UnusedParameter.Local \ No newline at end of file diff --git a/Main/CheckTypeProperties.cs b/Main/CheckTypeProperties.cs index 57dc1cf5..d3fd93dc 100644 --- a/Main/CheckTypeProperties.cs +++ b/Main/CheckTypeProperties.cs @@ -16,6 +16,7 @@ internal interface ICheckTypeProperties ScopeLevel GetScopeLevelFor(INamedTypeSymbol implementationType); INamedTypeSymbol GetCompositeFor(INamedTypeSymbol interfaceType); bool IsComposite(INamedTypeSymbol implementationType); + IMethodSymbol? GetConstructorChoiceFor(INamedTypeSymbol implementationType); } internal class CheckTypeProperties : ICheckTypeProperties @@ -25,10 +26,13 @@ internal class CheckTypeProperties : ICheckTypeProperties private readonly IImmutableSet _scopedInstanceTypes; private readonly IImmutableSet _scopeRootTypes; private readonly IImmutableSet _compositeTypes; - private readonly Dictionary _interfaceToComposite; + private readonly Dictionary _interfaceToComposite; + private readonly Dictionary _implementationToConstructorChoice; internal CheckTypeProperties( ITypesFromTypeAggregatingAttributes typesFromTypeAggregatingAttributes, + IGetAssemblyAttributes getAssemblyAttributes, + WellKnownTypes wellKnownTypes, IGetSetOfTypesWithProperties getSetOfTypesWithProperties) { _transientTypes = getSetOfTypesWithProperties.Get(typesFromTypeAggregatingAttributes.Transient); @@ -47,6 +51,52 @@ internal CheckTypeProperties( }, SymbolEqualityComparer.Default) .Where(g => g.Count() == 1) .ToDictionary(g => g.Key, g => g.Single(), SymbolEqualityComparer.Default); + + _implementationToConstructorChoice = getAssemblyAttributes + .AllAssemblyAttributes + .Concat(getAssemblyAttributes + .AllAssemblyAttributes + .Where(ad => + ad.AttributeClass?.Equals(wellKnownTypes.SpyConstructorChoiceAggregationAttribute, + SymbolEqualityComparer.Default) ?? false) + .SelectMany(ad => ad + .ConstructorArguments + .Where(ca => ca.Kind == TypedConstantKind.Enum) + .Select(ca => ca.Value as INamedTypeSymbol) + .OfType() + .SelectMany(e => e.GetAttributes()))) + .Where(ad => + ad.AttributeClass?.Equals(wellKnownTypes.ConstructorChoiceAttribute, + SymbolEqualityComparer.Default) ?? false) + .Select(ad => + { + if (ad.ConstructorArguments.Length < 2) + return null; + var implementationType = ad.ConstructorArguments[0].Value as INamedTypeSymbol; + var parameterTypes = ad + .ConstructorArguments[1] + .Values + .Select(tc => tc.Value) + .OfType() + .ToList(); + + if (implementationType is { }) + { + var constructorChoice = implementationType + .Constructors + .Where(c => c.Parameters.Length == parameterTypes.Count) + .SingleOrDefault(c => c.Parameters.Select(p => p.Type) + .Zip(parameterTypes, (pLeft, pRight) => pLeft.Equals(pRight, SymbolEqualityComparer.Default)) + .All(b => b)); + return constructorChoice is { } + ? (implementationType, constructorChoice) + : ((INamedTypeSymbol, IMethodSymbol)?) null; + } + + return null; + }) + .OfType<(INamedTypeSymbol, IMethodSymbol)>() + .ToDictionary(t => t.Item1, t => t.Item2); } public bool ShouldBeManaged(INamedTypeSymbol implementationType) => !_transientTypes.Contains(implementationType); @@ -63,4 +113,14 @@ public ScopeLevel GetScopeLevelFor(INamedTypeSymbol implementationType) public INamedTypeSymbol GetCompositeFor(INamedTypeSymbol interfaceType) => _interfaceToComposite[interfaceType]; public bool IsComposite(INamedTypeSymbol implementationType) => _compositeTypes.Contains(implementationType); + public IMethodSymbol? GetConstructorChoiceFor(INamedTypeSymbol implementationType) + { + if (implementationType.Constructors.Length == 1 + && implementationType.Constructors.SingleOrDefault() is { } constructor) + return constructor; + + return _implementationToConstructorChoice.TryGetValue(implementationType, out var constr) + ? constr : + null; + } } \ No newline at end of file diff --git a/Main/ExecuteImpl.cs b/Main/ExecuteImpl.cs index a46c44e5..e7a3e96f 100644 --- a/Main/ExecuteImpl.cs +++ b/Main/ExecuteImpl.cs @@ -55,19 +55,26 @@ public void Execute() .Where(x => x.AllInterfaces.Any(x => x.OriginalDefinition.Equals(_wellKnownTypes.Container, SymbolEqualityComparer.Default))); foreach (var namedTypeSymbol in containerClasses) { - var containerInfo = _containerInfoFactory(namedTypeSymbol); - if (containerInfo.IsValid) + try { - var containerResolutionBuilder = _containerResolutionBuilderFactory(containerInfo); - containerResolutionBuilder.AddCreateResolveFunctions(containerInfo.ResolutionRootTypes); - var containerResolution = containerResolutionBuilder.Build(); - var errorTreeItems = _resolutionTreeCreationErrorHarvester.Harvest(containerResolution); - if (errorTreeItems.Any()) - _containerErrorGenerator.Generate(containerInfo, errorTreeItems); - else - _containerGenerator.Generate(containerInfo, containerResolution); + var containerInfo = _containerInfoFactory(namedTypeSymbol); + if (containerInfo.IsValid) + { + var containerResolutionBuilder = _containerResolutionBuilderFactory(containerInfo); + containerResolutionBuilder.AddCreateResolveFunctions(containerInfo.ResolutionRootTypes); + var containerResolution = containerResolutionBuilder.Build(); + var errorTreeItems = _resolutionTreeCreationErrorHarvester.Harvest(containerResolution); + if (errorTreeItems.Any()) + _containerErrorGenerator.Generate(containerInfo, errorTreeItems); + else + _containerGenerator.Generate(containerInfo, containerResolution); + } + else throw new NotImplementedException("Handle non-valid container information"); + } + catch (Exception) + { + // ignore } - else throw new NotImplementedException("Handle non-valid container information"); } } diff --git a/Main/Main.csproj b/Main/Main.csproj index 90b5dc43..2249215f 100644 --- a/Main/Main.csproj +++ b/Main/Main.csproj @@ -4,7 +4,7 @@ Library netstandard2.0 MrMeeseeks.DIE - $(RootNamespace) + MrMeeseeks.DIE true true diff --git a/Main/Properties/launchSettings.json b/Main/Properties/launchSettings.json index ae8702f9..048ecac2 100644 --- a/Main/Properties/launchSettings.json +++ b/Main/Properties/launchSettings.json @@ -3,9 +3,6 @@ "Main": { "commandName": "DebugRoslynComponent", "targetProject": "..\\Sample\\Sample.csproj" - }, - "Profile 1": { - "commandName": "Executable" } } } \ No newline at end of file diff --git a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs index bd832e99..a33ce4f5 100644 --- a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs +++ b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs @@ -175,7 +175,7 @@ protected Resolvable SwitchType(SwitchTypeParameter parameter) if (type.TypeKind == TypeKind.Interface) return SwitchInterface(new SwitchInterfaceParameter(type, currentFuncParameters)); - if (type.TypeKind == TypeKind.Class) + if (type.TypeKind == TypeKind.Class || type.TypeKind == TypeKind.Struct) return SwitchClass(new SwitchClassParameter(type, currentFuncParameters)); if (type.TypeKind == TypeKind.Delegate @@ -493,7 +493,7 @@ protected Resolvable CreateConstructorResolution(ForConstructorParameter paramet { var (implementationType, currentParameters) = parameter; - if (implementationType.Constructors.SingleOrDefault() is not { } constructor) + if (CheckTypeProperties.GetConstructorChoiceFor(implementationType) is not { } constructor) { return new ErrorTreeItem(implementationType.Constructors.Length switch { diff --git a/Main/RoslynExtensions.cs b/Main/RoslynExtensions.cs index 0711ecc5..0dd3acd9 100644 --- a/Main/RoslynExtensions.cs +++ b/Main/RoslynExtensions.cs @@ -40,7 +40,7 @@ internal static bool IsAccessibleInternally(this ITypeSymbol type) } // Picked from https://github.com/YairHalberstadt/stronginject Thank you! - internal static string FullName(this ITypeSymbol type) => + public static string FullName(this ITypeSymbol type) => type.ToDisplayString(new SymbolDisplayFormat( globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Included, typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces, diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index f56a5210..217b6263 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -21,7 +21,7 @@ public void Execute(GeneratorExecutionContext context) var getAllImplementations = new GetAllImplementations(context, typesFromTypeAggregatingAttributes); var getSetOfTypesWithProperties = new GetSetOfTypesWithProperties(getAllImplementations); var checkDecorators = new CheckDecorators(wellKnownTypes, getAssemblyAttributes, typesFromTypeAggregatingAttributes, getSetOfTypesWithProperties); - var checkTypeProperties = new CheckTypeProperties(typesFromTypeAggregatingAttributes, getSetOfTypesWithProperties); + var checkTypeProperties = new CheckTypeProperties(typesFromTypeAggregatingAttributes, getAssemblyAttributes, wellKnownTypes, getSetOfTypesWithProperties); var typeToImplementationMapper = new TypeToImplementationsMapper(getAllImplementations, checkDecorators, checkTypeProperties); var containerGenerator = new ContainerGenerator(context, wellKnownTypes, diagLogger); var referenceGeneratorFactory = new ReferenceGeneratorFactory(ReferenceGeneratorFactory); diff --git a/Main/WellKnownTypes.cs b/Main/WellKnownTypes.cs index d46b510e..4c537510 100644 --- a/Main/WellKnownTypes.cs +++ b/Main/WellKnownTypes.cs @@ -3,6 +3,7 @@ internal record WellKnownTypes( INamedTypeSymbol Container, INamedTypeSymbol SpyAggregationAttribute, + INamedTypeSymbol SpyConstructorChoiceAggregationAttribute, INamedTypeSymbol ImplementationAggregationAttribute, INamedTypeSymbol TransientAggregationAttribute, INamedTypeSymbol SingleInstanceAggregationAttribute, @@ -11,6 +12,7 @@ internal record WellKnownTypes( INamedTypeSymbol DecoratorAggregationAttribute, INamedTypeSymbol CompositeAggregationAttribute, INamedTypeSymbol DecoratorSequenceChoiceAttribute, + INamedTypeSymbol ConstructorChoiceAttribute, INamedTypeSymbol Disposable, INamedTypeSymbol AsyncDisposable, INamedTypeSymbol Lazy1, @@ -52,6 +54,9 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK var spyAggregationAttribute = compilation .GetTypeByMetadataName(typeof(SpyAggregationAttribute).FullName ?? ""); + var spyConstructorChoiceAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(SpyConstructorChoiceAggregationAttribute).FullName ?? ""); + var implementationAggregationAttribute = compilation .GetTypeByMetadataName(typeof(ImplementationAggregationAttribute).FullName ?? ""); @@ -76,8 +81,12 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK var decoratorSequenceChoiceAttribute = compilation .GetTypeByMetadataName(typeof(DecoratorSequenceChoiceAttribute).FullName ?? ""); + var constructorChoiceAttribute = compilation + .GetTypeByMetadataName(typeof(ConstructorChoiceAttribute).FullName ?? ""); + if (iContainer is null || spyAggregationAttribute is null + || spyConstructorChoiceAggregationAttribute is null || implementationAggregationAttribute is null || transientAggregationAttribute is null || singleInstanceAggregationAttribute is null @@ -86,6 +95,7 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK || decoratorAggregationAttribute is null || compositeAggregationAttribute is null || decoratorSequenceChoiceAttribute is null + || constructorChoiceAttribute is null || iDisposable is null || iAsyncDisposable is null || lazy1 is null @@ -109,6 +119,7 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK wellKnownTypes = new WellKnownTypes( Container: iContainer, SpyAggregationAttribute: spyAggregationAttribute, + SpyConstructorChoiceAggregationAttribute: spyConstructorChoiceAggregationAttribute, ImplementationAggregationAttribute: implementationAggregationAttribute, TransientAggregationAttribute: transientAggregationAttribute, SingleInstanceAggregationAttribute: singleInstanceAggregationAttribute, @@ -117,6 +128,7 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK DecoratorAggregationAttribute: decoratorAggregationAttribute, CompositeAggregationAttribute: compositeAggregationAttribute, DecoratorSequenceChoiceAttribute: decoratorSequenceChoiceAttribute, + ConstructorChoiceAttribute: constructorChoiceAttribute, Disposable: iDisposable, AsyncDisposable: iAsyncDisposable, Lazy1: lazy1, diff --git a/MrMeeseeks.DIE.sln b/MrMeeseeks.DIE.sln index 33809b7a..ac5c5bcb 100644 --- a/MrMeeseeks.DIE.sln +++ b/MrMeeseeks.DIE.sln @@ -16,6 +16,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Spy", "Spy\Spy.csproj", "{4 EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test", "Test\Test.csproj", "{5075D83B-EF12-4372-8210-CEB5D81A4FE2}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestChild", "TestChild\TestChild.csproj", "{1CCECD48-C564-4799-8A4C-19A9BF847795}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SampleChild", "SampleChild\SampleChild.csproj", "{73D1DC76-4CD8-4534-8717-0551B635F864}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -38,6 +42,14 @@ Global {5075D83B-EF12-4372-8210-CEB5D81A4FE2}.Debug|Any CPU.Build.0 = Debug|Any CPU {5075D83B-EF12-4372-8210-CEB5D81A4FE2}.Release|Any CPU.ActiveCfg = Release|Any CPU {5075D83B-EF12-4372-8210-CEB5D81A4FE2}.Release|Any CPU.Build.0 = Release|Any CPU + {1CCECD48-C564-4799-8A4C-19A9BF847795}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1CCECD48-C564-4799-8A4C-19A9BF847795}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1CCECD48-C564-4799-8A4C-19A9BF847795}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1CCECD48-C564-4799-8A4C-19A9BF847795}.Release|Any CPU.Build.0 = Release|Any CPU + {73D1DC76-4CD8-4534-8717-0551B635F864}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {73D1DC76-4CD8-4534-8717-0551B635F864}.Debug|Any CPU.Build.0 = Debug|Any CPU + {73D1DC76-4CD8-4534-8717-0551B635F864}.Release|Any CPU.ActiveCfg = Release|Any CPU + {73D1DC76-4CD8-4534-8717-0551B635F864}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Sample/Context.cs b/Sample/Context.cs index b846b3a4..b670a403 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -1,39 +1,14 @@ -namespace MrMeeseeks.DIE.Sample; +using System; +using MrMeeseeks.DIE; +//using SampleChild; -internal interface IDecoratedScopeRoot -{ - IDecoratedScopeRootDependency Dependency { get; } - IDecoratedScopeRoot Decorated { get; } -} - -internal interface IDecoratedScopeRootDependency {} - -internal class DecoratedScopeRootDependency : IDecoratedScopeRootDependency, IScopedInstance { } - -internal class DecoratorScopeRootBasis : IDecoratedScopeRoot, IScopeRoot, IScopedInstance -{ - public IDecoratedScopeRootDependency Dependency { get; } - - public IDecoratedScopeRoot Decorated => this; - - public DecoratorScopeRootBasis( - IDecoratedScopeRootDependency dependency) => - Dependency = dependency; -} - -internal class DecoratorScopeRoot : IDecoratedScopeRoot, IDecorator -{ - public DecoratorScopeRoot(IDecoratedScopeRoot decorated, IDecoratedScopeRootDependency dependency) - { - Decorated = decorated; - Dependency = dependency; - } +[assembly:ImplementationAggregation(typeof(DateTime))] +[assembly:ConstructorChoice(typeof(DateTime))] +//[assembly:SpyAggregation(typeof(IPublicTypeReport))] +//[assembly:SpyConstructorChoiceAggregationAttribute( PublicConstructorReport.ClassToo, PublicConstructorReport.Class_Int32)] - public IDecoratedScopeRootDependency Dependency { get; } - public IDecoratedScopeRoot Decorated { get; } -} +namespace MrMeeseeks.DIE.Sample; -internal partial class DecoratorScopeRootContainer : IContainer +internal partial class ConstructorChoiceContainer : IContainer { - } \ No newline at end of file diff --git a/Sample/Program.cs b/Sample/Program.cs index a6025558..f4e80bd9 100644 --- a/Sample/Program.cs +++ b/Sample/Program.cs @@ -1,5 +1,7 @@ -using MrMeeseeks.DIE.Sample; +using System; +using MrMeeseeks.DIE; +using MrMeeseeks.DIE.Sample; -System.Console.WriteLine("Hello, world!"); -using var container = new DecoratorScopeRootContainer(); -System.Console.WriteLine(((MrMeeseeks.DIE.IContainer) container).Resolve()); \ No newline at end of file +Console.WriteLine("Hello, world!"); +var container = new ConstructorChoiceContainer(); +Console.WriteLine(((IContainer) container).Resolve()); \ No newline at end of file diff --git a/SampleChild/Class1.cs b/SampleChild/Class1.cs new file mode 100644 index 00000000..2fdda502 --- /dev/null +++ b/SampleChild/Class1.cs @@ -0,0 +1,30 @@ +namespace MrMeeseeks.DIE.SampleChild; + +public interface IClass {} + +public class Class : IClass +{ + public Class() + { + } + + public Class(int i) + { + + } +} + +public interface IClassToo {} + +public class ClassToo : IClassToo +{ + public ClassToo() + { + + } + + public ClassToo(int i) + { + + } +} \ No newline at end of file diff --git a/SampleChild/SampleChild.csproj b/SampleChild/SampleChild.csproj index 4c2b7f02..13c95705 100644 --- a/SampleChild/SampleChild.csproj +++ b/SampleChild/SampleChild.csproj @@ -1,21 +1,18 @@ - - net5.0 - - MrMeeseeks.DIE.SampleChild - true - $(BaseIntermediateOutputPath)\GeneratedFiles - - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - + + net6.0 + MrMeeseeks.DIE.SampleChild + true + $(BaseIntermediateOutputPath)\GeneratedFiles + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + diff --git a/Spy/Attributes.cs b/Spy/Attributes.cs new file mode 100644 index 00000000..9fe0afa8 --- /dev/null +++ b/Spy/Attributes.cs @@ -0,0 +1,11 @@ +using System; + +namespace MrMeeseeks.DIE.Spy; + +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Assembly | AttributeTargets.Class)] +public class ConstructorChoiceAttribute : Attribute +{ + public ConstructorChoiceAttribute(Type implementationType, params Type[] parameterTypes) + { + } +} diff --git a/Spy/Properties/launchSettings.json b/Spy/Properties/launchSettings.json new file mode 100644 index 00000000..a4807c69 --- /dev/null +++ b/Spy/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "Spy": { + "commandName": "DebugRoslynComponent", + "targetProject": "..\\TestChild\\TestChild.csproj" + } + } +} \ No newline at end of file diff --git a/Spy/RoslynExtensions.cs b/Spy/RoslynExtensions.cs new file mode 100644 index 00000000..342a7c62 --- /dev/null +++ b/Spy/RoslynExtensions.cs @@ -0,0 +1,13 @@ +namespace MrMeeseeks.DIE.Spy; + +public static class RoslynExtensions +{ + // Picked from https://github.com/YairHalberstadt/stronginject Thank you! + public static string FullName(this ITypeSymbol type) => + type.ToDisplayString(new SymbolDisplayFormat( + globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Included, + typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces, + genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters, + parameterOptions: SymbolDisplayParameterOptions.IncludeType | SymbolDisplayParameterOptions.IncludeParamsRefOut, + memberOptions: SymbolDisplayMemberOptions.IncludeRef)); +} \ No newline at end of file diff --git a/Spy/Spy.csproj b/Spy/Spy.csproj index f7f889d5..9f0339b0 100644 --- a/Spy/Spy.csproj +++ b/Spy/Spy.csproj @@ -35,9 +35,5 @@ - - - - diff --git a/Spy/TypeReportGenerator.cs b/Spy/TypeReportGenerator.cs index 4bbe9df4..a2d62327 100644 --- a/Spy/TypeReportGenerator.cs +++ b/Spy/TypeReportGenerator.cs @@ -83,7 +83,7 @@ static StringBuilder GenerateBody(Accessibility accessModifier, IList (t.c, $"{t.Item2}_{i}"))) .Select(t => @$" [global::{typeof(EnumMemberAttribute).FullName}({nameof(EnumMemberAttribute.Value)} = ""{t.c.ToDisplayString()}"")] -[global::{typeof(ConstructorReferenceAttribute).FullName}(typeof({t.c.ContainingType.FullName()}){(t.c.Parameters.Any() ? $", {string.Join(", ", t.c.Parameters.Select(p => $"typeof({p.Type.FullName()})"))}" : "")})] +[global::{typeof(ConstructorChoiceAttribute).FullName}(typeof({t.c.ContainingType.FullName()}){(t.c.Parameters.Any() ? $", {string.Join(", ", t.c.Parameters.Select(p => $"typeof({p.Type.FullName()})"))}" : "")})] {t.Item2},") .Aggregate( generatedContainer, diff --git a/Test/AssemblyInfo.cs b/Test/AssemblyInfo.cs index f29596ae..654e5670 100644 --- a/Test/AssemblyInfo.cs +++ b/Test/AssemblyInfo.cs @@ -1,5 +1,6 @@ +using System; using MrMeeseeks.DIE; -using MrMeeseeks.DIE.Sample; +using MrMeeseeks.DIE.Test; [assembly:SingleInstanceAggregation(typeof(ISingleInstance))] [assembly:ScopedInstanceAggregation(typeof(IScopedInstance))] @@ -8,7 +9,7 @@ [assembly:DecoratorAggregation(typeof(IDecorator<>))] [assembly:CompositeAggregation(typeof(IComposite<>))] -namespace MrMeeseeks.DIE.Sample; +namespace MrMeeseeks.DIE.Test; public class AssemblyInfo { diff --git a/Test/CompositeTests.cs b/Test/CompositeTests.cs index 33a4b810..a050aa7a 100644 --- a/Test/CompositeTests.cs +++ b/Test/CompositeTests.cs @@ -1,12 +1,12 @@ using System.Collections.Generic; using MrMeeseeks.DIE; -using MrMeeseeks.DIE.Sample; +using MrMeeseeks.DIE.Test; using Xunit; [assembly:DecoratorSequenceChoice(typeof(ICompositeDecorated), typeof(CompositeDecoratedDecoratorA), typeof(CompositeDecoratedDecoratorB))] [assembly:DecoratorSequenceChoice(typeof(CompositeDecorated), typeof(CompositeDecoratedDecoratorB))] -namespace MrMeeseeks.DIE.Sample; +namespace MrMeeseeks.DIE.Test; internal interface ICompositeNormal { diff --git a/Test/ConstructorChoiceTests.cs b/Test/ConstructorChoiceTests.cs new file mode 100644 index 00000000..29b2b379 --- /dev/null +++ b/Test/ConstructorChoiceTests.cs @@ -0,0 +1,26 @@ +using System; +using MrMeeseeks.DIE; +using TestChild; +using Xunit; + +[assembly:ImplementationAggregation(typeof(DateTime))] +[assembly:ConstructorChoice(typeof(DateTime))] + +namespace MrMeeseeks.DIE.Test; + +internal partial class ConstructorChoiceContainer : IContainer +{ + +} + +public partial class ImplementationAggregationTests +{ + [Fact] + public void ResolveExternalType() + { + new SpyConstructorChoiceAggregationAttribute(PublicConstructorReport.Class); + using var container = new ConstructorChoiceContainer(); + var dateTime = ((IContainer) container).Resolve(); + Assert.Equal(DateTime.MinValue, dateTime); + } +} \ No newline at end of file diff --git a/Test/DecoratorTests.cs b/Test/DecoratorTests.cs index 4e2fc8e3..18a42d87 100644 --- a/Test/DecoratorTests.cs +++ b/Test/DecoratorTests.cs @@ -1,11 +1,11 @@ using System.Collections.Generic; using MrMeeseeks.DIE; -using MrMeeseeks.DIE.Sample; +using MrMeeseeks.DIE.Test; using Xunit; [assembly:DecoratorSequenceChoice(typeof(IDecoratedMulti), typeof(DecoratorMultiA), typeof(DecoratorMultiB))] -namespace MrMeeseeks.DIE.Sample; +namespace MrMeeseeks.DIE.Test; internal interface IDecoratedNormal { diff --git a/Test/ImplementationAggregationTests.cs b/Test/ImplementationAggregationTests.cs index 8ec21850..923a4016 100644 --- a/Test/ImplementationAggregationTests.cs +++ b/Test/ImplementationAggregationTests.cs @@ -5,21 +5,23 @@ [assembly:ImplementationAggregation(typeof(FileInfo))] -namespace MrMeeseeks.DIE.Sample; +namespace MrMeeseeks.DIE.Test; internal partial class ImplementationAggregationContainer : IContainer> { } -public partial class ImplementationAggregationTests +public partial class ConstructorChoiceTests { [Fact] public void ResolveExternalType() { using var container = new ImplementationAggregationContainer(); - var fileInfo = ((IContainer>) container).Resolve()(@"C:\HelloWorld.txt"); + var path = @"C:\HelloWorld.txt"; + var fileInfo = ((IContainer>) container).Resolve()(path); Assert.NotNull(fileInfo); Assert.IsType(fileInfo); + Assert.Equal(path, fileInfo.FullName); } } \ No newline at end of file diff --git a/Test/MarkerInterfaces.cs b/Test/MarkerInterfaces.cs index b7993d38..3f7c670a 100644 --- a/Test/MarkerInterfaces.cs +++ b/Test/MarkerInterfaces.cs @@ -1,4 +1,4 @@ -namespace MrMeeseeks.DIE.Sample; +namespace MrMeeseeks.DIE.Test; public interface ISingleInstance { } public interface IScopedInstance { } diff --git a/Test/Test.csproj b/Test/Test.csproj index cb21ddf4..32a2803e 100644 --- a/Test/Test.csproj +++ b/Test/Test.csproj @@ -3,7 +3,7 @@ net6.0 - MrMeeseeks.DIE.Sample + MrMeeseeks.DIE.Test false true $(BaseIntermediateOutputPath)\GeneratedFiles @@ -28,6 +28,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/TestChild/Class.cs b/TestChild/Class.cs new file mode 100644 index 00000000..a2dd54fc --- /dev/null +++ b/TestChild/Class.cs @@ -0,0 +1,31 @@ +namespace MrMeeseeks.DIE.TestChild; + +public interface IClass {} + +public class Class : IClass +{ + public Class() + { + + } + + public Class(int i) + { + + } +} + +public interface IClassToo {} + +public class ClassToo : IClassToo +{ + public ClassToo() + { + + } + + public ClassToo(int i) + { + + } +} \ No newline at end of file diff --git a/TestChild/TestChild.csproj b/TestChild/TestChild.csproj new file mode 100644 index 00000000..8f16c11c --- /dev/null +++ b/TestChild/TestChild.csproj @@ -0,0 +1,19 @@ + + + + net6.0 + + MrMeeseeks.DIE.TestChild + true + $(BaseIntermediateOutputPath)\GeneratedFiles + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + From d6be0358a1dbf9ab2f9d3e138f88b809a2a06191 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Wed, 8 Dec 2021 11:19:31 +0100 Subject: [PATCH 031/162] Initialized Read Me --- README.md | 84 ++-------------------------------- Test/ConstructorChoiceTests.cs | 2 - 2 files changed, 3 insertions(+), 83 deletions(-) diff --git a/README.md b/README.md index af300e7c..728eeb57 100644 --- a/README.md +++ b/README.md @@ -1,83 +1,5 @@ -# MrMeeseeks.StaticDelegateGenerator +# MrMeeseeks.DIE -This Generator applies the Delegate pattern (similar or synonomous to Proxy, Wrapper, Adapter patterns) to the static elements (properties and methods) of a given type. +DIE is a secret agency organized by a bunch of Mr. Meeseekses. Its goal is to gather the information necessary to resolve dependencies. Therefore, … -The explanations of the whys and hows here won't go much into the details of the basics. It's recommended to have a look into the Dependency Inversion Principle (DIP; it's one of the SOLID principles) & Dependency Injection and Object Oriented Programming (OOP) patterns like Proxy, Wrapper, Adapter and Delegate patterns. The patterns are all similar in the way how they are implemtented. They just differ in use cases. This project chose to go with the term Delegate, because it seemed to be most fitting. - -## Why and which problem does it solve? - -Let's directly start with a bad example: - -```C# -internal class BadExampleUsingStaticDependencyInConstructor -{ - public BadExampleUsingStaticDependencyInConstructor() - { - Console.WriteLine(DateTime.Now); - } -} -``` - -This is a violation of the DIP, because `DateTime.Now` is a dependency on a concrete implementation rather than an abstraction. That is always the case with references to static code. The issue here is that you cannot switch implementations. For example, this would make unit tests which depend on `DateTime.Now` returning a very concrete value impossible. - - -This is just indirectly the problem which `MrMeeseeks.StaticDelegateGenerator` solves. The problem which this project solves directly can be inferred from the solution to the problem of the bad example abover. Meaning the solution being the next problem. Here the solution: - -```C# -internal interface IDateTimeNowStaticDelegate -{ - DateTime Now { get; } -} - -internal class DateTimeNowStaticDelegate : IDateTimeNowStaticDelegate -{ - public DateTime Now => DateTime.Now; -} - -internal class SolvedExampleWithConstructorInjection -{ - public SolvedExampleWithConstructorInjection( - IDateTimeNowStaticDelegate dateTimeNowStaticDelegate) - { - Console.WriteLine(dateTimeNowStaticDelegate.Now); - } -} -``` - -Solution: we delegate to the static code and wrap it into an concrete implementation implementing an interface which finally gets injected by constructor injection (DI). Let's call that the (Static) Delegate pattern. - -DIP is happy, problem solved, right? Not yet. Here comes the human component into play. Maintaining the Delegate pattern for all static references becomes tedious and monotonous fast. Also it bloats the code base (more code, more files) without doing something new (it just delegates to already existing functionality). - -And that is exactly the problem which `MrMeeseeks.StaticDelegateGenerator` is trying to solves. - -## Usage - -First, get the latest release version of the nuget package: - -``` -Install-Package MrMeeseeks.StaticDelegateGenerator -``` - -Then declare which type you want to get a Static Delegate from via the `StaticDelegate`-Attribute. For `DateTime` it would look like: - -```C# -using System; -using MrMeeseeks.StaticDelegateGenerator; - -[assembly: StaticDelegate(typeof(DateTime))] -``` - -The Source Generator will then generate an interface called `IDateTimeStaticDelegate` and a corresponding concrete implementation `DateTimeStaticDelegate` which you can use inplace of `DateTime`: - -```C# -internal class SolvedExampleWithStaticDelegate -{ - public SolvedExampleWithStaticDelegate( - IDateTimeStaticDelegate dateTimeNowStaticDelegate) - { - Console.WriteLine(dateTimeNowStaticDelegate.Now); - } -} -``` - -Of course you would need to setup your DI to inject `DateTimeStaticDelegate` into this constructor parameter. However, this is a topic of its own which won't be covered here. +> The acronym DIE stands for **D**ependency **I**njection DI**E** diff --git a/Test/ConstructorChoiceTests.cs b/Test/ConstructorChoiceTests.cs index 29b2b379..e3e59fc3 100644 --- a/Test/ConstructorChoiceTests.cs +++ b/Test/ConstructorChoiceTests.cs @@ -1,6 +1,5 @@ using System; using MrMeeseeks.DIE; -using TestChild; using Xunit; [assembly:ImplementationAggregation(typeof(DateTime))] @@ -18,7 +17,6 @@ public partial class ImplementationAggregationTests [Fact] public void ResolveExternalType() { - new SpyConstructorChoiceAggregationAttribute(PublicConstructorReport.Class); using var container = new ConstructorChoiceContainer(); var dateTime = ((IContainer) container).Resolve(); Assert.Equal(DateTime.MinValue, dateTime); From 7769b1375eaffd49e3a6741f48a93357e28ebc71 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Thu, 9 Dec 2021 17:48:10 +0100 Subject: [PATCH 032/162] Implemented Instances --- Main/ContainerGenerator.cs | 8 +++- Main/ContainerInfo.cs | 3 ++ .../ContainerResolutionBuilder.cs | 6 ++- .../RangeResolutionBaseBuilder.cs | 10 +++-- .../ScopeResolutionBuilder.cs | 6 ++- Main/ResolutionTreeCreationErrorHarvester.cs | 2 + Main/ResolutionTreeItem.cs | 6 ++- Main/SourceGenerator.cs | 6 ++- Main/UserProvidedScopeElements.cs | 28 +++++++++++++ Test/InstanceTests.cs | 40 +++++++++++++++++++ 10 files changed, 103 insertions(+), 12 deletions(-) create mode 100644 Main/UserProvidedScopeElements.cs create mode 100644 Test/InstanceTests.cs diff --git a/Main/ContainerGenerator.cs b/Main/ContainerGenerator.cs index ebbf468f..d20e61a0 100644 --- a/Main/ContainerGenerator.cs +++ b/Main/ContainerGenerator.cs @@ -176,7 +176,9 @@ StringBuilder GenerateFields( stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); break; case ParameterResolution: - break; + break; // the parameter is the field + case FieldResolution: + break; // the scope already contains the field case CollectionResolution(var reference, var typeFullName, _, var items): stringBuilder = items.OfType().Aggregate(stringBuilder, GenerateFields); stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); @@ -228,7 +230,9 @@ StringBuilder GenerateResolutions( stringBuilder = stringBuilder.AppendLine($"}};"); break; case ParameterResolution: - break; + break; // parameter exists already + case FieldResolution: + break; // field exists already case CollectionResolution(var reference, _, var itemFullName, var items): stringBuilder = items.OfType().Aggregate(stringBuilder, GenerateResolutions); stringBuilder = stringBuilder.AppendLine( diff --git a/Main/ContainerInfo.cs b/Main/ContainerInfo.cs index d5bef098..a436212d 100644 --- a/Main/ContainerInfo.cs +++ b/Main/ContainerInfo.cs @@ -6,6 +6,7 @@ internal interface IContainerInfo string Namespace { get; } string FullName { get; } bool IsValid { get; } + INamedTypeSymbol ContainerType { get; } IReadOnlyList ResolutionRootTypes { get; } } @@ -21,6 +22,7 @@ internal ContainerInfo( Name = containerClass.Name; Namespace = containerClass.ContainingNamespace.FullName(); FullName = containerClass.FullName(); + ContainerType = containerClass; ResolutionRootTypes = containerClass .AllInterfaces @@ -44,5 +46,6 @@ internal ContainerInfo( public string Namespace { get; } public string FullName { get; } public bool IsValid { get; } + public INamedTypeSymbol ContainerType { get; } public IReadOnlyList ResolutionRootTypes { get; } } \ No newline at end of file diff --git a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs index 38eae73e..f06c1b7c 100644 --- a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs @@ -28,14 +28,16 @@ internal ContainerResolutionBuilder( ICheckTypeProperties checkTypeProperties, ICheckDecorators checkDecorators, WellKnownTypes wellKnownTypes, - Func scopeResolutionBuilderFactory) + Func scopeResolutionBuilderFactory, + IUserProvidedScopeElements userProvidedScopeElements) : base( (containerInfo.Name, false), wellKnownTypes, typeToImplementationsMapper, referenceGeneratorFactory, checkTypeProperties, - checkDecorators) + checkDecorators, + userProvidedScopeElements) { _containerInfo = containerInfo; _scopeResolutionBuilder = scopeResolutionBuilderFactory(this); diff --git a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs index a33ce4f5..2b38151f 100644 --- a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs +++ b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs @@ -48,6 +48,7 @@ internal record CompositionInterfaceExtension( protected readonly List<(RangedInstanceFunction, RangedInstanceFunctionOverload)> RangedInstances = new (); protected readonly DisposableCollectionResolution DisposableCollectionResolution; + protected readonly IUserProvidedScopeElements UserProvidedScopeElements; protected readonly DisposalHandling DisposalHandling; protected readonly string Name; @@ -60,12 +61,14 @@ protected RangeResolutionBaseBuilder( ITypeToImplementationsMapper typeToImplementationsMapper, IReferenceGeneratorFactory referenceGeneratorFactory, ICheckTypeProperties checkTypeProperties, - ICheckDecorators checkDecorators) + ICheckDecorators checkDecorators, + IUserProvidedScopeElements userProvidedScopeElements) { WellKnownTypes = wellKnownTypes; TypeToImplementationsMapper = typeToImplementationsMapper; CheckTypeProperties = checkTypeProperties; CheckDecorators = checkDecorators; + UserProvidedScopeElements = userProvidedScopeElements; RootReferenceGenerator = referenceGeneratorFactory.Create(); DisposableCollectionResolution = new DisposableCollectionResolution( @@ -101,9 +104,10 @@ protected Resolvable SwitchType(SwitchTypeParameter parameter) { var (type, currentFuncParameters) = parameter; if (currentFuncParameters.FirstOrDefault(t => SymbolEqualityComparer.Default.Equals(t.Type.OriginalDefinition, type.OriginalDefinition)) is { Type: not null, Resolution: not null } funcParameter) - { return funcParameter.Resolution; - } + + if (UserProvidedScopeElements.GetInstanceFor(type) is { } field) + return new FieldResolution(field.Name, field.Type.FullName()); if (type.OriginalDefinition.Equals(WellKnownTypes.Lazy1, SymbolEqualityComparer.Default) && type is INamedTypeSymbol namedTypeSymbol) diff --git a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs index 55f6ee90..c5cccd91 100644 --- a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs @@ -36,14 +36,16 @@ internal ScopeResolutionBuilder( ITypeToImplementationsMapper typeToImplementationsMapper, IReferenceGeneratorFactory referenceGeneratorFactory, ICheckTypeProperties checkTypeProperties, - ICheckDecorators checkDecorators) + ICheckDecorators checkDecorators, + IUserProvidedScopeElements userProvidedScopeElements) : base( ("DefaultScope", true), wellKnownTypes, typeToImplementationsMapper, referenceGeneratorFactory, checkTypeProperties, - checkDecorators) + checkDecorators, + userProvidedScopeElements) { _containerResolutionBuilder = containerResolutionBuilder; _containerReference = RootReferenceGenerator.Generate("_container"); diff --git a/Main/ResolutionTreeCreationErrorHarvester.cs b/Main/ResolutionTreeCreationErrorHarvester.cs index afe9ba1f..96e028d3 100644 --- a/Main/ResolutionTreeCreationErrorHarvester.cs +++ b/Main/ResolutionTreeCreationErrorHarvester.cs @@ -25,6 +25,8 @@ static void Inner(ResolutionTreeItem item, ICollection errorTreeI break; case ScopeRootResolution: break; + case FieldResolution: + break; case RangeResolution containerResolution: foreach (var overload in containerResolution.RangedInstances.SelectMany(ri => ri.Overloads)) Inner(overload.Dependency, errorTreeItems); diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index 94fc5fd7..3c9732d5 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -112,4 +112,8 @@ internal record DisposalHandling( string DisposedFieldReference, string DisposedLocalReference, string DisposedPropertyReference, - string DisposableLocalReference); \ No newline at end of file + string DisposableLocalReference); + +internal record FieldResolution( + string FieldReferenceName, + string TypeFullName) : Resolvable($"this.{FieldReferenceName}", TypeFullName); \ No newline at end of file diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index 217b6263..b8ecbdde 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -44,14 +44,16 @@ public void Execute(GeneratorExecutionContext context) checkTypeProperties, checkDecorators, wellKnownTypes, - ScopeResolutionBuilderFactory); + ScopeResolutionBuilderFactory, + new UserProvidedScopeElements(ci.ContainerType)); IScopeResolutionBuilder ScopeResolutionBuilderFactory(IContainerResolutionBuilder containerBuilder) => new ScopeResolutionBuilder( containerBuilder, wellKnownTypes, typeToImplementationMapper, referenceGeneratorFactory, checkTypeProperties, - checkDecorators); + checkDecorators, + new EmptyUserProvidedScopeElements()); // todo Replace EmptyUserProvidedScopeElements with one for the scope specifically IContainerInfo ContainerInfoFactory(INamedTypeSymbol type) => new ContainerInfo(type, wellKnownTypes); IReferenceGenerator ReferenceGeneratorFactory(int j) => new ReferenceGenerator(j); } diff --git a/Main/UserProvidedScopeElements.cs b/Main/UserProvidedScopeElements.cs new file mode 100644 index 00000000..57eb7635 --- /dev/null +++ b/Main/UserProvidedScopeElements.cs @@ -0,0 +1,28 @@ +namespace MrMeeseeks.DIE; + +internal interface IUserProvidedScopeElements +{ + IFieldSymbol? GetInstanceFor(ITypeSymbol typeSymbol); +} + +internal class EmptyUserProvidedScopeElements : IUserProvidedScopeElements +{ + public IFieldSymbol? GetInstanceFor(ITypeSymbol typeSymbol) => null; +} + +internal class UserProvidedScopeElements : IUserProvidedScopeElements +{ + private readonly IReadOnlyDictionary _typeToField; + + public UserProvidedScopeElements(INamedTypeSymbol scopeType) + { + _typeToField = scopeType.GetMembers() + .Where(s => s.Name.StartsWith("DIE_")) + .Where(s => s is IFieldSymbol fieldSymbol && (fieldSymbol.IsConst || fieldSymbol.IsReadOnly)) + .OfType() + .ToDictionary(fs => fs.Type, fs => fs, SymbolEqualityComparer.IncludeNullability); + } + + public IFieldSymbol? GetInstanceFor(ITypeSymbol typeSymbol) => + _typeToField.TryGetValue(typeSymbol, out var ret) ? ret : null; +} \ No newline at end of file diff --git a/Test/InstanceTests.cs b/Test/InstanceTests.cs new file mode 100644 index 00000000..ef010e83 --- /dev/null +++ b/Test/InstanceTests.cs @@ -0,0 +1,40 @@ +using Xunit; + +namespace MrMeeseeks.DIE.Test; + +internal interface IInstanceClass +{ + string Dependency { get; } +} + +internal class InstanceClass : IInstanceClass +{ + public string Dependency { get; } + + public InstanceClass(string dependency) + { + Dependency = dependency; + } +} + +internal partial class InstanceContainer : IContainer +{ + private readonly string DIE_Dependency; + + public InstanceContainer(string dieDependency) + { + DIE_Dependency = dieDependency; + } +} + +public partial class InstanceTests +{ + [Fact] + public void ResolveExternalType() + { + var check = "Hello, instance!"; + using var container = new InstanceContainer(check); + var instanceClass = ((IContainer) container).Resolve(); + Assert.Equal(check, instanceClass.Dependency); + } +} \ No newline at end of file From 10a0dd80dde9d28f28db805be090cd56bc06a6b4 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Thu, 9 Dec 2021 22:01:05 +0100 Subject: [PATCH 033/162] Implemented Properties --- .../RangeResolutionBaseBuilder.cs | 3 ++ Main/UserProvidedScopeElements.cs | 16 +++++++- Test/InstanceTests.cs | 5 +-- Test/PropertyTests.cs | 37 +++++++++++++++++++ 4 files changed, 56 insertions(+), 5 deletions(-) create mode 100644 Test/PropertyTests.cs diff --git a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs index 2b38151f..d6e55803 100644 --- a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs +++ b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs @@ -108,6 +108,9 @@ protected Resolvable SwitchType(SwitchTypeParameter parameter) if (UserProvidedScopeElements.GetInstanceFor(type) is { } field) return new FieldResolution(field.Name, field.Type.FullName()); + + if (UserProvidedScopeElements.GetPropertyFor(type) is { } property) + return new FieldResolution(property.Name, property.Type.FullName()); if (type.OriginalDefinition.Equals(WellKnownTypes.Lazy1, SymbolEqualityComparer.Default) && type is INamedTypeSymbol namedTypeSymbol) diff --git a/Main/UserProvidedScopeElements.cs b/Main/UserProvidedScopeElements.cs index 57eb7635..f5e7aa23 100644 --- a/Main/UserProvidedScopeElements.cs +++ b/Main/UserProvidedScopeElements.cs @@ -3,26 +3,40 @@ namespace MrMeeseeks.DIE; internal interface IUserProvidedScopeElements { IFieldSymbol? GetInstanceFor(ITypeSymbol typeSymbol); + IPropertySymbol? GetPropertyFor(ITypeSymbol typeSymbol); } internal class EmptyUserProvidedScopeElements : IUserProvidedScopeElements { public IFieldSymbol? GetInstanceFor(ITypeSymbol typeSymbol) => null; + public IPropertySymbol? GetPropertyFor(ITypeSymbol typeSymbol) => null; } internal class UserProvidedScopeElements : IUserProvidedScopeElements { private readonly IReadOnlyDictionary _typeToField; + private readonly IReadOnlyDictionary _typeToProperty; public UserProvidedScopeElements(INamedTypeSymbol scopeType) { - _typeToField = scopeType.GetMembers() + var dieMembers = scopeType.GetMembers() .Where(s => s.Name.StartsWith("DIE_")) + .ToList(); + + _typeToField = dieMembers .Where(s => s is IFieldSymbol fieldSymbol && (fieldSymbol.IsConst || fieldSymbol.IsReadOnly)) .OfType() .ToDictionary(fs => fs.Type, fs => fs, SymbolEqualityComparer.IncludeNullability); + + _typeToProperty = dieMembers + .Where(s => s is IPropertySymbol { GetMethod: { } }) + .OfType() + .ToDictionary(ps => ps.Type, ps => ps, SymbolEqualityComparer.IncludeNullability); } public IFieldSymbol? GetInstanceFor(ITypeSymbol typeSymbol) => _typeToField.TryGetValue(typeSymbol, out var ret) ? ret : null; + + public IPropertySymbol? GetPropertyFor(ITypeSymbol typeSymbol) => + _typeToProperty.TryGetValue(typeSymbol, out var ret) ? ret : null; } \ No newline at end of file diff --git a/Test/InstanceTests.cs b/Test/InstanceTests.cs index ef010e83..1a61b132 100644 --- a/Test/InstanceTests.cs +++ b/Test/InstanceTests.cs @@ -21,10 +21,7 @@ internal partial class InstanceContainer : IContainer { private readonly string DIE_Dependency; - public InstanceContainer(string dieDependency) - { - DIE_Dependency = dieDependency; - } + public InstanceContainer(string dieDependency) => DIE_Dependency = dieDependency; } public partial class InstanceTests diff --git a/Test/PropertyTests.cs b/Test/PropertyTests.cs new file mode 100644 index 00000000..3e9672bf --- /dev/null +++ b/Test/PropertyTests.cs @@ -0,0 +1,37 @@ +using Xunit; + +namespace MrMeeseeks.DIE.Test; + +internal interface IPropertyClass +{ + string Dependency { get; } +} + +internal class PropertyClass : IPropertyClass +{ + public string Dependency { get; } + + public PropertyClass(string dependency) + { + Dependency = dependency; + } +} + +internal partial class PropertyContainer : IContainer +{ + private string DIE_Dependency { get; } + + public PropertyContainer(string dieDependency) => DIE_Dependency = dieDependency; +} + +public partial class PropertyTests +{ + [Fact] + public void ResolveExternalType() + { + var check = "Hello, Property!"; + using var container = new PropertyContainer(check); + var propertyClass = ((IContainer) container).Resolve(); + Assert.Equal(check, propertyClass.Dependency); + } +} \ No newline at end of file From bf87f193f02e95d588537260daa97f1c31cbe143 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Fri, 10 Dec 2021 10:47:38 +0100 Subject: [PATCH 034/162] Generating default scope only if used --- Main/ContainerGenerator.cs | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/Main/ContainerGenerator.cs b/Main/ContainerGenerator.cs index d20e61a0..2edfc6f1 100644 --- a/Main/ContainerGenerator.cs +++ b/Main/ContainerGenerator.cs @@ -42,22 +42,26 @@ public void Generate(IContainerInfo containerInfo, ContainerResolution container generatedContainer, containerResolution); - var defaultScopeResolution = containerResolution.DefaultScope; - generatedContainer = generatedContainer - .AppendLine($"internal partial class {defaultScopeResolution.Name} : {_wellKnownTypes.Disposable.FullName()}") - .AppendLine($"{{") - .AppendLine($"private readonly {containerInfo.FullName} {defaultScopeResolution.ContainerReference};") - .AppendLine($"internal {defaultScopeResolution.Name}({containerInfo.FullName} {defaultScopeResolution.ContainerParameterReference})") - .AppendLine($"{{") - .AppendLine($"{defaultScopeResolution.ContainerReference} = {defaultScopeResolution.ContainerParameterReference};") - .AppendLine($"}}"); + if (containerResolution.DefaultScope.RootResolutions.Any() + || containerResolution.DefaultScope.RangedInstances.Any()) + { + var defaultScopeResolution = containerResolution.DefaultScope; + generatedContainer = generatedContainer + .AppendLine($"internal partial class {defaultScopeResolution.Name} : {_wellKnownTypes.Disposable.FullName()}") + .AppendLine($"{{") + .AppendLine($"private readonly {containerInfo.FullName} {defaultScopeResolution.ContainerReference};") + .AppendLine($"internal {defaultScopeResolution.Name}({containerInfo.FullName} {defaultScopeResolution.ContainerParameterReference})") + .AppendLine($"{{") + .AppendLine($"{defaultScopeResolution.ContainerReference} = {defaultScopeResolution.ContainerParameterReference};") + .AppendLine($"}}"); - generatedContainer = GenerateResolutionRange( - generatedContainer, - defaultScopeResolution); + generatedContainer = GenerateResolutionRange( + generatedContainer, + defaultScopeResolution); - generatedContainer = generatedContainer - .AppendLine($"}}"); + generatedContainer = generatedContainer + .AppendLine($"}}"); + } generatedContainer = generatedContainer .AppendLine($"}}") From 4cebc2899d2f68b9c7fd22b4e3a34038e2649a90 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Fri, 10 Dec 2021 15:12:46 +0100 Subject: [PATCH 035/162] Implemented Factories --- Main/ContainerGenerator.cs | 22 ++++++++++++---- .../RangeResolutionBaseBuilder.cs | 22 +++++++++++++--- Main/ResolutionTreeItem.cs | 13 +++++++--- Main/UserProvidedScopeElements.cs | 11 ++++++++ Test/FactoryTests.cs | 25 +++++++++++++++++++ 5 files changed, 82 insertions(+), 11 deletions(-) create mode 100644 Test/FactoryTests.cs diff --git a/Main/ContainerGenerator.cs b/Main/ContainerGenerator.cs index 2edfc6f1..9a3506a2 100644 --- a/Main/ContainerGenerator.cs +++ b/Main/ContainerGenerator.cs @@ -181,8 +181,14 @@ StringBuilder GenerateFields( break; case ParameterResolution: break; // the parameter is the field - case FieldResolution: - break; // the scope already contains the field + case FieldResolution(var reference, var typeFullName, _): + stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); + break; + case FactoryResolution(var reference, var typeFullName, _, var parameters): + stringBuilder = parameters.Aggregate(stringBuilder, + (builder, tuple) => GenerateFields(builder, tuple.Dependency)); + stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); + break; case CollectionResolution(var reference, var typeFullName, _, var items): stringBuilder = items.OfType().Aggregate(stringBuilder, GenerateFields); stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); @@ -221,7 +227,7 @@ StringBuilder GenerateResolutions( stringBuilder = parameters.Aggregate(stringBuilder, (builder, tuple) => GenerateResolutions(builder, tuple.Dependency ?? throw new Exception())); stringBuilder = stringBuilder.AppendLine( - $"{reference} = new {typeFullName}({string.Join(", ", parameters.Select(d => $"{d.name}: {d.Dependency?.Reference}"))});"); + $"{reference} = new {typeFullName}({string.Join(", ", parameters.Select(d => $"{d.Name}: {d.Dependency?.Reference}"))});"); if (disposableCollectionResolution is {}) stringBuilder = stringBuilder.AppendLine( $"{disposableCollectionResolution.Reference}.Add(({_wellKnownTypes.Disposable.FullName()}) {reference});"); @@ -235,8 +241,14 @@ StringBuilder GenerateResolutions( break; case ParameterResolution: break; // parameter exists already - case FieldResolution: - break; // field exists already + case FieldResolution(var reference, _, var fieldName): + stringBuilder = stringBuilder.AppendLine($"{reference} = this.{fieldName};"); + break; + case FactoryResolution(var reference, _, var functionName, var parameters): + stringBuilder = parameters.Aggregate(stringBuilder, + (builder, tuple) => GenerateResolutions(builder, tuple.Dependency ?? throw new Exception())); + stringBuilder = stringBuilder.AppendLine($"{reference} = this.{functionName}({string.Join(", ", parameters.Select(t => $"{t.Name}: {t.Dependency.Reference}"))});"); + break; case CollectionResolution(var reference, _, var itemFullName, var items): stringBuilder = items.OfType().Aggregate(stringBuilder, GenerateResolutions); stringBuilder = stringBuilder.AppendLine( diff --git a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs index d6e55803..7efeca4e 100644 --- a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs +++ b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs @@ -106,11 +106,27 @@ protected Resolvable SwitchType(SwitchTypeParameter parameter) if (currentFuncParameters.FirstOrDefault(t => SymbolEqualityComparer.Default.Equals(t.Type.OriginalDefinition, type.OriginalDefinition)) is { Type: not null, Resolution: not null } funcParameter) return funcParameter.Resolution; - if (UserProvidedScopeElements.GetInstanceFor(type) is { } field) - return new FieldResolution(field.Name, field.Type.FullName()); + if (UserProvidedScopeElements.GetInstanceFor(type) is { } instance) + return new FieldResolution( + RootReferenceGenerator.Generate(instance.Type), + instance.Type.FullName(), + instance.Name); if (UserProvidedScopeElements.GetPropertyFor(type) is { } property) - return new FieldResolution(property.Name, property.Type.FullName()); + return new FieldResolution( + RootReferenceGenerator.Generate(property.Type), + property.Type.FullName(), + property.Name); + + if (UserProvidedScopeElements.GetFactoryFor(type) is { } factory) + return new FactoryResolution( + RootReferenceGenerator.Generate(factory.ReturnType), + factory.ReturnType.FullName(), + factory.Name, + factory + .Parameters + .Select(p => (p.Name, SwitchType(new SwitchTypeParameter(p.Type, currentFuncParameters)))) + .ToList()); if (type.OriginalDefinition.Equals(WellKnownTypes.Lazy1, SymbolEqualityComparer.Default) && type is INamedTypeSymbol namedTypeSymbol) diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index 3c9732d5..ed4388c3 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -28,7 +28,7 @@ internal record ConstructorResolution( string Reference, string TypeFullName, DisposableCollectionResolution? DisposableCollectionResolution, - IReadOnlyList<(string name, Resolvable Dependency)> Parameter) : Resolvable(Reference, TypeFullName); + IReadOnlyList<(string Name, Resolvable Dependency)> Parameter) : Resolvable(Reference, TypeFullName); internal record ScopeRootResolution( string Reference, @@ -75,6 +75,12 @@ internal record FuncResolution( IReadOnlyList Parameter, ResolutionTreeItem Dependency) : Resolvable(Reference, TypeFullName); +internal record FactoryResolution( + string Reference, + string TypeFullName, + string FunctionName, + IReadOnlyList<(string Name, Resolvable Dependency)> Parameter) : Resolvable(Reference, TypeFullName); + internal record CollectionResolution( string Reference, string TypeFullName, @@ -115,5 +121,6 @@ internal record DisposalHandling( string DisposableLocalReference); internal record FieldResolution( - string FieldReferenceName, - string TypeFullName) : Resolvable($"this.{FieldReferenceName}", TypeFullName); \ No newline at end of file + string Reference, + string TypeFullName, + string FieldName) : Resolvable(Reference, TypeFullName); \ No newline at end of file diff --git a/Main/UserProvidedScopeElements.cs b/Main/UserProvidedScopeElements.cs index f5e7aa23..cc908004 100644 --- a/Main/UserProvidedScopeElements.cs +++ b/Main/UserProvidedScopeElements.cs @@ -4,18 +4,21 @@ internal interface IUserProvidedScopeElements { IFieldSymbol? GetInstanceFor(ITypeSymbol typeSymbol); IPropertySymbol? GetPropertyFor(ITypeSymbol typeSymbol); + IMethodSymbol? GetFactoryFor(ITypeSymbol typeSymbol); } internal class EmptyUserProvidedScopeElements : IUserProvidedScopeElements { public IFieldSymbol? GetInstanceFor(ITypeSymbol typeSymbol) => null; public IPropertySymbol? GetPropertyFor(ITypeSymbol typeSymbol) => null; + public IMethodSymbol? GetFactoryFor(ITypeSymbol typeSymbol) => null; } internal class UserProvidedScopeElements : IUserProvidedScopeElements { private readonly IReadOnlyDictionary _typeToField; private readonly IReadOnlyDictionary _typeToProperty; + private readonly IReadOnlyDictionary _typeToMethod; public UserProvidedScopeElements(INamedTypeSymbol scopeType) { @@ -32,6 +35,11 @@ public UserProvidedScopeElements(INamedTypeSymbol scopeType) .Where(s => s is IPropertySymbol { GetMethod: { } }) .OfType() .ToDictionary(ps => ps.Type, ps => ps, SymbolEqualityComparer.IncludeNullability); + + _typeToMethod = dieMembers + .Where(s => s is IMethodSymbol { ReturnsVoid: false, Arity: 0, IsConditional: false, MethodKind: MethodKind.Ordinary }) + .OfType() + .ToDictionary(ps => ps.ReturnType, ps => ps, SymbolEqualityComparer.IncludeNullability); } public IFieldSymbol? GetInstanceFor(ITypeSymbol typeSymbol) => @@ -39,4 +47,7 @@ public UserProvidedScopeElements(INamedTypeSymbol scopeType) public IPropertySymbol? GetPropertyFor(ITypeSymbol typeSymbol) => _typeToProperty.TryGetValue(typeSymbol, out var ret) ? ret : null; + + public IMethodSymbol? GetFactoryFor(ITypeSymbol typeSymbol) => + _typeToMethod.TryGetValue(typeSymbol, out var ret) ? ret : null; } \ No newline at end of file diff --git a/Test/FactoryTests.cs b/Test/FactoryTests.cs new file mode 100644 index 00000000..d9ab9585 --- /dev/null +++ b/Test/FactoryTests.cs @@ -0,0 +1,25 @@ +using System.IO; +using Xunit; + +namespace MrMeeseeks.DIE.Test; + +internal partial class FactoryContainer : IContainer +{ + private string DIE_Path { get; } + + private FileInfo DIE_FileInfo(string path) => new (path); + + public FactoryContainer(string diePath) => DIE_Path = diePath; +} + +public partial class FactoryTests +{ + [Fact] + public void ResolveExternalType() + { + var check = @"C:\HelloWorld.txt"; + using var container = new FactoryContainer(check); + var fileInfo = ((IContainer) container).Resolve(); + Assert.Equal(check, fileInfo.FullName); + } +} \ No newline at end of file From 48f5c6c1f2a143a91c4c67fc77830efd2ff26dca Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Fri, 10 Dec 2021 16:06:22 +0100 Subject: [PATCH 036/162] Implemented init-property initializations --- Main/ContainerGenerator.cs | 19 +++-- .../RangeResolutionBaseBuilder.cs | 75 +++++++++++-------- Main/ResolutionTreeItem.cs | 11 ++- Test/ConstructorTests.cs | 33 ++++++++ Test/Test.csproj | 4 + 5 files changed, 102 insertions(+), 40 deletions(-) create mode 100644 Test/ConstructorTests.cs diff --git a/Main/ContainerGenerator.cs b/Main/ContainerGenerator.cs index 9a3506a2..835596da 100644 --- a/Main/ContainerGenerator.cs +++ b/Main/ContainerGenerator.cs @@ -171,9 +171,11 @@ StringBuilder GenerateFields( stringBuilder = GenerateFields(stringBuilder, resolutionBase); stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); break; - case ConstructorResolution(var reference, var typeFullName, _, var parameters): + case ConstructorResolution(var reference, var typeFullName, _, var parameters, var initializedProperties): stringBuilder = parameters.Aggregate(stringBuilder, (builder, tuple) => GenerateFields(builder, tuple.Dependency)); + stringBuilder = initializedProperties.Aggregate(stringBuilder, + (builder, tuple) => GenerateFields(builder, tuple.Dependency)); stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); break; case FuncResolution(var reference, var typeFullName, _, _): @@ -209,7 +211,7 @@ StringBuilder GenerateResolutions( { switch (resolution) { - case ScopeRootResolution(var reference, var typeFullName, var scopeReference, var scopeTypeFullName, var singleInstanceScopeReference, var parameter, var (disposableCollectionReference, _, _, _), var (createFunctionReference, _)): + case ScopeRootResolution(var reference, var typeFullName, var scopeReference, var scopeTypeFullName, var singleInstanceScopeReference, var parameter, var (disposableCollectionReference, _, _, _, _), var (createFunctionReference, _)): stringBuilder = stringBuilder .AppendLine($"{scopeReference} = new {scopeTypeFullName}({singleInstanceScopeReference});") .AppendLine($"{disposableCollectionReference}.Add(({_wellKnownTypes.Disposable.FullName()}) {scopeReference});") @@ -223,11 +225,18 @@ StringBuilder GenerateResolutions( stringBuilder = stringBuilder.AppendLine( $"{reference} = ({typeFullName}) {resolutionBase.Reference};"); break; - case ConstructorResolution(var reference, var typeFullName, var disposableCollectionResolution, var parameters): + case ConstructorResolution(var reference, var typeFullName, var disposableCollectionResolution, var parameters, var initializedProperties): stringBuilder = parameters.Aggregate(stringBuilder, - (builder, tuple) => GenerateResolutions(builder, tuple.Dependency ?? throw new Exception())); + (builder, tuple) => GenerateResolutions(builder, tuple.Dependency)); + stringBuilder = initializedProperties.Aggregate(stringBuilder, + (builder, tuple) => GenerateResolutions(builder, tuple.Dependency)); + var constructorParameter = + string.Join(", ", parameters.Select(d => $"{d.Name}: {d.Dependency.Reference}")); + var objectInitializerParameter = initializedProperties.Any() + ? $" {{ {string.Join(", ", initializedProperties.Select(p => $"{p.Name} = {p.Dependency.Reference}"))} }}" + : ""; stringBuilder = stringBuilder.AppendLine( - $"{reference} = new {typeFullName}({string.Join(", ", parameters.Select(d => $"{d.Name}: {d.Dependency?.Reference}"))});"); + $"{reference} = new {typeFullName}({constructorParameter}){objectInitializerParameter};"); if (disposableCollectionResolution is {}) stringBuilder = stringBuilder.AppendLine( $"{disposableCollectionResolution.Reference}.Add(({_wellKnownTypes.Disposable.FullName()}) {reference});"); diff --git a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs index 7efeca4e..fb81f49d 100644 --- a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs +++ b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs @@ -159,7 +159,8 @@ protected Resolvable SwitchType(SwitchTypeParameter parameter) Array.Empty(), dependency) ) - })); + }), + Array.Empty<(string Name, Resolvable Dependency)>()); } if (type.OriginalDefinition.Equals(WellKnownTypes.Enumerable1, SymbolEqualityComparer.Default) @@ -554,39 +555,47 @@ protected Resolvable CreateConstructorResolution(ForConstructorParameter paramet CheckTypeProperties), new ReadOnlyCollection<(string Name, Resolvable Dependency)>(constructor .Parameters - .Select(p => - { - if (checkForDecoration && p.Type.Equals(decoration?.InterfaceType, SymbolEqualityComparer.Default)) - { - return (p.Name, decoration.CurrentInterfaceResolution); - } - if (checkForComposition - && composition is {} - && (p.Type.Equals(WellKnownTypes.Enumerable1.Construct(composition.InterfaceType), SymbolEqualityComparer.Default) - || p.Type.Equals(WellKnownTypes.ReadOnlyCollection1.Construct(composition.InterfaceType), SymbolEqualityComparer.Default) - || p.Type.Equals(WellKnownTypes.ReadOnlyList1.Construct(composition.InterfaceType), SymbolEqualityComparer.Default))) - { - - return (p.Name, new CollectionResolution( - RootReferenceGenerator.Generate(p.Type), - p.Type.FullName(), - composition.InterfaceType.FullName(), - composition.InterfaceResolutionComposition)); - } - if (p.Type is not INamedTypeSymbol parameterType) - { - return ("", - new ErrorTreeItem( - $"[{implementationType.FullName()}] Class.Constructor.Parameter: Parameter type {p.Type.FullName()} is not a named type symbol")); - } - - return ( - p.Name, - SwitchType(new SwitchTypeParameter( - parameterType, - currentParameters))); - }) + .Select(p => ProcessChildType(p.Type, p.Name, implementationType, currentParameters)) + .ToList()), + new ReadOnlyCollection<(string Name, Resolvable Dependency)>(implementationType + .GetMembers() + .OfType() + .Where(p => p.SetMethod?.IsInitOnly ?? false) + .Select(p => ProcessChildType(p.Type, p.Name, implementationType, currentParameters)) .ToList())); + + (string Name, Resolvable Dependency) ProcessChildType(ITypeSymbol typeSymbol, string parameterName, INamedTypeSymbol impType, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currParameter) + { + if (checkForDecoration && typeSymbol.Equals(decoration?.InterfaceType, SymbolEqualityComparer.Default)) + { + return (parameterName, decoration.CurrentInterfaceResolution); + } + if (checkForComposition + && composition is {} + && (typeSymbol.Equals(WellKnownTypes.Enumerable1.Construct(composition.InterfaceType), SymbolEqualityComparer.Default) + || typeSymbol.Equals(WellKnownTypes.ReadOnlyCollection1.Construct(composition.InterfaceType), SymbolEqualityComparer.Default) + || typeSymbol.Equals(WellKnownTypes.ReadOnlyList1.Construct(composition.InterfaceType), SymbolEqualityComparer.Default))) + { + + return (parameterName, new CollectionResolution( + RootReferenceGenerator.Generate(typeSymbol), + typeSymbol.FullName(), + composition.InterfaceType.FullName(), + composition.InterfaceResolutionComposition)); + } + if (typeSymbol is not INamedTypeSymbol parameterType) + { + return ("", + new ErrorTreeItem( + $"[{impType.FullName()}] Class.Constructor.Parameter: Parameter type {typeSymbol.FullName()} is not a named type symbol")); + } + + return ( + parameterName, + SwitchType(new SwitchTypeParameter( + parameterType, + currParameter))); + } } diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index ed4388c3..1cb7dcc2 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -28,7 +28,8 @@ internal record ConstructorResolution( string Reference, string TypeFullName, DisposableCollectionResolution? DisposableCollectionResolution, - IReadOnlyList<(string Name, Resolvable Dependency)> Parameter) : Resolvable(Reference, TypeFullName); + IReadOnlyList<(string Name, Resolvable Dependency)> Parameter, + IReadOnlyList<(string Name, Resolvable Dependency)> InitializedProperties) : Resolvable(Reference, TypeFullName); internal record ScopeRootResolution( string Reference, @@ -89,7 +90,13 @@ internal record CollectionResolution( internal record DisposableCollectionResolution( string Reference, - string TypeFullName) : ConstructorResolution(Reference, TypeFullName, null, Array.Empty<(string name, Resolvable Dependency)>()); + string TypeFullName) + : ConstructorResolution( + Reference, + TypeFullName, + null, + Array.Empty<(string Name, Resolvable Dependency)>(), + Array.Empty<(string Name, Resolvable Dependency)>()); internal abstract record RangeResolution( IReadOnlyList RootResolutions, diff --git a/Test/ConstructorTests.cs b/Test/ConstructorTests.cs new file mode 100644 index 00000000..1382c4f9 --- /dev/null +++ b/Test/ConstructorTests.cs @@ -0,0 +1,33 @@ +using Xunit; + +namespace MrMeeseeks.DIE.Test; + +internal interface IConstructorInitDependency {} + +internal class ConstructorInitDependency : IConstructorInitDependency {} + +internal interface IConstructorInit +{ + IConstructorInitDependency? Dependency { get; } +} + +internal class ConstructorInit : IConstructorInit +{ + public IConstructorInitDependency? Dependency { get; init; } +} + +internal partial class ConstructorInitContainer : IContainer +{ +} + +public partial class ConstructorsTests +{ + [Fact] + public void ResolveInitProperty() + { + using var container = new ConstructorInitContainer(); + var resolution = ((IContainer) container).Resolve(); + Assert.NotNull(resolution.Dependency); + Assert.IsType(resolution.Dependency); + } +} \ No newline at end of file diff --git a/Test/Test.csproj b/Test/Test.csproj index 32a2803e..930e5eab 100644 --- a/Test/Test.csproj +++ b/Test/Test.csproj @@ -10,6 +10,10 @@ + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + From 7b721a63a04dc08e653b0fd5e7af79e675077d40 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sat, 11 Dec 2021 12:55:27 +0100 Subject: [PATCH 037/162] Implemented ValueTuple --- Main/ContainerGenerator.cs | 8 + Main/ExecuteImpl.cs | 3 +- .../RangeResolutionBaseBuilder.cs | 46 ++++- Main/ResolutionTreeCreationErrorHarvester.cs | 4 + Main/ResolutionTreeItem.cs | 5 + Sample/Container.cs | 5 +- Sample/Context.cs | 41 ++++- Sample/Program.cs | 4 +- Test/ValueTupleTests.cs | 165 ++++++++++++++++++ 9 files changed, 264 insertions(+), 17 deletions(-) create mode 100644 Test/ValueTupleTests.cs diff --git a/Main/ContainerGenerator.cs b/Main/ContainerGenerator.cs index 835596da..7eb3176e 100644 --- a/Main/ContainerGenerator.cs +++ b/Main/ContainerGenerator.cs @@ -178,6 +178,10 @@ StringBuilder GenerateFields( (builder, tuple) => GenerateFields(builder, tuple.Dependency)); stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); break; + case SyntaxValueTupleResolution(var reference, var typeFullName, var items): + stringBuilder = items.Aggregate(stringBuilder, GenerateFields); + stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); + break; case FuncResolution(var reference, var typeFullName, _, _): stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); break; @@ -241,6 +245,10 @@ StringBuilder GenerateResolutions( stringBuilder = stringBuilder.AppendLine( $"{disposableCollectionResolution.Reference}.Add(({_wellKnownTypes.Disposable.FullName()}) {reference});"); break; + case SyntaxValueTupleResolution(var reference, var typeFullName, var items): + stringBuilder = items.Aggregate(stringBuilder, GenerateResolutions); + stringBuilder = stringBuilder.AppendLine($"{reference} = ({string.Join(", ", items.Select(d => d.Reference))});"); + break; case FuncResolution(var reference, _, var parameter, Resolvable resolutionBase): stringBuilder = stringBuilder.AppendLine($"{reference} = ({string.Join(", ", parameter.Select(fpr => fpr.Reference))}) =>"); stringBuilder = stringBuilder.AppendLine($"{{"); diff --git a/Main/ExecuteImpl.cs b/Main/ExecuteImpl.cs index e7a3e96f..2e55f35a 100644 --- a/Main/ExecuteImpl.cs +++ b/Main/ExecuteImpl.cs @@ -52,7 +52,8 @@ public void Execute() .Select(x => semanticModel.GetDeclaredSymbol(x)) .Where(x => x is not null) .OfType() - .Where(x => x.AllInterfaces.Any(x => x.OriginalDefinition.Equals(_wellKnownTypes.Container, SymbolEqualityComparer.Default))); + .Where(x => x.AllInterfaces.Any(x => x.OriginalDefinition.Equals(_wellKnownTypes.Container, SymbolEqualityComparer.Default))) + .ToList(); foreach (var namedTypeSymbol in containerClasses) { try diff --git a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs index fb81f49d..61ffa9f0 100644 --- a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs +++ b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs @@ -128,6 +128,50 @@ protected Resolvable SwitchType(SwitchTypeParameter parameter) .Select(p => (p.Name, SwitchType(new SwitchTypeParameter(p.Type, currentFuncParameters)))) .ToList()); + if (type.FullName().StartsWith("global::System.ValueTuple<") && type is INamedTypeSymbol valueTupleType) + { + return new ConstructorResolution( + RootReferenceGenerator.Generate(valueTupleType), + valueTupleType.FullName(), + ImplementsIDisposable(valueTupleType, WellKnownTypes, DisposableCollectionResolution, CheckTypeProperties), + valueTupleType + .TypeArguments + .Select((t, i) => ($"item{(i + 1)}", SwitchType(new SwitchTypeParameter(t, currentFuncParameters)))) + .ToList(), + Array.Empty<(string Name, Resolvable Dependency)>()); + } + + if (type.FullName().StartsWith("(") && type.FullName().EndsWith(")") && type is INamedTypeSymbol syntaxValueTupleType) + { + var itemTypes = GetTypeArguments(syntaxValueTupleType).ToList(); + + return new SyntaxValueTupleResolution( + RootReferenceGenerator.Generate("syntaxValueTuple"), + syntaxValueTupleType.FullName(), + itemTypes + .Select(t => SwitchType(new SwitchTypeParameter(t, currentFuncParameters))) + .ToList()); + + IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTupleType) + { + foreach (var typeArgument in currentSyntaxValueTupleType.TypeArguments) + { + if (typeArgument.FullName().StartsWith("(") && typeArgument.FullName().EndsWith(")") && + typeArgument is INamedTypeSymbol nextSyntaxValueTupleType) + { + foreach (var typeSymbol in GetTypeArguments(nextSyntaxValueTupleType)) + { + yield return typeSymbol; + } + } + else + { + yield return typeArgument; + } + } + } + } + if (type.OriginalDefinition.Equals(WellKnownTypes.Lazy1, SymbolEqualityComparer.Default) && type is INamedTypeSymbol namedTypeSymbol) { @@ -199,7 +243,7 @@ protected Resolvable SwitchType(SwitchTypeParameter parameter) if (type.TypeKind == TypeKind.Interface) return SwitchInterface(new SwitchInterfaceParameter(type, currentFuncParameters)); - if (type.TypeKind == TypeKind.Class || type.TypeKind == TypeKind.Struct) + if (type.TypeKind is TypeKind.Class or TypeKind.Struct) return SwitchClass(new SwitchClassParameter(type, currentFuncParameters)); if (type.TypeKind == TypeKind.Delegate diff --git a/Main/ResolutionTreeCreationErrorHarvester.cs b/Main/ResolutionTreeCreationErrorHarvester.cs index 96e028d3..066f1c3b 100644 --- a/Main/ResolutionTreeCreationErrorHarvester.cs +++ b/Main/ResolutionTreeCreationErrorHarvester.cs @@ -40,6 +40,10 @@ static void Inner(ResolutionTreeItem item, ICollection errorTreeI foreach (var valueTuple in constructorResolution.Parameter) Inner(valueTuple.Dependency, errorTreeItems); break; + case SyntaxValueTupleResolution syntaxValueTupleResolution: + foreach (var resolvable in syntaxValueTupleResolution.Items) + Inner(resolvable, errorTreeItems); + break; case CollectionResolution collectionResolution: foreach (var resolutionTreeItem in collectionResolution.Parameter) Inner(resolutionTreeItem, errorTreeItems); diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index 1cb7dcc2..a33da169 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -31,6 +31,11 @@ internal record ConstructorResolution( IReadOnlyList<(string Name, Resolvable Dependency)> Parameter, IReadOnlyList<(string Name, Resolvable Dependency)> InitializedProperties) : Resolvable(Reference, TypeFullName); +internal record SyntaxValueTupleResolution( + string Reference, + string TypeFullName, + IReadOnlyList Items) : Resolvable(Reference, TypeFullName); + internal record ScopeRootResolution( string Reference, string TypeFullName, diff --git a/Sample/Container.cs b/Sample/Container.cs index ef5707c2..b7338604 100644 --- a/Sample/Container.cs +++ b/Sample/Container.cs @@ -1,12 +1,9 @@ using MrMeeseeks.DIE; using MrMeeseeks.DIE.Sample; -//[assembly:Spy(typeof(IPublicTypeReport), typeof(IInternalTypeReport))] [assembly:SingleInstanceAggregation(typeof(ISingleInstance))] [assembly:ScopedInstanceAggregation(typeof(IScopedInstance))] [assembly:ScopeRootAggregation(typeof(IScopeRoot))] [assembly:TransientAggregation(typeof(ITransient))] [assembly:DecoratorAggregation(typeof(IDecorator<>))] -[assembly:CompositeAggregation(typeof(IComposite<>))] -//[assembly:DecoratorSequenceChoice(typeof(IDecoratedMulti))] -//[assembly:DecoratorSequenceChoice(typeof(DecoratorMultiBasisB), typeof(DecoratorMultiA), typeof(DecoratorMultiB))] \ No newline at end of file +[assembly:CompositeAggregation(typeof(IComposite<>))] \ No newline at end of file diff --git a/Sample/Context.cs b/Sample/Context.cs index b670a403..9c90c4a7 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -1,14 +1,37 @@ -using System; -using MrMeeseeks.DIE; -//using SampleChild; +namespace MrMeeseeks.DIE.Sample; -[assembly:ImplementationAggregation(typeof(DateTime))] -[assembly:ConstructorChoice(typeof(DateTime))] -//[assembly:SpyAggregation(typeof(IPublicTypeReport))] -//[assembly:SpyConstructorChoiceAggregationAttribute( PublicConstructorReport.ClassToo, PublicConstructorReport.Class_Int32)] +internal interface IValueTupleBase +{ + (int _0, int _1, int _2, int _3, int _4, + int _5, int _6, int _7, int _8, int _9, + int _10, int _11, int _12, int _13, int _14, + int _15, int _16, int _17, int _18, int _19, + int _20, int _21, int _22, int _23, int _24, + int _25) Dependency { get; } +} + +internal class ValueTupleBase : IValueTupleBase +{ + public ValueTupleBase( + (int _0, int _1, int _2, int _3, int _4, + int _5, int _6, int _7, int _8, int _9, + int _10, int _11, int _12, int _13, int _14, + int _15, int _16, int _17, int _18, int _19, + int _20, int _21, int _22, int _23, int _24, + int _25) dependency) => + Dependency = dependency; -namespace MrMeeseeks.DIE.Sample; + public (int _0, int _1, int _2, int _3, int _4, + int _5, int _6, int _7, int _8, int _9, + int _10, int _11, int _12, int _13, int _14, + int _15, int _16, int _17, int _18, int _19, + int _20, int _21, int _22, int _23, int _24, + int _25) Dependency { get; } +} -internal partial class ConstructorChoiceContainer : IContainer +internal partial class ValueTupleContainer : IContainer { + private int _i; + + private int DIE_Counter() => _i++; } \ No newline at end of file diff --git a/Sample/Program.cs b/Sample/Program.cs index f4e80bd9..a91985db 100644 --- a/Sample/Program.cs +++ b/Sample/Program.cs @@ -3,5 +3,5 @@ using MrMeeseeks.DIE.Sample; Console.WriteLine("Hello, world!"); -var container = new ConstructorChoiceContainer(); -Console.WriteLine(((IContainer) container).Resolve()); \ No newline at end of file +var container = new ValueTupleContainer(); +Console.WriteLine(((IContainer) container).Resolve()); \ No newline at end of file diff --git a/Test/ValueTupleTests.cs b/Test/ValueTupleTests.cs new file mode 100644 index 00000000..44a93396 --- /dev/null +++ b/Test/ValueTupleTests.cs @@ -0,0 +1,165 @@ +using System; +using Xunit; + +namespace MrMeeseeks.DIE.Test; + +internal interface IValueTupleBase +{ + (int _0, int _1, int _2, int _3, int _4, + int _5, int _6, int _7, int _8, int _9, + int _10, int _11, int _12, int _13, int _14, + int _15, int _16, int _17, int _18, int _19, + int _20, int _21, int _22, int _23, int _24, + int _25) Dependency { get; } +} + +internal class ValueTupleBase : IValueTupleBase +{ + public ValueTupleBase( + (int _0, int _1, int _2, int _3, int _4, + int _5, int _6, int _7, int _8, int _9, + int _10, int _11, int _12, int _13, int _14, + int _15, int _16, int _17, int _18, int _19, + int _20, int _21, int _22, int _23, int _24, + int _25) dependency) => + Dependency = dependency; + + public (int _0, int _1, int _2, int _3, int _4, + int _5, int _6, int _7, int _8, int _9, + int _10, int _11, int _12, int _13, int _14, + int _15, int _16, int _17, int _18, int _19, + int _20, int _21, int _22, int _23, int _24, + int _25) Dependency { get; } +} + +internal partial class ValueTupleContainer : IContainer +{ + private int _i; + + private int DIE_Counter() => _i++; +} + +public partial class ValueTupleTests +{ + [Fact] + public void ResolveValueTuple() + { + using var container = new ValueTupleContainer(); + var valueTupleBase = ((IContainer) container).Resolve(); + Assert.Equal(25, valueTupleBase.Dependency._25); + } +} + +internal interface INonSyntaxValueTupleBase +{ + ValueTuple>>> + Dependency { get; } +} + +internal class NonSyntaxValueTupleBase : INonSyntaxValueTupleBase +{ + public NonSyntaxValueTupleBase( + ValueTuple>>> + dependency) => + Dependency = dependency; + + public ValueTuple>>> + Dependency { get; } +} + +internal partial class NonSyntaxValueTupleContainer : IContainer +{ + private int _i; + + private int DIE_Counter() => _i++; +} + +public partial class ValueTupleTests +{ + [Fact] + public void ResolveNonSyntaxValueTuple() + { + using var container = new NonSyntaxValueTupleContainer(); + var nonSyntaxValueTupleBase = ((IContainer) container).Resolve(); + Assert.Equal(25, nonSyntaxValueTupleBase.Dependency.Item26); + } +} + +internal interface INonSyntaxSingleItemValueTupleBase +{ + ValueTuple + Dependency { get; } +} + +internal class NonSyntaxSingleItemValueTupleBase : INonSyntaxSingleItemValueTupleBase +{ + public NonSyntaxSingleItemValueTupleBase( + ValueTuple + dependency) => + Dependency = dependency; + + public ValueTuple + Dependency { get; } +} + +internal partial class NonSyntaxSingleItemValueTupleContainer : IContainer +{ + private int _i; + + private int DIE_Counter() => _i++; +} + +public partial class ValueTupleTests +{ + [Fact] + public void ResolveNonSyntaxSingleItemValueTuple() + { + using var container = new NonSyntaxSingleItemValueTupleContainer(); + var NonSyntaxSingleItemValueTupleBase = ((IContainer) container).Resolve(); + Assert.Equal(0, NonSyntaxSingleItemValueTupleBase.Dependency.Item1); + } +} + +internal interface INonSyntaxDoubleItemValueTupleBase +{ + ValueTuple + Dependency { get; } +} + +internal class NonSyntaxDoubleItemValueTupleBase : INonSyntaxDoubleItemValueTupleBase +{ + public NonSyntaxDoubleItemValueTupleBase( + ValueTuple + dependency) => + Dependency = dependency; + + public ValueTuple + Dependency { get; } +} + +internal partial class NonSyntaxDoubleItemValueTupleContainer : IContainer +{ + private int _i; + + private int DIE_Counter() => _i++; +} + +public partial class ValueTupleTests +{ + [Fact] + public void ResolveNonSyntaxDoubleItemValueTuple() + { + using var container = new NonSyntaxDoubleItemValueTupleContainer(); + var NonSyntaxDoubleItemValueTupleBase = ((IContainer) container).Resolve(); + Assert.Equal(1, NonSyntaxDoubleItemValueTupleBase.Dependency.Item2); + } +} \ No newline at end of file From 7bf0026634003e639003f7fe22f7c436907dec45 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Tue, 14 Dec 2021 09:50:01 +0100 Subject: [PATCH 038/162] Reducing disposal code if it is unnecessary --- Main/CodeBuilding/ContainerCodeBuilder.cs | 47 ++++ Main/CodeBuilding/ContainerGenerator.cs | 52 ++++ Main/CodeBuilding/RangeCodeBaseBuilder.cs | 273 ++++++++++++++++++ Main/CodeBuilding/ScopeCodeBuilder.cs | 52 ++++ Main/ContainerGenerator.cs | 321 ---------------------- Main/ExecuteImpl.cs | 1 + Main/SourceGenerator.cs | 21 +- 7 files changed, 444 insertions(+), 323 deletions(-) create mode 100644 Main/CodeBuilding/ContainerCodeBuilder.cs create mode 100644 Main/CodeBuilding/ContainerGenerator.cs create mode 100644 Main/CodeBuilding/RangeCodeBaseBuilder.cs create mode 100644 Main/CodeBuilding/ScopeCodeBuilder.cs delete mode 100644 Main/ContainerGenerator.cs diff --git a/Main/CodeBuilding/ContainerCodeBuilder.cs b/Main/CodeBuilding/ContainerCodeBuilder.cs new file mode 100644 index 00000000..bae097a3 --- /dev/null +++ b/Main/CodeBuilding/ContainerCodeBuilder.cs @@ -0,0 +1,47 @@ +namespace MrMeeseeks.DIE.CodeBuilding; + +internal interface IContainerCodeBuilder : IRangeCodeBaseBuilder +{ + +} + +internal class ContainerCodeBuilder : RangeCodeBaseBuilder, IContainerCodeBuilder +{ + private readonly IContainerInfo _containerInfo; + private readonly ContainerResolution _containerResolution; + private readonly IScopeCodeBuilder _defaultScopeBuilder; + + public override StringBuilder Build(StringBuilder stringBuilder) + { + stringBuilder = stringBuilder + .AppendLine($"namespace {_containerInfo.Namespace}") + .AppendLine($"{{") + .AppendLine($"partial class {_containerInfo.Name} : {WellKnownTypes.Disposable.FullName()}") + .AppendLine($"{{"); + + stringBuilder = GenerateResolutionRange( + stringBuilder, + _containerResolution); + + stringBuilder = _defaultScopeBuilder.Build(stringBuilder); + + return stringBuilder + .AppendLine($"}}") + .AppendLine($"}}"); + } + + public ContainerCodeBuilder( + // parameter + IContainerInfo containerInfo, + ContainerResolution containerResolution, + IScopeCodeBuilder defaultScopeBuilder, + + // dependencies + WellKnownTypes wellKnownTypes) + : base(wellKnownTypes) + { + _containerInfo = containerInfo; + _containerResolution = containerResolution; + _defaultScopeBuilder = defaultScopeBuilder; + } +} \ No newline at end of file diff --git a/Main/CodeBuilding/ContainerGenerator.cs b/Main/CodeBuilding/ContainerGenerator.cs new file mode 100644 index 00000000..e121bc8f --- /dev/null +++ b/Main/CodeBuilding/ContainerGenerator.cs @@ -0,0 +1,52 @@ +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Text; + +namespace MrMeeseeks.DIE.CodeBuilding; + +internal interface IContainerGenerator +{ + void Generate(IContainerInfo containerInfo, ContainerResolution resolvable); +} + +internal class ContainerGenerator : IContainerGenerator +{ + private readonly GeneratorExecutionContext _context; + private readonly IDiagLogger _diagLogger; + private readonly Func _containerCodeBuilderFactory; + private readonly Func _scopeCodeBuilderFactory; + + internal ContainerGenerator( + GeneratorExecutionContext context, + IDiagLogger diagLogger, + Func containerCodeBuilderFactory, + Func scopeCodeBuilderFactory) + { + _context = context; + _diagLogger = diagLogger; + _containerCodeBuilderFactory = containerCodeBuilderFactory; + _scopeCodeBuilderFactory = scopeCodeBuilderFactory; + } + + public void Generate(IContainerInfo containerInfo, ContainerResolution containerResolution) + { + if (!containerInfo.IsValid) + { + _diagLogger.Log($"return generation"); + return; + } + + var containerCodeBuilder = _containerCodeBuilderFactory(containerInfo, containerResolution, + _scopeCodeBuilderFactory(containerInfo, containerResolution.DefaultScope)); + + var generatedContainer = containerCodeBuilder.Build(new StringBuilder()); + + var containerSource = CSharpSyntaxTree + .ParseText(SourceText.From(generatedContainer.ToString(), Encoding.UTF8)) + .GetRoot() + .NormalizeWhitespace() + .SyntaxTree + .GetText(); + + _context.AddSource($"{containerInfo.Namespace}.{containerInfo.Name}.g.cs", containerSource); + } +} \ No newline at end of file diff --git a/Main/CodeBuilding/RangeCodeBaseBuilder.cs b/Main/CodeBuilding/RangeCodeBaseBuilder.cs new file mode 100644 index 00000000..20342e44 --- /dev/null +++ b/Main/CodeBuilding/RangeCodeBaseBuilder.cs @@ -0,0 +1,273 @@ +namespace MrMeeseeks.DIE.CodeBuilding; + +internal interface IRangeCodeBaseBuilder +{ + StringBuilder Build(StringBuilder stringBuilder); +} + +internal abstract class RangeCodeBaseBuilder : IRangeCodeBaseBuilder +{ + protected readonly WellKnownTypes WellKnownTypes; + protected bool IsDisposalHandlingRequired = false; + + internal RangeCodeBaseBuilder( + WellKnownTypes wellKnownTypes) + { + WellKnownTypes = wellKnownTypes; + } + + protected StringBuilder GenerateResolutionRange( + StringBuilder stringBuilder, + RangeResolution rangeResolution) + { + stringBuilder = rangeResolution.RangedInstances.Aggregate(stringBuilder, GenerateRangedInstanceFunction); + + stringBuilder = rangeResolution.RootResolutions.Aggregate(stringBuilder, GenerateResolutionFunction); + + return GenerateContainerDisposalFunction( + stringBuilder, + rangeResolution); + } + + protected StringBuilder GenerateContainerDisposalFunction( + StringBuilder stringBuilder, + RangeResolution rangeResolution) + { + var disposalHandling = rangeResolution.DisposalHandling; + stringBuilder = stringBuilder + .AppendLine($"private {disposalHandling.DisposableCollection.TypeFullName} {disposalHandling.DisposableCollection.Reference} = new {disposalHandling.DisposableCollection.TypeFullName}();") + .AppendLine($"private int {disposalHandling.DisposedFieldReference} = 0;") + .AppendLine($"private bool {disposalHandling.DisposedPropertyReference} => {disposalHandling.DisposedFieldReference} != 0;") + .AppendLine($"public void Dispose()") + .AppendLine($"{{") + .AppendLine($"var {disposalHandling.DisposedLocalReference} = global::System.Threading.Interlocked.Exchange(ref this.{disposalHandling.DisposedFieldReference}, 1);") + .AppendLine($"if ({disposalHandling.DisposedLocalReference} != 0) return;"); + + if (IsDisposalHandlingRequired) + { + stringBuilder = rangeResolution.RangedInstances.Aggregate( + stringBuilder, + (current, singleInstanceResolution) => current.AppendLine($"this.{singleInstanceResolution.Function.LockReference}.Wait();")); + + stringBuilder = stringBuilder + .AppendLine($"try") + .AppendLine($"{{") + .AppendLine($"foreach(var {disposalHandling.DisposableLocalReference} in {disposalHandling.DisposableCollection.Reference})") + .AppendLine($"{{") + .AppendLine($"try") + .AppendLine($"{{") + .AppendLine($"{disposalHandling.DisposableLocalReference}.Dispose();") + .AppendLine($"}}") + .AppendLine($"catch({WellKnownTypes.Exception.FullName()})") + .AppendLine($"{{") + .AppendLine($"// catch and ignore exceptions of individual disposals so the other disposals are triggered") + .AppendLine($"}}") + .AppendLine($"}}") + .AppendLine($"}}") + .AppendLine($"finally") + .AppendLine($"{{"); + + stringBuilder = rangeResolution.RangedInstances.Aggregate( + stringBuilder, + (current, singleInstanceResolution) => current.AppendLine($"this.{singleInstanceResolution.Function.LockReference}.Release();")); + + return stringBuilder + .AppendLine($"}}") + .AppendLine($"}}"); + } + + return stringBuilder + .AppendLine($"}}"); + } + + protected StringBuilder GenerateResolutionFunction( + StringBuilder stringBuilder, + RootResolutionFunction resolution) + { + var parameter = string.Join(",", resolution.Parameter.Select(r => $"{r.TypeFullName} {r.Reference}")); + stringBuilder = stringBuilder + .AppendLine($"{resolution.AccessModifier} {resolution.TypeFullName} {resolution.ExplicitImplementationFullName}{(string.IsNullOrWhiteSpace(resolution.ExplicitImplementationFullName) ? "" : ".")}{resolution.Reference}({parameter})") + .AppendLine($"{{") + .AppendLine($"if (this.{resolution.DisposalHandling.DisposedPropertyReference}) throw new {WellKnownTypes.ObjectDisposedException}(nameof({resolution.RangeName}));"); + + return GenerateResolutionFunctionContent(stringBuilder, resolution.Resolvable) + .AppendLine($"return {resolution.Resolvable.Reference};") + .AppendLine($"}}"); + } + + protected StringBuilder GenerateResolutionFunctionContent( + StringBuilder stringBuilder, + Resolvable resolution) + { + stringBuilder = GenerateFields(stringBuilder, resolution); + return GenerateResolutions(stringBuilder, resolution); + } + + protected StringBuilder GenerateFields( + StringBuilder stringBuilder, + Resolvable resolution) + { + switch (resolution) + { + case ScopeRootResolution(var reference, var typeFullName, var scopeReference, var scopeTypeFullName, _, _, _, _): + stringBuilder = stringBuilder + .AppendLine($"{scopeTypeFullName} {scopeReference};") + .AppendLine($"{typeFullName} {reference};"); + break; + case InterfaceResolution(var reference, var typeFullName, Resolvable resolutionBase): + stringBuilder = GenerateFields(stringBuilder, resolutionBase); + stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); + break; + case ConstructorResolution(var reference, var typeFullName, _, var parameters, var initializedProperties): + stringBuilder = parameters.Aggregate(stringBuilder, + (builder, tuple) => GenerateFields(builder, tuple.Dependency)); + stringBuilder = initializedProperties.Aggregate(stringBuilder, + (builder, tuple) => GenerateFields(builder, tuple.Dependency)); + stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); + break; + case SyntaxValueTupleResolution(var reference, var typeFullName, var items): + stringBuilder = items.Aggregate(stringBuilder, GenerateFields); + stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); + break; + case FuncResolution(var reference, var typeFullName, _, _): + stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); + break; + case ParameterResolution: + break; // the parameter is the field + case FieldResolution(var reference, var typeFullName, _): + stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); + break; + case FactoryResolution(var reference, var typeFullName, _, var parameters): + stringBuilder = parameters.Aggregate(stringBuilder, + (builder, tuple) => GenerateFields(builder, tuple.Dependency)); + stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); + break; + case CollectionResolution(var reference, var typeFullName, _, var items): + stringBuilder = items.OfType().Aggregate(stringBuilder, GenerateFields); + stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); + break; + case var (reference, typeFullName): + stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); + break; + default: + throw new Exception("Unexpected case or not implemented."); + } + + return stringBuilder; + } + + protected StringBuilder GenerateResolutions( + StringBuilder stringBuilder, + Resolvable resolution) + { + switch (resolution) + { + case ScopeRootResolution(var reference, var typeFullName, var scopeReference, var scopeTypeFullName, var singleInstanceScopeReference, var parameter, var (disposableCollectionReference, _, _, _, _), var (createFunctionReference, _)): + stringBuilder = stringBuilder + .AppendLine($"{scopeReference} = new {scopeTypeFullName}({singleInstanceScopeReference});") + .AppendLine($"{disposableCollectionReference}.Add(({WellKnownTypes.Disposable.FullName()}) {scopeReference});") + .AppendLine($"{reference} = ({typeFullName}) {scopeReference}.{createFunctionReference}({string.Join(", ", parameter.Select(p => p.Reference))});"); + IsDisposalHandlingRequired = true; + break; + case RangedInstanceReferenceResolution(var reference, { Reference: {} functionReference}, var parameter, var owningObjectReference): + stringBuilder = stringBuilder.AppendLine($"{reference} = {owningObjectReference}.{functionReference}({string.Join(", ", parameter.Select(p => p.Reference))});"); + break; + case InterfaceResolution(var reference, var typeFullName, Resolvable resolutionBase): + stringBuilder = GenerateResolutions(stringBuilder, resolutionBase); + stringBuilder = stringBuilder.AppendLine( + $"{reference} = ({typeFullName}) {resolutionBase.Reference};"); + break; + case ConstructorResolution(var reference, var typeFullName, var disposableCollectionResolution, var parameters, var initializedProperties): + stringBuilder = parameters.Aggregate(stringBuilder, + (builder, tuple) => GenerateResolutions(builder, tuple.Dependency)); + stringBuilder = initializedProperties.Aggregate(stringBuilder, + (builder, tuple) => GenerateResolutions(builder, tuple.Dependency)); + var constructorParameter = + string.Join(", ", parameters.Select(d => $"{d.Name}: {d.Dependency.Reference}")); + var objectInitializerParameter = initializedProperties.Any() + ? $" {{ {string.Join(", ", initializedProperties.Select(p => $"{p.Name} = {p.Dependency.Reference}"))} }}" + : ""; + stringBuilder = stringBuilder.AppendLine( + $"{reference} = new {typeFullName}({constructorParameter}){objectInitializerParameter};"); + if (disposableCollectionResolution is {}) + { + stringBuilder = stringBuilder.AppendLine( + $"{disposableCollectionResolution.Reference}.Add(({WellKnownTypes.Disposable.FullName()}) {reference});"); + IsDisposalHandlingRequired = true; + } + break; + case SyntaxValueTupleResolution(var reference, var typeFullName, var items): + stringBuilder = items.Aggregate(stringBuilder, GenerateResolutions); + stringBuilder = stringBuilder.AppendLine($"{reference} = ({string.Join(", ", items.Select(d => d.Reference))});"); + break; + case FuncResolution(var reference, _, var parameter, Resolvable resolutionBase): + stringBuilder = stringBuilder.AppendLine($"{reference} = ({string.Join(", ", parameter.Select(fpr => fpr.Reference))}) =>"); + stringBuilder = stringBuilder.AppendLine($"{{"); + GenerateResolutionFunctionContent(stringBuilder, resolutionBase); + stringBuilder = stringBuilder.AppendLine($"return {resolutionBase.Reference};"); + stringBuilder = stringBuilder.AppendLine($"}};"); + break; + case ParameterResolution: + break; // parameter exists already + case FieldResolution(var reference, _, var fieldName): + stringBuilder = stringBuilder.AppendLine($"{reference} = this.{fieldName};"); + break; + case FactoryResolution(var reference, _, var functionName, var parameters): + stringBuilder = parameters.Aggregate(stringBuilder, + (builder, tuple) => GenerateResolutions(builder, tuple.Dependency ?? throw new Exception())); + stringBuilder = stringBuilder.AppendLine($"{reference} = this.{functionName}({string.Join(", ", parameters.Select(t => $"{t.Name}: {t.Dependency.Reference}"))});"); + break; + case CollectionResolution(var reference, _, var itemFullName, var items): + stringBuilder = items.OfType().Aggregate(stringBuilder, GenerateResolutions); + stringBuilder = stringBuilder.AppendLine( + $"{reference} = new {itemFullName}[]{{{string.Join(", ", items.Select(d => $"({itemFullName}) {(d as Resolvable)?.Reference}"))}}};"); + break; + default: + throw new Exception("Unexpected case or not implemented."); + } + + return stringBuilder; + } + + protected StringBuilder GenerateRangedInstanceFunction(StringBuilder stringBuilder, RangedInstance rangedInstance) + { + stringBuilder = stringBuilder + .AppendLine( + $"private {rangedInstance.Function.TypeFullName} {rangedInstance.Function.FieldReference};") + .AppendLine( + $"private {WellKnownTypes.SemaphoreSlim.FullName()} {rangedInstance.Function.LockReference} = new {WellKnownTypes.SemaphoreSlim.FullName()}(1);"); + + foreach (var (resolvable, funcParameterResolutions) in rangedInstance.Overloads) + { + var parameters = string.Join(", ", + funcParameterResolutions.Select(p => $"{p.TypeFullName} {p.Reference}")); + stringBuilder = stringBuilder.AppendLine( + $"public {rangedInstance.Function.TypeFullName} {rangedInstance.Function.Reference}({parameters})") + .AppendLine($"{{") + .AppendLine($"this.{rangedInstance.Function.LockReference}.Wait();") + .AppendLine($"try") + .AppendLine($"{{") + .AppendLine( + $"if (this.{rangedInstance.DisposalHandling.DisposedPropertyReference}) throw new {WellKnownTypes.ObjectDisposedException}(nameof({rangedInstance.DisposalHandling.RangeName}));") + .AppendLine( + $"if (!object.ReferenceEquals({rangedInstance.Function.FieldReference}, null)) return {rangedInstance.Function.FieldReference};"); + + stringBuilder = GenerateResolutionFunctionContent(stringBuilder, resolvable); + + stringBuilder = stringBuilder + .AppendLine( + $"this.{rangedInstance.Function.FieldReference} = {resolvable.Reference};") + .AppendLine($"}}") + .AppendLine($"finally") + .AppendLine($"{{") + .AppendLine($"this.{rangedInstance.Function.LockReference}.Release();") + .AppendLine($"}}") + .AppendLine($"return this.{rangedInstance.Function.FieldReference};") + .AppendLine($"}}"); + } + + return stringBuilder; + } + + public abstract StringBuilder Build(StringBuilder stringBuilder); +} \ No newline at end of file diff --git a/Main/CodeBuilding/ScopeCodeBuilder.cs b/Main/CodeBuilding/ScopeCodeBuilder.cs new file mode 100644 index 00000000..74c6bca5 --- /dev/null +++ b/Main/CodeBuilding/ScopeCodeBuilder.cs @@ -0,0 +1,52 @@ +namespace MrMeeseeks.DIE.CodeBuilding; + +internal interface IScopeCodeBuilder : IRangeCodeBaseBuilder +{ + +} + +internal class ScopeCodeBuilder : RangeCodeBaseBuilder, IScopeCodeBuilder +{ + private readonly IContainerInfo _containerInfo; + private readonly ScopeResolution _scopeResolution; + + public override StringBuilder Build(StringBuilder stringBuilder) + { + if (!_scopeResolution.RootResolutions.Any() && !_scopeResolution.RangedInstances.Any()) + return stringBuilder; + + stringBuilder = stringBuilder + .AppendLine( + $"internal partial class {_scopeResolution.Name} : {WellKnownTypes.Disposable.FullName()}") + .AppendLine($"{{") + .AppendLine($"private readonly {_containerInfo.FullName} {_scopeResolution.ContainerReference};") + .AppendLine( + $"internal {_scopeResolution.Name}({_containerInfo.FullName} {_scopeResolution.ContainerParameterReference})") + .AppendLine($"{{") + .AppendLine( + $"{_scopeResolution.ContainerReference} = {_scopeResolution.ContainerParameterReference};") + .AppendLine($"}}"); + + stringBuilder = GenerateResolutionRange( + stringBuilder, + _scopeResolution); + + stringBuilder = stringBuilder + .AppendLine($"}}"); + + return stringBuilder; + } + + public ScopeCodeBuilder( + // parameter + IContainerInfo containerInfo, + ScopeResolution scopeResolution, + + // dependencies + WellKnownTypes wellKnownTypes) + : base(wellKnownTypes) + { + _containerInfo = containerInfo; + _scopeResolution = scopeResolution; + } +} \ No newline at end of file diff --git a/Main/ContainerGenerator.cs b/Main/ContainerGenerator.cs deleted file mode 100644 index 7eb3176e..00000000 --- a/Main/ContainerGenerator.cs +++ /dev/null @@ -1,321 +0,0 @@ -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.Text; - -namespace MrMeeseeks.DIE; - -internal interface IContainerGenerator -{ - void Generate(IContainerInfo containerInfo, ContainerResolution resolvable); -} - -internal class ContainerGenerator : IContainerGenerator -{ - private readonly GeneratorExecutionContext _context; - private readonly WellKnownTypes _wellKnownTypes; - private readonly IDiagLogger _diagLogger; - - internal ContainerGenerator( - GeneratorExecutionContext context, - WellKnownTypes wellKnownTypes, - IDiagLogger diagLogger) - { - _context = context; - _wellKnownTypes = wellKnownTypes; - _diagLogger = diagLogger; - } - - public void Generate(IContainerInfo containerInfo, ContainerResolution containerResolution) - { - if (!containerInfo.IsValid) - { - _diagLogger.Log($"return generation"); - return; - } - - var generatedContainer = new StringBuilder() - .AppendLine($"namespace {containerInfo.Namespace}") - .AppendLine($"{{") - .AppendLine($"partial class {containerInfo.Name} : {_wellKnownTypes.Disposable.FullName()}") - .AppendLine($"{{"); - - generatedContainer = GenerateResolutionRange( - generatedContainer, - containerResolution); - - if (containerResolution.DefaultScope.RootResolutions.Any() - || containerResolution.DefaultScope.RangedInstances.Any()) - { - var defaultScopeResolution = containerResolution.DefaultScope; - generatedContainer = generatedContainer - .AppendLine($"internal partial class {defaultScopeResolution.Name} : {_wellKnownTypes.Disposable.FullName()}") - .AppendLine($"{{") - .AppendLine($"private readonly {containerInfo.FullName} {defaultScopeResolution.ContainerReference};") - .AppendLine($"internal {defaultScopeResolution.Name}({containerInfo.FullName} {defaultScopeResolution.ContainerParameterReference})") - .AppendLine($"{{") - .AppendLine($"{defaultScopeResolution.ContainerReference} = {defaultScopeResolution.ContainerParameterReference};") - .AppendLine($"}}"); - - generatedContainer = GenerateResolutionRange( - generatedContainer, - defaultScopeResolution); - - generatedContainer = generatedContainer - .AppendLine($"}}"); - } - - generatedContainer = generatedContainer - .AppendLine($"}}") - .AppendLine($"}}"); - - var containerSource = CSharpSyntaxTree - .ParseText(SourceText.From(generatedContainer.ToString(), Encoding.UTF8)) - .GetRoot() - .NormalizeWhitespace() - .SyntaxTree - .GetText(); - _context.AddSource($"{containerInfo.Namespace}.{containerInfo.Name}.g.cs", containerSource); - - StringBuilder GenerateResolutionRange( - StringBuilder stringBuilder, - RangeResolution rangeResolution) - { - stringBuilder = GenerateContainerDisposalFunction( - stringBuilder, - rangeResolution); - - stringBuilder = rangeResolution.RangedInstances.Aggregate(stringBuilder, GenerateRangedInstanceFunction); - - return rangeResolution.RootResolutions.Aggregate(stringBuilder, GenerateResolutionFunction); - } - - StringBuilder GenerateContainerDisposalFunction( - StringBuilder stringBuilder, - RangeResolution rangeResolution) - { - var disposalHandling = rangeResolution.DisposalHandling; - stringBuilder = stringBuilder - .AppendLine($"private {disposalHandling.DisposableCollection.TypeFullName} {disposalHandling.DisposableCollection.Reference} = new {disposalHandling.DisposableCollection.TypeFullName}();") - .AppendLine($"private int {disposalHandling.DisposedFieldReference} = 0;") - .AppendLine($"private bool {disposalHandling.DisposedPropertyReference} => {disposalHandling.DisposedFieldReference} != 0;") - .AppendLine($"public void Dispose()") - .AppendLine($"{{") - .AppendLine($"var {disposalHandling.DisposedLocalReference} = global::System.Threading.Interlocked.Exchange(ref this.{disposalHandling.DisposedFieldReference}, 1);") - .AppendLine($"if ({disposalHandling.DisposedLocalReference} != 0) return;"); - - stringBuilder = rangeResolution.RangedInstances.Aggregate( - stringBuilder, - (current, singleInstanceResolution) => current.AppendLine($"this.{singleInstanceResolution.Function.LockReference}.Wait();")); - - stringBuilder = stringBuilder - .AppendLine($"try") - .AppendLine($"{{") - .AppendLine($"foreach(var {disposalHandling.DisposableLocalReference} in {disposalHandling.DisposableCollection.Reference})") - .AppendLine($"{{") - .AppendLine($"try") - .AppendLine($"{{") - .AppendLine($"{disposalHandling.DisposableLocalReference}.Dispose();") - .AppendLine($"}}") - .AppendLine($"catch({_wellKnownTypes.Exception.FullName()})") - .AppendLine($"{{") - .AppendLine($"// catch and ignore exceptions of individual disposals so the other disposals are triggered") - .AppendLine($"}}") - .AppendLine($"}}") - .AppendLine($"}}") - .AppendLine($"finally") - .AppendLine($"{{"); - - stringBuilder = rangeResolution.RangedInstances.Aggregate( - stringBuilder, - (current, singleInstanceResolution) => current.AppendLine($"this.{singleInstanceResolution.Function.LockReference}.Release();")); - - return stringBuilder - .AppendLine($"}}") - .AppendLine($"}}"); - } - - StringBuilder GenerateResolutionFunction( - StringBuilder stringBuilder, - RootResolutionFunction resolution) - { - var parameter = string.Join(",", resolution.Parameter.Select(r => $"{r.TypeFullName} {r.Reference}")); - stringBuilder = stringBuilder - .AppendLine($"{resolution.AccessModifier} {resolution.TypeFullName} {resolution.ExplicitImplementationFullName}{(string.IsNullOrWhiteSpace(resolution.ExplicitImplementationFullName) ? "" : ".")}{resolution.Reference}({parameter})") - .AppendLine($"{{") - .AppendLine($"if (this.{resolution.DisposalHandling.DisposedPropertyReference}) throw new {_wellKnownTypes.ObjectDisposedException}(nameof({resolution.RangeName}));"); - - return GenerateResolutionFunctionContent(stringBuilder, resolution.Resolvable) - .AppendLine($"return {resolution.Resolvable.Reference};") - .AppendLine($"}}"); - } - - StringBuilder GenerateResolutionFunctionContent( - StringBuilder stringBuilder, - Resolvable resolution) - { - stringBuilder = GenerateFields(stringBuilder, resolution); - return GenerateResolutions(stringBuilder, resolution); - } - - StringBuilder GenerateFields( - StringBuilder stringBuilder, - Resolvable resolution) - { - switch (resolution) - { - case ScopeRootResolution(var reference, var typeFullName, var scopeReference, var scopeTypeFullName, _, _, _, _): - stringBuilder = stringBuilder - .AppendLine($"{scopeTypeFullName} {scopeReference};") - .AppendLine($"{typeFullName} {reference};"); - break; - case InterfaceResolution(var reference, var typeFullName, Resolvable resolutionBase): - stringBuilder = GenerateFields(stringBuilder, resolutionBase); - stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); - break; - case ConstructorResolution(var reference, var typeFullName, _, var parameters, var initializedProperties): - stringBuilder = parameters.Aggregate(stringBuilder, - (builder, tuple) => GenerateFields(builder, tuple.Dependency)); - stringBuilder = initializedProperties.Aggregate(stringBuilder, - (builder, tuple) => GenerateFields(builder, tuple.Dependency)); - stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); - break; - case SyntaxValueTupleResolution(var reference, var typeFullName, var items): - stringBuilder = items.Aggregate(stringBuilder, GenerateFields); - stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); - break; - case FuncResolution(var reference, var typeFullName, _, _): - stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); - break; - case ParameterResolution: - break; // the parameter is the field - case FieldResolution(var reference, var typeFullName, _): - stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); - break; - case FactoryResolution(var reference, var typeFullName, _, var parameters): - stringBuilder = parameters.Aggregate(stringBuilder, - (builder, tuple) => GenerateFields(builder, tuple.Dependency)); - stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); - break; - case CollectionResolution(var reference, var typeFullName, _, var items): - stringBuilder = items.OfType().Aggregate(stringBuilder, GenerateFields); - stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); - break; - case var (reference, typeFullName): - stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); - break; - default: - throw new Exception("Unexpected case or not implemented."); - } - - return stringBuilder; - } - - StringBuilder GenerateResolutions( - StringBuilder stringBuilder, - Resolvable resolution) - { - switch (resolution) - { - case ScopeRootResolution(var reference, var typeFullName, var scopeReference, var scopeTypeFullName, var singleInstanceScopeReference, var parameter, var (disposableCollectionReference, _, _, _, _), var (createFunctionReference, _)): - stringBuilder = stringBuilder - .AppendLine($"{scopeReference} = new {scopeTypeFullName}({singleInstanceScopeReference});") - .AppendLine($"{disposableCollectionReference}.Add(({_wellKnownTypes.Disposable.FullName()}) {scopeReference});") - .AppendLine($"{reference} = ({typeFullName}) {scopeReference}.{createFunctionReference}({string.Join(", ", parameter.Select(p => p.Reference))});"); - break; - case RangedInstanceReferenceResolution(var reference, { Reference: {} functionReference}, var parameter, var owningObjectReference): - stringBuilder = stringBuilder.AppendLine($"{reference} = {owningObjectReference}.{functionReference}({string.Join(", ", parameter.Select(p => p.Reference))});"); - break; - case InterfaceResolution(var reference, var typeFullName, Resolvable resolutionBase): - stringBuilder = GenerateResolutions(stringBuilder, resolutionBase); - stringBuilder = stringBuilder.AppendLine( - $"{reference} = ({typeFullName}) {resolutionBase.Reference};"); - break; - case ConstructorResolution(var reference, var typeFullName, var disposableCollectionResolution, var parameters, var initializedProperties): - stringBuilder = parameters.Aggregate(stringBuilder, - (builder, tuple) => GenerateResolutions(builder, tuple.Dependency)); - stringBuilder = initializedProperties.Aggregate(stringBuilder, - (builder, tuple) => GenerateResolutions(builder, tuple.Dependency)); - var constructorParameter = - string.Join(", ", parameters.Select(d => $"{d.Name}: {d.Dependency.Reference}")); - var objectInitializerParameter = initializedProperties.Any() - ? $" {{ {string.Join(", ", initializedProperties.Select(p => $"{p.Name} = {p.Dependency.Reference}"))} }}" - : ""; - stringBuilder = stringBuilder.AppendLine( - $"{reference} = new {typeFullName}({constructorParameter}){objectInitializerParameter};"); - if (disposableCollectionResolution is {}) - stringBuilder = stringBuilder.AppendLine( - $"{disposableCollectionResolution.Reference}.Add(({_wellKnownTypes.Disposable.FullName()}) {reference});"); - break; - case SyntaxValueTupleResolution(var reference, var typeFullName, var items): - stringBuilder = items.Aggregate(stringBuilder, GenerateResolutions); - stringBuilder = stringBuilder.AppendLine($"{reference} = ({string.Join(", ", items.Select(d => d.Reference))});"); - break; - case FuncResolution(var reference, _, var parameter, Resolvable resolutionBase): - stringBuilder = stringBuilder.AppendLine($"{reference} = ({string.Join(", ", parameter.Select(fpr => fpr.Reference))}) =>"); - stringBuilder = stringBuilder.AppendLine($"{{"); - GenerateResolutionFunctionContent(stringBuilder, resolutionBase); - stringBuilder = stringBuilder.AppendLine($"return {resolutionBase.Reference};"); - stringBuilder = stringBuilder.AppendLine($"}};"); - break; - case ParameterResolution: - break; // parameter exists already - case FieldResolution(var reference, _, var fieldName): - stringBuilder = stringBuilder.AppendLine($"{reference} = this.{fieldName};"); - break; - case FactoryResolution(var reference, _, var functionName, var parameters): - stringBuilder = parameters.Aggregate(stringBuilder, - (builder, tuple) => GenerateResolutions(builder, tuple.Dependency ?? throw new Exception())); - stringBuilder = stringBuilder.AppendLine($"{reference} = this.{functionName}({string.Join(", ", parameters.Select(t => $"{t.Name}: {t.Dependency.Reference}"))});"); - break; - case CollectionResolution(var reference, _, var itemFullName, var items): - stringBuilder = items.OfType().Aggregate(stringBuilder, GenerateResolutions); - stringBuilder = stringBuilder.AppendLine( - $"{reference} = new {itemFullName}[]{{{string.Join(", ", items.Select(d => $"({itemFullName}) {(d as Resolvable)?.Reference}"))}}};"); - break; - default: - throw new Exception("Unexpected case or not implemented."); - } - - return stringBuilder; - } - - StringBuilder GenerateRangedInstanceFunction(StringBuilder stringBuilder, RangedInstance rangedInstance) - { - stringBuilder = stringBuilder - .AppendLine( - $"private {rangedInstance.Function.TypeFullName} {rangedInstance.Function.FieldReference};") - .AppendLine( - $"private {_wellKnownTypes.SemaphoreSlim.FullName()} {rangedInstance.Function.LockReference} = new {_wellKnownTypes.SemaphoreSlim.FullName()}(1);"); - - foreach (var (resolvable, funcParameterResolutions) in rangedInstance.Overloads) - { - var parameters = string.Join(", ", - funcParameterResolutions.Select(p => $"{p.TypeFullName} {p.Reference}")); - stringBuilder = stringBuilder.AppendLine( - $"public {rangedInstance.Function.TypeFullName} {rangedInstance.Function.Reference}({parameters})") - .AppendLine($"{{") - .AppendLine($"this.{rangedInstance.Function.LockReference}.Wait();") - .AppendLine($"try") - .AppendLine($"{{") - .AppendLine( - $"if (this.{rangedInstance.DisposalHandling.DisposedPropertyReference}) throw new {_wellKnownTypes.ObjectDisposedException}(nameof({rangedInstance.DisposalHandling.RangeName}));") - .AppendLine( - $"if (!object.ReferenceEquals({rangedInstance.Function.FieldReference}, null)) return {rangedInstance.Function.FieldReference};"); - - stringBuilder = GenerateResolutionFunctionContent(stringBuilder, resolvable); - - stringBuilder = stringBuilder - .AppendLine( - $"this.{rangedInstance.Function.FieldReference} = {resolvable.Reference};") - .AppendLine($"}}") - .AppendLine($"finally") - .AppendLine($"{{") - .AppendLine($"this.{rangedInstance.Function.LockReference}.Release();") - .AppendLine($"}}") - .AppendLine($"return this.{rangedInstance.Function.FieldReference};") - .AppendLine($"}}"); - } - - return stringBuilder; - } - } -} \ No newline at end of file diff --git a/Main/ExecuteImpl.cs b/Main/ExecuteImpl.cs index 2e55f35a..807fb656 100644 --- a/Main/ExecuteImpl.cs +++ b/Main/ExecuteImpl.cs @@ -1,4 +1,5 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; +using MrMeeseeks.DIE.CodeBuilding; using MrMeeseeks.DIE.ResolutionBuilding; namespace MrMeeseeks.DIE; diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index b8ecbdde..1423d807 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -1,4 +1,5 @@ -using MrMeeseeks.DIE.ResolutionBuilding; +using MrMeeseeks.DIE.CodeBuilding; +using MrMeeseeks.DIE.ResolutionBuilding; namespace MrMeeseeks.DIE; @@ -23,7 +24,7 @@ public void Execute(GeneratorExecutionContext context) var checkDecorators = new CheckDecorators(wellKnownTypes, getAssemblyAttributes, typesFromTypeAggregatingAttributes, getSetOfTypesWithProperties); var checkTypeProperties = new CheckTypeProperties(typesFromTypeAggregatingAttributes, getAssemblyAttributes, wellKnownTypes, getSetOfTypesWithProperties); var typeToImplementationMapper = new TypeToImplementationsMapper(getAllImplementations, checkDecorators, checkTypeProperties); - var containerGenerator = new ContainerGenerator(context, wellKnownTypes, diagLogger); + var containerGenerator = new ContainerGenerator(context, diagLogger, ContainerCodeBuilderFactory, ScopeCodeBuilderFactory); var referenceGeneratorFactory = new ReferenceGeneratorFactory(ReferenceGeneratorFactory); var containerErrorGenerator = new ContainerErrorGenerator(context); var resolutionTreeCreationErrorHarvester = new ResolutionTreeCreationErrorHarvester(); @@ -56,5 +57,21 @@ public void Execute(GeneratorExecutionContext context) new EmptyUserProvidedScopeElements()); // todo Replace EmptyUserProvidedScopeElements with one for the scope specifically IContainerInfo ContainerInfoFactory(INamedTypeSymbol type) => new ContainerInfo(type, wellKnownTypes); IReferenceGenerator ReferenceGeneratorFactory(int j) => new ReferenceGenerator(j); + + IContainerCodeBuilder ContainerCodeBuilderFactory( + IContainerInfo containerInfo, + ContainerResolution containerResolution, + IScopeCodeBuilder scopeCodeBuilder) => new ContainerCodeBuilder( + containerInfo, + containerResolution, + scopeCodeBuilder, + wellKnownTypes); + + IScopeCodeBuilder ScopeCodeBuilderFactory( + IContainerInfo containerInfo, + ScopeResolution containerResolution) => new ScopeCodeBuilder( + containerInfo, + containerResolution, + wellKnownTypes); } } \ No newline at end of file From 975b5ac91f19215d6a34f22af4fe5774e924ea9b Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sat, 15 Jan 2022 10:26:20 +0100 Subject: [PATCH 039/162] Renaming scope instance terms for more consistency --- Main/Attributes.cs | 8 ++-- Main/CheckTypeProperties.cs | 16 +++---- Main/CodeBuilding/RangeCodeBaseBuilder.cs | 8 ++-- .../ContainerResolutionBuilder.cs | 10 ++--- .../RangeResolutionBaseBuilder.cs | 14 +++--- .../ScopeResolutionBuilder.cs | 10 ++--- Main/ResolutionTreeItem.cs | 2 +- Main/TypesFromTypeAggregatingAttributes.cs | 12 ++--- Main/WellKnownTypes.cs | 20 ++++----- Sample/Container.cs | 4 +- Sample/MarkerInterfaces.cs | 4 +- Test/AssemblyInfo.cs | 14 ++---- Test/CompositeTests.cs | 44 +++++++++---------- Test/DecoratorTests.cs | 34 +++++++------- Test/MarkerInterfaces.cs | 4 +- 15 files changed, 98 insertions(+), 106 deletions(-) diff --git a/Main/Attributes.cs b/Main/Attributes.cs index 67f4ec3f..b5a675e0 100644 --- a/Main/Attributes.cs +++ b/Main/Attributes.cs @@ -26,15 +26,15 @@ public TransientAggregationAttribute(params Type[] types) {} } [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] -public class SingleInstanceAggregationAttribute : Attribute +public class ContainerInstanceAggregationAttribute : Attribute { - public SingleInstanceAggregationAttribute(params Type[] types) {} + public ContainerInstanceAggregationAttribute(params Type[] types) {} } [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] -public class ScopedInstanceAggregationAttribute : Attribute +public class ScopeInstanceAggregationAttribute : Attribute { - public ScopedInstanceAggregationAttribute(params Type[] types) {} + public ScopeInstanceAggregationAttribute(params Type[] types) {} } [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] diff --git a/Main/CheckTypeProperties.cs b/Main/CheckTypeProperties.cs index d3fd93dc..9827c987 100644 --- a/Main/CheckTypeProperties.cs +++ b/Main/CheckTypeProperties.cs @@ -5,7 +5,7 @@ internal enum ScopeLevel None, Scope, TransientScope, - SingleInstance + Container } internal interface ICheckTypeProperties @@ -22,8 +22,8 @@ internal interface ICheckTypeProperties internal class CheckTypeProperties : ICheckTypeProperties { private readonly IImmutableSet _transientTypes; - private readonly IImmutableSet _singleInstanceTypes; - private readonly IImmutableSet _scopedInstanceTypes; + private readonly IImmutableSet _containerInstanceTypes; + private readonly IImmutableSet _scopeInstanceTypes; private readonly IImmutableSet _scopeRootTypes; private readonly IImmutableSet _compositeTypes; private readonly Dictionary _interfaceToComposite; @@ -36,8 +36,8 @@ internal CheckTypeProperties( IGetSetOfTypesWithProperties getSetOfTypesWithProperties) { _transientTypes = getSetOfTypesWithProperties.Get(typesFromTypeAggregatingAttributes.Transient); - _singleInstanceTypes = getSetOfTypesWithProperties.Get(typesFromTypeAggregatingAttributes.SingleInstance); - _scopedInstanceTypes = getSetOfTypesWithProperties.Get(typesFromTypeAggregatingAttributes.ScopedInstance); + _containerInstanceTypes = getSetOfTypesWithProperties.Get(typesFromTypeAggregatingAttributes.ContainerInstance); + _scopeInstanceTypes = getSetOfTypesWithProperties.Get(typesFromTypeAggregatingAttributes.ScopeInstance); _scopeRootTypes = getSetOfTypesWithProperties.Get(typesFromTypeAggregatingAttributes.ScopeRoot); _compositeTypes = getSetOfTypesWithProperties.Get(typesFromTypeAggregatingAttributes.Composite); _interfaceToComposite = _compositeTypes @@ -104,9 +104,9 @@ internal CheckTypeProperties( public bool ShouldBeComposite(INamedTypeSymbol interfaceType) => _interfaceToComposite.ContainsKey(interfaceType); public ScopeLevel GetScopeLevelFor(INamedTypeSymbol implementationType) { - if (_singleInstanceTypes.Contains(implementationType)) - return ScopeLevel.SingleInstance; - if (_scopedInstanceTypes.Contains(implementationType)) + if (_containerInstanceTypes.Contains(implementationType)) + return ScopeLevel.Container; + if (_scopeInstanceTypes.Contains(implementationType)) return ScopeLevel.Scope; return ScopeLevel.None; } diff --git a/Main/CodeBuilding/RangeCodeBaseBuilder.cs b/Main/CodeBuilding/RangeCodeBaseBuilder.cs index 20342e44..75402061 100644 --- a/Main/CodeBuilding/RangeCodeBaseBuilder.cs +++ b/Main/CodeBuilding/RangeCodeBaseBuilder.cs @@ -47,7 +47,7 @@ protected StringBuilder GenerateContainerDisposalFunction( { stringBuilder = rangeResolution.RangedInstances.Aggregate( stringBuilder, - (current, singleInstanceResolution) => current.AppendLine($"this.{singleInstanceResolution.Function.LockReference}.Wait();")); + (current, containerInstanceResolution) => current.AppendLine($"this.{containerInstanceResolution.Function.LockReference}.Wait();")); stringBuilder = stringBuilder .AppendLine($"try") @@ -69,7 +69,7 @@ protected StringBuilder GenerateContainerDisposalFunction( stringBuilder = rangeResolution.RangedInstances.Aggregate( stringBuilder, - (current, singleInstanceResolution) => current.AppendLine($"this.{singleInstanceResolution.Function.LockReference}.Release();")); + (current, containerInstanceResolution) => current.AppendLine($"this.{containerInstanceResolution.Function.LockReference}.Release();")); return stringBuilder .AppendLine($"}}") @@ -162,9 +162,9 @@ protected StringBuilder GenerateResolutions( { switch (resolution) { - case ScopeRootResolution(var reference, var typeFullName, var scopeReference, var scopeTypeFullName, var singleInstanceScopeReference, var parameter, var (disposableCollectionReference, _, _, _, _), var (createFunctionReference, _)): + case ScopeRootResolution(var reference, var typeFullName, var scopeReference, var scopeTypeFullName, var containerInstanceScopeReference, var parameter, var (disposableCollectionReference, _, _, _, _), var (createFunctionReference, _)): stringBuilder = stringBuilder - .AppendLine($"{scopeReference} = new {scopeTypeFullName}({singleInstanceScopeReference});") + .AppendLine($"{scopeReference} = new {scopeTypeFullName}({containerInstanceScopeReference});") .AppendLine($"{disposableCollectionReference}.Add(({WellKnownTypes.Disposable.FullName()}) {scopeReference});") .AppendLine($"{reference} = ({typeFullName}) {scopeReference}.{createFunctionReference}({string.Join(", ", parameter.Select(p => p.Reference))});"); IsDisposalHandlingRequired = true; diff --git a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs index f06c1b7c..17a1e869 100644 --- a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs @@ -4,7 +4,7 @@ internal interface IContainerResolutionBuilder { void AddCreateResolveFunctions(IReadOnlyList rootTypes); - RangedInstanceReferenceResolution CreateSingleInstanceReferenceResolution( + RangedInstanceReferenceResolution CreateContainerInstanceReferenceResolution( RangeResolutionBaseBuilder.ForConstructorParameter parameter, string containerReference); @@ -59,14 +59,14 @@ public void AddCreateResolveFunctions(IReadOnlyList rootTypes) DisposalHandling)); } - public RangedInstanceReferenceResolution CreateSingleInstanceReferenceResolution(ForConstructorParameter parameter, string containerReference) => + public RangedInstanceReferenceResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter, string containerReference) => CreateRangedInstanceReferenceResolution( parameter, - "Single", + "Container", containerReference); - protected override RangedInstanceReferenceResolution CreateSingleInstanceReferenceResolution(ForConstructorParameter parameter) => - CreateSingleInstanceReferenceResolution(parameter, "this"); + protected override RangedInstanceReferenceResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter) => + CreateContainerInstanceReferenceResolution(parameter, "this"); protected override ScopeRootResolution CreateScopeRootResolution( IScopeRootParameter parameter, diff --git a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs index 61ffa9f0..8e5dfbe1 100644 --- a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs +++ b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs @@ -85,7 +85,7 @@ protected RangeResolutionBaseBuilder( RootReferenceGenerator.Generate("disposable")); } - protected abstract RangedInstanceReferenceResolution CreateSingleInstanceReferenceResolution(ForConstructorParameter parameter); + protected abstract RangedInstanceReferenceResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter); protected abstract ScopeRootResolution CreateScopeRootResolution( IScopeRootParameter parameter, @@ -529,8 +529,8 @@ protected Resolvable SwitchImplementation(SwitchImplementationParameter paramete }; return scopeLevel switch { - ScopeLevel.SingleInstance => CreateSingleInstanceReferenceResolution(nextParameter), - ScopeLevel.Scope => CreateScopedInstanceReferenceResolution(nextParameter), + ScopeLevel.Container => CreateContainerInstanceReferenceResolution(nextParameter), + ScopeLevel.Scope => CreateScopeInstanceReferenceResolution(nextParameter), _ => CreateConstructorResolution(nextParameter) }; } @@ -643,11 +643,11 @@ protected Resolvable CreateConstructorResolution(ForConstructorParameter paramet } - private RangedInstanceReferenceResolution CreateScopedInstanceReferenceResolution( + private RangedInstanceReferenceResolution CreateScopeInstanceReferenceResolution( ForConstructorParameter parameter) => CreateRangedInstanceReferenceResolution( parameter, - "Scoped", + "Scope", "this"); protected RangedInstanceReferenceResolution CreateRangedInstanceReferenceResolution( @@ -697,7 +697,7 @@ protected void DoRangedInstancesWork() { while (RangedInstanceResolutionsQueue.Any()) { - var (scopedInstanceFunction, parameter, type, interfaceExtension) = RangedInstanceResolutionsQueue.Dequeue(); + var (scopeInstanceFunction, parameter, type, interfaceExtension) = RangedInstanceResolutionsQueue.Dequeue(); var resolvable = interfaceExtension switch { DecorationInterfaceExtension decoration => CreateConstructorResolution(new ForConstructorParameterWithDecoration( @@ -707,7 +707,7 @@ protected void DoRangedInstancesWork() _ => CreateConstructorResolution(new ForConstructorParameter(type, parameter)) }; RangedInstances.Add(( - scopedInstanceFunction, + scopeInstanceFunction, new RangedInstanceFunctionOverload( resolvable, parameter.Select(t => t.Item2).ToList()))); diff --git a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs index c5cccd91..8ff35433 100644 --- a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs @@ -7,7 +7,7 @@ internal interface IScopeResolutionBuilder ScopeRootResolution AddCreateResolveFunction( RangeResolutionBaseBuilder.IScopeRootParameter parameter, INamedTypeSymbol rootType, - string singleInstanceScopeReference, + string containerInstanceScopeReference, DisposableCollectionResolution disposableCollectionResolution, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters); @@ -52,9 +52,9 @@ internal ScopeResolutionBuilder( _containerParameterReference = RootReferenceGenerator.Generate("container"); } - protected override RangedInstanceReferenceResolution CreateSingleInstanceReferenceResolution( + protected override RangedInstanceReferenceResolution CreateContainerInstanceReferenceResolution( ForConstructorParameter parameter) => - _containerResolutionBuilder.CreateSingleInstanceReferenceResolution( + _containerResolutionBuilder.CreateContainerInstanceReferenceResolution( parameter, _containerReference); @@ -75,7 +75,7 @@ protected override ScopeRootResolution CreateScopeRootResolution( public ScopeRootResolution AddCreateResolveFunction( IScopeRootParameter parameter, INamedTypeSymbol rootType, - string singleInstanceScopeReference, + string containerInstanceScopeReference, DisposableCollectionResolution disposableCollectionResolution, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) { @@ -105,7 +105,7 @@ public ScopeRootResolution AddCreateResolveFunction( rootType.FullName(), RootReferenceGenerator.Generate("scopeRoot"), Name, - singleInstanceScopeReference, + containerInstanceScopeReference, currentParameters.Select(t => t.Resolution).ToList(), disposableCollectionResolution, function); diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index a33da169..267881bd 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -41,7 +41,7 @@ internal record ScopeRootResolution( string TypeFullName, string ScopeReference, string ScopeTypeFullName, - string SingleInstanceScopeReference, + string ContainerInstanceScopeReference, IReadOnlyList Parameter, DisposableCollectionResolution DisposableCollectionResolution, ScopeRootFunction ScopeRootFunction) : Resolvable(Reference, TypeFullName); diff --git a/Main/TypesFromTypeAggregatingAttributes.cs b/Main/TypesFromTypeAggregatingAttributes.cs index cb5908ff..eacda2b5 100644 --- a/Main/TypesFromTypeAggregatingAttributes.cs +++ b/Main/TypesFromTypeAggregatingAttributes.cs @@ -5,8 +5,8 @@ internal interface ITypesFromTypeAggregatingAttributes IReadOnlyList Spy { get; } IReadOnlyList Implementation { get; } IReadOnlyList Transient { get; } - IReadOnlyList SingleInstance { get; } - IReadOnlyList ScopedInstance { get; } + IReadOnlyList ContainerInstance { get; } + IReadOnlyList ScopeInstance { get; } IReadOnlyList ScopeRoot { get; } IReadOnlyList Decorator { get; } IReadOnlyList Composite { get; } @@ -21,8 +21,8 @@ internal TypesFromTypeAggregatingAttributes( Spy = GetTypesFromAttribute(wellKnownTypes.SpyAggregationAttribute).ToList(); Implementation = GetTypesFromAttribute(wellKnownTypes.ImplementationAggregationAttribute).ToList(); Transient = GetTypesFromAttribute(wellKnownTypes.TransientAggregationAttribute).ToList(); - SingleInstance = GetTypesFromAttribute(wellKnownTypes.SingleInstanceAggregationAttribute).ToList(); - ScopedInstance = GetTypesFromAttribute(wellKnownTypes.ScopedInstanceAggregationAttribute).ToList(); + ContainerInstance = GetTypesFromAttribute(wellKnownTypes.ContainerInstanceAggregationAttribute).ToList(); + ScopeInstance = GetTypesFromAttribute(wellKnownTypes.ScopeInstanceAggregationAttribute).ToList(); ScopeRoot = GetTypesFromAttribute(wellKnownTypes.ScopeRootAggregationAttribute).ToList(); Decorator = GetTypesFromAttribute(wellKnownTypes.DecoratorAggregationAttribute).ToList(); Composite = GetTypesFromAttribute(wellKnownTypes.CompositeAggregationAttribute).ToList(); @@ -63,8 +63,8 @@ bool CheckValidType(TypedConstant typedConstant, out INamedTypeSymbol type) public IReadOnlyList Spy { get; } public IReadOnlyList Implementation { get; } public IReadOnlyList Transient { get; } - public IReadOnlyList SingleInstance { get; } - public IReadOnlyList ScopedInstance { get; } + public IReadOnlyList ContainerInstance { get; } + public IReadOnlyList ScopeInstance { get; } public IReadOnlyList ScopeRoot { get; } public IReadOnlyList Decorator { get; } public IReadOnlyList Composite { get; } diff --git a/Main/WellKnownTypes.cs b/Main/WellKnownTypes.cs index 4c537510..f14a62d9 100644 --- a/Main/WellKnownTypes.cs +++ b/Main/WellKnownTypes.cs @@ -6,8 +6,8 @@ internal record WellKnownTypes( INamedTypeSymbol SpyConstructorChoiceAggregationAttribute, INamedTypeSymbol ImplementationAggregationAttribute, INamedTypeSymbol TransientAggregationAttribute, - INamedTypeSymbol SingleInstanceAggregationAttribute, - INamedTypeSymbol ScopedInstanceAggregationAttribute, + INamedTypeSymbol ContainerInstanceAggregationAttribute, + INamedTypeSymbol ScopeInstanceAggregationAttribute, INamedTypeSymbol ScopeRootAggregationAttribute, INamedTypeSymbol DecoratorAggregationAttribute, INamedTypeSymbol CompositeAggregationAttribute, @@ -63,11 +63,11 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK var transientAggregationAttribute = compilation .GetTypeByMetadataName(typeof(TransientAggregationAttribute).FullName ?? ""); - var singleInstanceAggregationAttribute = compilation - .GetTypeByMetadataName(typeof(SingleInstanceAggregationAttribute).FullName ?? ""); + var containerInstanceAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(ContainerInstanceAggregationAttribute).FullName ?? ""); - var scopedInstanceAggregationAttribute = compilation - .GetTypeByMetadataName(typeof(ScopedInstanceAggregationAttribute).FullName ?? ""); + var scopeInstanceAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(ScopeInstanceAggregationAttribute).FullName ?? ""); var scopeRootAggregationAttribute = compilation .GetTypeByMetadataName(typeof(ScopeRootAggregationAttribute).FullName ?? ""); @@ -89,8 +89,8 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK || spyConstructorChoiceAggregationAttribute is null || implementationAggregationAttribute is null || transientAggregationAttribute is null - || singleInstanceAggregationAttribute is null - || scopedInstanceAggregationAttribute is null + || containerInstanceAggregationAttribute is null + || scopeInstanceAggregationAttribute is null || scopeRootAggregationAttribute is null || decoratorAggregationAttribute is null || compositeAggregationAttribute is null @@ -122,8 +122,8 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK SpyConstructorChoiceAggregationAttribute: spyConstructorChoiceAggregationAttribute, ImplementationAggregationAttribute: implementationAggregationAttribute, TransientAggregationAttribute: transientAggregationAttribute, - SingleInstanceAggregationAttribute: singleInstanceAggregationAttribute, - ScopedInstanceAggregationAttribute: scopedInstanceAggregationAttribute, + ContainerInstanceAggregationAttribute: containerInstanceAggregationAttribute, + ScopeInstanceAggregationAttribute: scopeInstanceAggregationAttribute, ScopeRootAggregationAttribute: scopeRootAggregationAttribute, DecoratorAggregationAttribute: decoratorAggregationAttribute, CompositeAggregationAttribute: compositeAggregationAttribute, diff --git a/Sample/Container.cs b/Sample/Container.cs index b7338604..a34879aa 100644 --- a/Sample/Container.cs +++ b/Sample/Container.cs @@ -1,8 +1,8 @@ using MrMeeseeks.DIE; using MrMeeseeks.DIE.Sample; -[assembly:SingleInstanceAggregation(typeof(ISingleInstance))] -[assembly:ScopedInstanceAggregation(typeof(IScopedInstance))] +[assembly:ContainerInstanceAggregation(typeof(IContainerInstance))] +[assembly:ScopeInstanceAggregation(typeof(IScopeInstance))] [assembly:ScopeRootAggregation(typeof(IScopeRoot))] [assembly:TransientAggregation(typeof(ITransient))] [assembly:DecoratorAggregation(typeof(IDecorator<>))] diff --git a/Sample/MarkerInterfaces.cs b/Sample/MarkerInterfaces.cs index b7993d38..ea36dee9 100644 --- a/Sample/MarkerInterfaces.cs +++ b/Sample/MarkerInterfaces.cs @@ -1,7 +1,7 @@ namespace MrMeeseeks.DIE.Sample; -public interface ISingleInstance { } -public interface IScopedInstance { } +public interface IContainerInstance { } +public interface IScopeInstance { } public interface IScopeRoot { } public interface ITransient { } public interface IDecorator { } diff --git a/Test/AssemblyInfo.cs b/Test/AssemblyInfo.cs index 654e5670..a14d9c8c 100644 --- a/Test/AssemblyInfo.cs +++ b/Test/AssemblyInfo.cs @@ -1,17 +1,9 @@ -using System; using MrMeeseeks.DIE; using MrMeeseeks.DIE.Test; -[assembly:SingleInstanceAggregation(typeof(ISingleInstance))] -[assembly:ScopedInstanceAggregation(typeof(IScopedInstance))] +[assembly:ContainerInstanceAggregation(typeof(IContainerInstance))] +[assembly:ScopeInstanceAggregation(typeof(IScopeInstance))] [assembly:ScopeRootAggregation(typeof(IScopeRoot))] [assembly:TransientAggregation(typeof(ITransient))] [assembly:DecoratorAggregation(typeof(IDecorator<>))] -[assembly:CompositeAggregation(typeof(IComposite<>))] - -namespace MrMeeseeks.DIE.Test; - -public class AssemblyInfo -{ - -} \ No newline at end of file +[assembly:CompositeAggregation(typeof(IComposite<>))] \ No newline at end of file diff --git a/Test/CompositeTests.cs b/Test/CompositeTests.cs index a050aa7a..68cc699f 100644 --- a/Test/CompositeTests.cs +++ b/Test/CompositeTests.cs @@ -65,30 +65,30 @@ public void NormalList() } } -internal interface ICompositeSingleInstance +internal interface ICompositeContainerInstance { - IReadOnlyList Composites { get; } + IReadOnlyList Composites { get; } } -internal class CompositeSingleInstanceBasisA : ICompositeSingleInstance, ISingleInstance +internal class CompositeContainerInstanceBasisA : ICompositeContainerInstance, IContainerInstance { - public IReadOnlyList Composites => new List { this }; + public IReadOnlyList Composites => new List { this }; } -internal class CompositeSingleInstanceBasisB : ICompositeSingleInstance, ISingleInstance +internal class CompositeContainerInstanceBasisB : ICompositeContainerInstance, IContainerInstance { - public IReadOnlyList Composites => new List { this }; + public IReadOnlyList Composites => new List { this }; } -internal class CompositeSingleInstance : ICompositeSingleInstance, IComposite +internal class CompositeContainerInstance : ICompositeContainerInstance, IComposite { - public CompositeSingleInstance(IReadOnlyList composites) => + public CompositeContainerInstance(IReadOnlyList composites) => Composites = composites; - public IReadOnlyList Composites { get; } + public IReadOnlyList Composites { get; } } -internal partial class CompositeSingleInstanceContainer : IContainer, IContainer> +internal partial class CompositeContainerInstanceContainer : IContainer, IContainer> { } @@ -96,32 +96,32 @@ internal partial class CompositeSingleInstanceContainer : IContainer) container).Resolve(); + using var container = new CompositeContainerInstanceContainer(); + var composite = ((IContainer) container).Resolve(); foreach (var compositeComposite in composite.Composites) { Assert.NotEqual(composite, compositeComposite); var type = compositeComposite.GetType(); - Assert.True(type == typeof(CompositeSingleInstanceBasisA) || type == typeof(CompositeSingleInstanceBasisB)); + Assert.True(type == typeof(CompositeContainerInstanceBasisA) || type == typeof(CompositeContainerInstanceBasisB)); } - var nextComposite = ((IContainer) container).Resolve(); + var nextComposite = ((IContainer) container).Resolve(); Assert.Equal(composite, nextComposite); } [Fact] - public void SingleInstanceList() + public void ContainerInstanceList() { - using var container = new CompositeSingleInstanceContainer(); - var composites = ((IContainer>) container).Resolve(); + using var container = new CompositeContainerInstanceContainer(); + var composites = ((IContainer>) container).Resolve(); foreach (var compositeComposite in composites) { var type = compositeComposite.GetType(); - Assert.True(type == typeof(CompositeSingleInstanceBasisA) || type == typeof(CompositeSingleInstanceBasisB)); + Assert.True(type == typeof(CompositeContainerInstanceBasisA) || type == typeof(CompositeContainerInstanceBasisB)); } Assert.Equal(2, composites.Count); - var nextComposites = ((IContainer>) container).Resolve(); + var nextComposites = ((IContainer>) container).Resolve(); Assert.Equal(composites[0], nextComposites[0]); Assert.Equal(composites[1], nextComposites[1]); } @@ -132,7 +132,7 @@ internal interface ICompositeMixedScoping IReadOnlyList Composites { get; } } -internal class CompositeMixedScopingBasisA : ICompositeMixedScoping, ISingleInstance +internal class CompositeMixedScopingBasisA : ICompositeMixedScoping, IContainerInstance { public IReadOnlyList Composites => new List { this }; } @@ -197,7 +197,7 @@ internal interface ICompositeScopeRoot internal interface ICompositeScopeRootDependency { } -internal class CompositeScopeRootDependency : ICompositeScopeRootDependency, IScopedInstance { } +internal class CompositeScopeRootDependency : ICompositeScopeRootDependency, IScopeInstance { } internal class CompositeScopeRootBasisA : ICompositeScopeRoot, IScopeRoot { diff --git a/Test/DecoratorTests.cs b/Test/DecoratorTests.cs index 18a42d87..4d33434e 100644 --- a/Test/DecoratorTests.cs +++ b/Test/DecoratorTests.cs @@ -43,25 +43,25 @@ public void Normal() } } -internal interface IDecoratedSingleInstance +internal interface IDecoratedContainerInstance { - IDecoratedSingleInstance Decorated { get; } + IDecoratedContainerInstance Decorated { get; } } -internal class DecoratorSingleInstanceBasis : IDecoratedSingleInstance, ISingleInstance +internal class DecoratorContainerInstanceBasis : IDecoratedContainerInstance, IContainerInstance { - public IDecoratedSingleInstance Decorated => this; + public IDecoratedContainerInstance Decorated => this; } -internal class DecoratorSingleInstance : IDecoratedSingleInstance, IDecorator +internal class DecoratorContainerInstance : IDecoratedContainerInstance, IDecorator { - public DecoratorSingleInstance(IDecoratedSingleInstance decoratedSingleInstance) => - Decorated = decoratedSingleInstance; + public DecoratorContainerInstance(IDecoratedContainerInstance decoratedContainerInstance) => + Decorated = decoratedContainerInstance; - public IDecoratedSingleInstance Decorated { get; } + public IDecoratedContainerInstance Decorated { get; } } -internal partial class DecoratorSingleInstanceContainer : IContainer +internal partial class DecoratorContainerInstanceContainer : IContainer { } @@ -69,15 +69,15 @@ internal partial class DecoratorSingleInstanceContainer : IContainer) container).Resolve(); + using var container = new DecoratorContainerInstanceContainer(); + var decorated = ((IContainer) container).Resolve(); Assert.NotEqual(decorated, decorated.Decorated); - Assert.IsType(decorated); - Assert.IsType(decorated.Decorated); + Assert.IsType(decorated); + Assert.IsType(decorated.Decorated); - var decoratedNextReference = ((IContainer) container).Resolve(); + var decoratedNextReference = ((IContainer) container).Resolve(); Assert.Equal(decorated, decoratedNextReference); Assert.Equal(decorated.Decorated, decoratedNextReference.Decorated); } @@ -91,9 +91,9 @@ internal interface IDecoratedScopeRoot internal interface IDecoratedScopeRootDependency {} -internal class DecoratedScopeRootDependency : IDecoratedScopeRootDependency, IScopedInstance {} +internal class DecoratedScopeRootDependency : IDecoratedScopeRootDependency, IScopeInstance {} -internal class DecoratorScopeRootBasis : IDecoratedScopeRoot, IScopeRoot, IScopedInstance +internal class DecoratorScopeRootBasis : IDecoratedScopeRoot, IScopeRoot, IScopeInstance { public IDecoratedScopeRootDependency Dependency { get; } diff --git a/Test/MarkerInterfaces.cs b/Test/MarkerInterfaces.cs index 3f7c670a..d77894cb 100644 --- a/Test/MarkerInterfaces.cs +++ b/Test/MarkerInterfaces.cs @@ -1,7 +1,7 @@ namespace MrMeeseeks.DIE.Test; -public interface ISingleInstance { } -public interface IScopedInstance { } +public interface IContainerInstance { } +public interface IScopeInstance { } public interface IScopeRoot { } public interface ITransient { } public interface IDecorator { } From ff1f69c0cfc9c0b2183ddaf1ddb1ab6dacfc8612 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sun, 16 Jan 2022 21:13:06 +0100 Subject: [PATCH 040/162] Prepared for TransientScopeInstances without TransientScopes --- Main/Attributes.cs | 6 + Main/CheckTypeProperties.cs | 4 + Main/CodeBuilding/ContainerCodeBuilder.cs | 33 ++++ Main/CodeBuilding/ContainerGenerator.cs | 6 +- Main/CodeBuilding/RangeCodeBaseBuilder.cs | 4 +- Main/CodeBuilding/ScopeCodeBuilder.cs | 16 +- .../ContainerResolutionBuilder.cs | 24 ++- ...entScopeImplementationResolutionBuilder.cs | 6 + .../RangeResolutionBaseBuilder.cs | 145 +---------------- Main/ResolutionBuilding/ResolutionDtos.cs | 147 ++++++++++++++++++ .../ScopeResolutionBuilder.cs | 23 ++- ...ransientScopeInterfaceResolutionBuilder.cs | 108 +++++++++++++ Main/ResolutionTreeItem.cs | 14 ++ Main/SourceGenerator.cs | 10 +- Main/TypesFromTypeAggregatingAttributes.cs | 3 + Main/WellKnownTypes.cs | 6 + Sample/Container.cs | 1 + Sample/MarkerInterfaces.cs | 1 + Test/AssemblyInfo.cs | 1 + Test/MarkerInterfaces.cs | 1 + Test/TransientScopeInstanceTests.cs | 65 ++++++++ 21 files changed, 462 insertions(+), 162 deletions(-) create mode 100644 Main/ResolutionBuilding/ITransientScopeImplementationResolutionBuilder.cs create mode 100644 Main/ResolutionBuilding/ResolutionDtos.cs create mode 100644 Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs create mode 100644 Test/TransientScopeInstanceTests.cs diff --git a/Main/Attributes.cs b/Main/Attributes.cs index b5a675e0..d07b3cd3 100644 --- a/Main/Attributes.cs +++ b/Main/Attributes.cs @@ -31,6 +31,12 @@ public class ContainerInstanceAggregationAttribute : Attribute public ContainerInstanceAggregationAttribute(params Type[] types) {} } +[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] +public class TransientScopeInstanceAggregationAttribute : Attribute +{ + public TransientScopeInstanceAggregationAttribute(params Type[] types) {} +} + [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] public class ScopeInstanceAggregationAttribute : Attribute { diff --git a/Main/CheckTypeProperties.cs b/Main/CheckTypeProperties.cs index 9827c987..9f76d993 100644 --- a/Main/CheckTypeProperties.cs +++ b/Main/CheckTypeProperties.cs @@ -23,6 +23,7 @@ internal class CheckTypeProperties : ICheckTypeProperties { private readonly IImmutableSet _transientTypes; private readonly IImmutableSet _containerInstanceTypes; + private readonly IImmutableSet _transientScopeInstanceTypes; private readonly IImmutableSet _scopeInstanceTypes; private readonly IImmutableSet _scopeRootTypes; private readonly IImmutableSet _compositeTypes; @@ -37,6 +38,7 @@ internal CheckTypeProperties( { _transientTypes = getSetOfTypesWithProperties.Get(typesFromTypeAggregatingAttributes.Transient); _containerInstanceTypes = getSetOfTypesWithProperties.Get(typesFromTypeAggregatingAttributes.ContainerInstance); + _transientScopeInstanceTypes = getSetOfTypesWithProperties.Get(typesFromTypeAggregatingAttributes.TransientScopeInstance); _scopeInstanceTypes = getSetOfTypesWithProperties.Get(typesFromTypeAggregatingAttributes.ScopeInstance); _scopeRootTypes = getSetOfTypesWithProperties.Get(typesFromTypeAggregatingAttributes.ScopeRoot); _compositeTypes = getSetOfTypesWithProperties.Get(typesFromTypeAggregatingAttributes.Composite); @@ -106,6 +108,8 @@ public ScopeLevel GetScopeLevelFor(INamedTypeSymbol implementationType) { if (_containerInstanceTypes.Contains(implementationType)) return ScopeLevel.Container; + if (_transientScopeInstanceTypes.Contains(implementationType)) + return ScopeLevel.TransientScope; if (_scopeInstanceTypes.Contains(implementationType)) return ScopeLevel.Scope; return ScopeLevel.None; diff --git a/Main/CodeBuilding/ContainerCodeBuilder.cs b/Main/CodeBuilding/ContainerCodeBuilder.cs index bae097a3..c2f522f0 100644 --- a/Main/CodeBuilding/ContainerCodeBuilder.cs +++ b/Main/CodeBuilding/ContainerCodeBuilder.cs @@ -11,6 +11,8 @@ internal class ContainerCodeBuilder : RangeCodeBaseBuilder, IContainerCodeBuilde private readonly ContainerResolution _containerResolution; private readonly IScopeCodeBuilder _defaultScopeBuilder; + protected override string TransientScopeReference { get; } + public override StringBuilder Build(StringBuilder stringBuilder) { stringBuilder = stringBuilder @@ -22,6 +24,35 @@ public override StringBuilder Build(StringBuilder stringBuilder) stringBuilder = GenerateResolutionRange( stringBuilder, _containerResolution); + + stringBuilder = stringBuilder + .AppendLine($"internal interface {_containerResolution.TransientScopeInterface.Name}") + .AppendLine($"{{"); + + stringBuilder = _containerResolution.TransientScopeInterface.Functions.Aggregate( + stringBuilder, + (sb, f) => sb.AppendLine( + $"{f.TypeFullName} {f.Reference}({string.Join(", ", f.Parameter.Select(p => $"{p.TypeFullName} {p.Reference}"))});")); + + stringBuilder = stringBuilder + .AppendLine($"}}"); + + stringBuilder = stringBuilder + .AppendLine($"internal class {_containerResolution.TransientScopeInterface.ContainerAdapterName} : {_containerResolution.TransientScopeInterface.Name}") + .AppendLine($"{{") + .AppendLine($"private {_containerInfo.FullName} _container;") + .AppendLine($"internal {_containerResolution.TransientScopeInterface.ContainerAdapterName}({_containerInfo.FullName} container) => _container = container;"); + + stringBuilder = _containerResolution.TransientScopeInterface.Functions.Aggregate( + stringBuilder, + (sb, f) => sb.AppendLine( + $"public {f.TypeFullName} {f.Reference}({string.Join(", ", f.Parameter.Select(p => $"{p.TypeFullName} {p.Reference}"))}) =>") + .AppendLine($"_container.{f.Reference}({string.Join(", ", f.Parameter.Select(p => p.Reference))});")); + + stringBuilder = stringBuilder + .AppendLine($"}}") + .AppendLine($"private {_containerResolution.TransientScopeInterface.ContainerAdapterName} _{TransientScopeReference};") + .AppendLine($"private {_containerResolution.TransientScopeInterface.ContainerAdapterName} {TransientScopeReference} => _{TransientScopeReference} ??= new {_containerResolution.TransientScopeInterface.ContainerAdapterName}(this);"); stringBuilder = _defaultScopeBuilder.Build(stringBuilder); @@ -43,5 +74,7 @@ public ContainerCodeBuilder( _containerInfo = containerInfo; _containerResolution = containerResolution; _defaultScopeBuilder = defaultScopeBuilder; + + TransientScopeReference = containerResolution.TransientScopeAdapterReference; } } \ No newline at end of file diff --git a/Main/CodeBuilding/ContainerGenerator.cs b/Main/CodeBuilding/ContainerGenerator.cs index e121bc8f..01bb48f7 100644 --- a/Main/CodeBuilding/ContainerGenerator.cs +++ b/Main/CodeBuilding/ContainerGenerator.cs @@ -13,13 +13,13 @@ internal class ContainerGenerator : IContainerGenerator private readonly GeneratorExecutionContext _context; private readonly IDiagLogger _diagLogger; private readonly Func _containerCodeBuilderFactory; - private readonly Func _scopeCodeBuilderFactory; + private readonly Func _scopeCodeBuilderFactory; internal ContainerGenerator( GeneratorExecutionContext context, IDiagLogger diagLogger, Func containerCodeBuilderFactory, - Func scopeCodeBuilderFactory) + Func scopeCodeBuilderFactory) { _context = context; _diagLogger = diagLogger; @@ -36,7 +36,7 @@ public void Generate(IContainerInfo containerInfo, ContainerResolution container } var containerCodeBuilder = _containerCodeBuilderFactory(containerInfo, containerResolution, - _scopeCodeBuilderFactory(containerInfo, containerResolution.DefaultScope)); + _scopeCodeBuilderFactory(containerInfo, containerResolution.DefaultScope, containerResolution.TransientScopeInterface)); var generatedContainer = containerCodeBuilder.Build(new StringBuilder()); diff --git a/Main/CodeBuilding/RangeCodeBaseBuilder.cs b/Main/CodeBuilding/RangeCodeBaseBuilder.cs index 75402061..6241633a 100644 --- a/Main/CodeBuilding/RangeCodeBaseBuilder.cs +++ b/Main/CodeBuilding/RangeCodeBaseBuilder.cs @@ -16,6 +16,8 @@ internal RangeCodeBaseBuilder( WellKnownTypes = wellKnownTypes; } + protected abstract string TransientScopeReference { get; } + protected StringBuilder GenerateResolutionRange( StringBuilder stringBuilder, RangeResolution rangeResolution) @@ -164,7 +166,7 @@ protected StringBuilder GenerateResolutions( { case ScopeRootResolution(var reference, var typeFullName, var scopeReference, var scopeTypeFullName, var containerInstanceScopeReference, var parameter, var (disposableCollectionReference, _, _, _, _), var (createFunctionReference, _)): stringBuilder = stringBuilder - .AppendLine($"{scopeReference} = new {scopeTypeFullName}({containerInstanceScopeReference});") + .AppendLine($"{scopeReference} = new {scopeTypeFullName}({containerInstanceScopeReference}, {TransientScopeReference});") .AppendLine($"{disposableCollectionReference}.Add(({WellKnownTypes.Disposable.FullName()}) {scopeReference});") .AppendLine($"{reference} = ({typeFullName}) {scopeReference}.{createFunctionReference}({string.Join(", ", parameter.Select(p => p.Reference))});"); IsDisposalHandlingRequired = true; diff --git a/Main/CodeBuilding/ScopeCodeBuilder.cs b/Main/CodeBuilding/ScopeCodeBuilder.cs index 74c6bca5..d084d067 100644 --- a/Main/CodeBuilding/ScopeCodeBuilder.cs +++ b/Main/CodeBuilding/ScopeCodeBuilder.cs @@ -9,6 +9,9 @@ internal class ScopeCodeBuilder : RangeCodeBaseBuilder, IScopeCodeBuilder { private readonly IContainerInfo _containerInfo; private readonly ScopeResolution _scopeResolution; + private readonly TransientScopeInterfaceResolution _transientScopeInterfaceResolution; + + protected override string TransientScopeReference { get; } public override StringBuilder Build(StringBuilder stringBuilder) { @@ -20,11 +23,13 @@ public override StringBuilder Build(StringBuilder stringBuilder) $"internal partial class {_scopeResolution.Name} : {WellKnownTypes.Disposable.FullName()}") .AppendLine($"{{") .AppendLine($"private readonly {_containerInfo.FullName} {_scopeResolution.ContainerReference};") - .AppendLine( - $"internal {_scopeResolution.Name}({_containerInfo.FullName} {_scopeResolution.ContainerParameterReference})") + .AppendLine($"private readonly {_transientScopeInterfaceResolution.Name} {TransientScopeReference};") + .AppendLine($"internal {_scopeResolution.Name}(") + .AppendLine($"{_containerInfo.FullName} {_scopeResolution.ContainerParameterReference},") + .AppendLine($"{_transientScopeInterfaceResolution.Name} {_scopeResolution.TransientScopeParameterReference})") .AppendLine($"{{") - .AppendLine( - $"{_scopeResolution.ContainerReference} = {_scopeResolution.ContainerParameterReference};") + .AppendLine($"{_scopeResolution.ContainerReference} = {_scopeResolution.ContainerParameterReference};") + .AppendLine($"{TransientScopeReference} = {_scopeResolution.TransientScopeParameterReference};") .AppendLine($"}}"); stringBuilder = GenerateResolutionRange( @@ -41,6 +46,7 @@ public ScopeCodeBuilder( // parameter IContainerInfo containerInfo, ScopeResolution scopeResolution, + TransientScopeInterfaceResolution transientScopeInterfaceResolution, // dependencies WellKnownTypes wellKnownTypes) @@ -48,5 +54,7 @@ public ScopeCodeBuilder( { _containerInfo = containerInfo; _scopeResolution = scopeResolution; + _transientScopeInterfaceResolution = transientScopeInterfaceResolution; + TransientScopeReference = _scopeResolution.TransientScopeReference; } } \ No newline at end of file diff --git a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs index 17a1e869..ed262e02 100644 --- a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs @@ -5,30 +5,33 @@ internal interface IContainerResolutionBuilder void AddCreateResolveFunctions(IReadOnlyList rootTypes); RangedInstanceReferenceResolution CreateContainerInstanceReferenceResolution( - RangeResolutionBaseBuilder.ForConstructorParameter parameter, + ForConstructorParameter parameter, string containerReference); ContainerResolution Build(); } -internal class ContainerResolutionBuilder : RangeResolutionBaseBuilder, IContainerResolutionBuilder +internal class ContainerResolutionBuilder : RangeResolutionBaseBuilder, IContainerResolutionBuilder, ITransientScopeImplementationResolutionBuilder { private readonly IContainerInfo _containerInfo; - + private readonly ITransientScopeInterfaceResolutionBuilder _transientScopeInterfaceResolutionBuilder; + private readonly List _rootResolutions = new (); private readonly IScopeResolutionBuilder _scopeResolutionBuilder; + private readonly string _transientScopeAdapterReference; internal ContainerResolutionBuilder( // parameters IContainerInfo containerInfo, // dependencies + ITransientScopeInterfaceResolutionBuilder transientScopeInterfaceResolutionBuilder, ITypeToImplementationsMapper typeToImplementationsMapper, IReferenceGeneratorFactory referenceGeneratorFactory, ICheckTypeProperties checkTypeProperties, ICheckDecorators checkDecorators, WellKnownTypes wellKnownTypes, - Func scopeResolutionBuilderFactory, + Func scopeResolutionBuilderFactory, IUserProvidedScopeElements userProvidedScopeElements) : base( (containerInfo.Name, false), @@ -40,7 +43,11 @@ internal ContainerResolutionBuilder( userProvidedScopeElements) { _containerInfo = containerInfo; - _scopeResolutionBuilder = scopeResolutionBuilderFactory(this); + _transientScopeInterfaceResolutionBuilder = transientScopeInterfaceResolutionBuilder; + _scopeResolutionBuilder = scopeResolutionBuilderFactory(this, transientScopeInterfaceResolutionBuilder); + + transientScopeInterfaceResolutionBuilder.AddImplementation(this); + _transientScopeAdapterReference = RootReferenceGenerator.Generate("TransientScopeAdapter"); } public void AddCreateResolveFunctions(IReadOnlyList rootTypes) @@ -68,6 +75,9 @@ public RangedInstanceReferenceResolution CreateContainerInstanceReferenceResolut protected override RangedInstanceReferenceResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter) => CreateContainerInstanceReferenceResolution(parameter, "this"); + protected override RangedInstanceReferenceResolution CreateTransientScopeInstanceReferenceResolution(ForConstructorParameter parameter) => + _transientScopeInterfaceResolutionBuilder.CreateTransientScopeInstanceReferenceResolution(parameter, "this"); + protected override ScopeRootResolution CreateScopeRootResolution( IScopeRootParameter parameter, INamedTypeSymbol rootType, @@ -98,6 +108,10 @@ public ContainerResolution Build() g.Select(t => t.Item2).ToList(), DisposalHandling)) .ToList(), + _transientScopeInterfaceResolutionBuilder.Build(), + _transientScopeAdapterReference, _scopeResolutionBuilder.Build()); } + + public void EnqueueRangedInstanceResolution(RangedInstanceResolutionsQueueItem item) => RangedInstanceResolutionsQueue.Enqueue(item); } \ No newline at end of file diff --git a/Main/ResolutionBuilding/ITransientScopeImplementationResolutionBuilder.cs b/Main/ResolutionBuilding/ITransientScopeImplementationResolutionBuilder.cs new file mode 100644 index 00000000..6c0ebd11 --- /dev/null +++ b/Main/ResolutionBuilding/ITransientScopeImplementationResolutionBuilder.cs @@ -0,0 +1,6 @@ +namespace MrMeeseeks.DIE.ResolutionBuilding; + +internal interface ITransientScopeImplementationResolutionBuilder +{ + void EnqueueRangedInstanceResolution(RangedInstanceResolutionsQueueItem item); +} \ No newline at end of file diff --git a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs index 8e5dfbe1..b0f01e7b 100644 --- a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs +++ b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs @@ -2,38 +2,6 @@ namespace MrMeeseeks.DIE.ResolutionBuilding; internal abstract class RangeResolutionBaseBuilder { - - internal abstract record InterfaceExtension( - INamedTypeSymbol InterfaceType) - { - internal string KeySuffix() => - this switch - { - DecorationInterfaceExtension decoration => $":::{decoration.ImplementationType.FullName()}", - CompositionInterfaceExtension composition => string.Join(":::", composition.ImplementationTypes.Select(i => i.FullName())), - _ => throw new ArgumentException() - }; - - internal string RangedNameSuffix() => - this switch - { - DecorationInterfaceExtension decoration => $"_{decoration.ImplementationType.Name}", - CompositionInterfaceExtension => "_Composite", - _ => throw new ArgumentException() - }; - } - internal record DecorationInterfaceExtension( - INamedTypeSymbol InterfaceType, - INamedTypeSymbol ImplementationType, - INamedTypeSymbol DecoratorType, - InterfaceResolution CurrentInterfaceResolution) - : InterfaceExtension(InterfaceType); - internal record CompositionInterfaceExtension( - INamedTypeSymbol InterfaceType, - IReadOnlyList ImplementationTypes, - INamedTypeSymbol CompositeType, - IReadOnlyList InterfaceResolutionComposition) - : InterfaceExtension(InterfaceType); protected readonly WellKnownTypes WellKnownTypes; protected readonly ITypeToImplementationsMapper TypeToImplementationsMapper; @@ -44,7 +12,7 @@ internal record CompositionInterfaceExtension( protected readonly IDictionary RangedInstanceReferenceResolutions = new Dictionary(); protected readonly HashSet<(RangedInstanceFunction, string)> RangedInstanceQueuedOverloads = new (); - protected readonly Queue<(RangedInstanceFunction, IReadOnlyList<(ITypeSymbol, ParameterResolution)>, INamedTypeSymbol, InterfaceExtension?)> RangedInstanceResolutionsQueue = new(); + protected readonly Queue RangedInstanceResolutionsQueue = new(); protected readonly List<(RangedInstanceFunction, RangedInstanceFunctionOverload)> RangedInstances = new (); protected readonly DisposableCollectionResolution DisposableCollectionResolution; @@ -86,19 +54,14 @@ protected RangeResolutionBaseBuilder( } protected abstract RangedInstanceReferenceResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter); + + protected abstract RangedInstanceReferenceResolution CreateTransientScopeInstanceReferenceResolution(ForConstructorParameter parameter); protected abstract ScopeRootResolution CreateScopeRootResolution( IScopeRootParameter parameter, INamedTypeSymbol rootType, DisposableCollectionResolution disposableCollectionResolution, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters); - - internal record Parameter; - - internal record SwitchTypeParameter( - ITypeSymbol Type, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentFuncParameters) - : Parameter; protected Resolvable SwitchType(SwitchTypeParameter parameter) { @@ -270,11 +233,6 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup return new ErrorTreeItem($"[{type.FullName()}] Couldn't process in resolution tree creation."); } - internal record SwitchInterfaceParameter( - ITypeSymbol Type, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentFuncParameters) - : Parameter; - private Resolvable SwitchInterface(SwitchInterfaceParameter parameter) { var (typeSymbol, currentParameters) = parameter; @@ -300,23 +258,6 @@ private Resolvable SwitchInterface(SwitchInterfaceParameter parameter) return SwitchInterfaceAfterScopeRoot(nextParameter); } - internal interface IScopeRootParameter - { - string KeySuffix(); - string RootFunctionSuffix(); - } - - internal record SwitchInterfaceAfterScopeRootParameter( - INamedTypeSymbol InterfaceType, - IList ImplementationTypes, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters) - : IScopeRootParameter - { - public string KeySuffix() => ":::InterfaceAfterRoot"; - - public string RootFunctionSuffix() => "_InterfaceAfterRoot"; - } - protected Resolvable SwitchInterfaceAfterScopeRoot( SwitchInterfaceAfterScopeRootParameter parameter) { @@ -356,12 +297,6 @@ protected Resolvable SwitchInterfaceAfterScopeRoot( currentParameters)); } - - internal record SwitchInterfaceForSpecificImplementationParameter( - INamedTypeSymbol InterfaceType, - INamedTypeSymbol ImplementationType, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters); - private Resolvable SwitchInterfaceForSpecificImplementation( SwitchInterfaceForSpecificImplementationParameter parameter) { @@ -384,29 +319,6 @@ private Resolvable SwitchInterfaceForSpecificImplementation( return CreateInterface(nextParameter); } - internal record CreateInterfaceParameter( - INamedTypeSymbol InterfaceType, - INamedTypeSymbol ImplementationType, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters) - : IScopeRootParameter - { - public virtual string KeySuffix() => ":::NormalInterface"; - - public virtual string RootFunctionSuffix() => "_NormalInterface"; - } - - internal record CreateInterfaceParameterAsComposition( - INamedTypeSymbol InterfaceType, - INamedTypeSymbol ImplementationType, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters, - CompositionInterfaceExtension Composition) - : CreateInterfaceParameter(InterfaceType, ImplementationType, CurrentParameters) - { - public override string KeySuffix() => ":::CompositeInterface"; - - public override string RootFunctionSuffix() => "_CompositeInterface"; - } - internal InterfaceResolution CreateInterface(CreateInterfaceParameter parameter) { var (interfaceType, implementationType, currentParameters) = parameter; @@ -450,10 +362,6 @@ internal InterfaceResolution CreateInterface(CreateInterfaceParameter parameter) return currentInterfaceResolution; } - internal record SwitchClassParameter( - ITypeSymbol TypeSymbol, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters); - protected Resolvable SwitchClass(SwitchClassParameter parameter) { var (typeSymbol, currentParameters) = parameter; @@ -480,28 +388,6 @@ protected Resolvable SwitchClass(SwitchClassParameter parameter) return SwitchImplementation(nextParameter); } - - internal record SwitchImplementationParameter( - INamedTypeSymbol ImplementationType, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters) - : IScopeRootParameter - { - public virtual string KeySuffix() => ":::Implementation"; - - public virtual string RootFunctionSuffix() => ""; - } - - internal record SwitchImplementationParameterWithDecoration( - INamedTypeSymbol ImplementationType, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters, - DecorationInterfaceExtension Decoration) - : SwitchImplementationParameter(ImplementationType, CurrentParameters); - - internal record SwitchImplementationParameterWithComposition( - INamedTypeSymbol ImplementationType, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters, - CompositionInterfaceExtension Composition) - : SwitchImplementationParameter(ImplementationType, CurrentParameters); protected Resolvable SwitchImplementation(SwitchImplementationParameter parameter) { @@ -530,33 +416,12 @@ protected Resolvable SwitchImplementation(SwitchImplementationParameter paramete return scopeLevel switch { ScopeLevel.Container => CreateContainerInstanceReferenceResolution(nextParameter), + ScopeLevel.TransientScope => CreateTransientScopeInstanceReferenceResolution(nextParameter), ScopeLevel.Scope => CreateScopeInstanceReferenceResolution(nextParameter), _ => CreateConstructorResolution(nextParameter) }; } - internal record ForConstructorParameter( - INamedTypeSymbol ImplementationType, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentFuncParameters); - - internal abstract record ForConstructorParameterWithInterfaceExtension( - INamedTypeSymbol ImplementationType, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentFuncParameters, - InterfaceExtension InterfaceExtension) - : ForConstructorParameter(ImplementationType, CurrentFuncParameters); - - internal record ForConstructorParameterWithDecoration( - INamedTypeSymbol ImplementationType, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentFuncParameters, - DecorationInterfaceExtension Decoration) - : ForConstructorParameterWithInterfaceExtension(ImplementationType, CurrentFuncParameters, Decoration); - - internal record ForConstructorParameterWithComposition( - INamedTypeSymbol ImplementationType, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentFuncParameters, - CompositionInterfaceExtension Composition) - : ForConstructorParameterWithInterfaceExtension(ImplementationType, CurrentFuncParameters, Composition); - protected Resolvable CreateConstructorResolution(ForConstructorParameter parameter) { var (implementationType, currentParameters) = parameter; @@ -682,7 +547,7 @@ protected RangedInstanceReferenceResolution CreateRangedInstanceReferenceResolut var tempParameter = currentParameters .Select(t => (t.Type, new ParameterResolution(RootReferenceGenerator.Generate(t.Type), t.Type.FullName()))) .ToList(); - RangedInstanceResolutionsQueue.Enqueue((function, tempParameter, implementationType, interfaceExtension)); + RangedInstanceResolutionsQueue.Enqueue(new RangedInstanceResolutionsQueueItem(function, tempParameter, implementationType, interfaceExtension)); RangedInstanceQueuedOverloads.Add((function, listedParameterTypes)); } diff --git a/Main/ResolutionBuilding/ResolutionDtos.cs b/Main/ResolutionBuilding/ResolutionDtos.cs new file mode 100644 index 00000000..9078a3f0 --- /dev/null +++ b/Main/ResolutionBuilding/ResolutionDtos.cs @@ -0,0 +1,147 @@ +namespace MrMeeseeks.DIE.ResolutionBuilding; + +internal abstract record InterfaceExtension( + INamedTypeSymbol InterfaceType) +{ + internal string KeySuffix() => + this switch + { + DecorationInterfaceExtension decoration => $":::{decoration.ImplementationType.FullName()}", + CompositionInterfaceExtension composition => string.Join(":::", composition.ImplementationTypes.Select(i => i.FullName())), + _ => throw new ArgumentException() + }; + + internal string RangedNameSuffix() => + this switch + { + DecorationInterfaceExtension decoration => $"_{decoration.ImplementationType.Name}", + CompositionInterfaceExtension => "_Composite", + _ => throw new ArgumentException() + }; +} + +internal record DecorationInterfaceExtension( + INamedTypeSymbol InterfaceType, + INamedTypeSymbol ImplementationType, + INamedTypeSymbol DecoratorType, + InterfaceResolution CurrentInterfaceResolution) + : InterfaceExtension(InterfaceType); +internal record CompositionInterfaceExtension( + INamedTypeSymbol InterfaceType, + IReadOnlyList ImplementationTypes, + INamedTypeSymbol CompositeType, + IReadOnlyList InterfaceResolutionComposition) + : InterfaceExtension(InterfaceType); + +internal record Parameter; + +internal record SwitchTypeParameter( + ITypeSymbol Type, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentFuncParameters) + : Parameter; + +internal record SwitchInterfaceParameter( + ITypeSymbol Type, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentFuncParameters) + : Parameter; + +internal interface IScopeRootParameter +{ + string KeySuffix(); + string RootFunctionSuffix(); +} + +internal record SwitchInterfaceAfterScopeRootParameter( + INamedTypeSymbol InterfaceType, + IList ImplementationTypes, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters) + : IScopeRootParameter +{ + public string KeySuffix() => ":::InterfaceAfterRoot"; + + public string RootFunctionSuffix() => "_InterfaceAfterRoot"; +} + + +internal record SwitchInterfaceForSpecificImplementationParameter( + INamedTypeSymbol InterfaceType, + INamedTypeSymbol ImplementationType, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters); + +internal record CreateInterfaceParameter( + INamedTypeSymbol InterfaceType, + INamedTypeSymbol ImplementationType, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters) + : IScopeRootParameter +{ + public virtual string KeySuffix() => ":::NormalInterface"; + + public virtual string RootFunctionSuffix() => "_NormalInterface"; +} + +internal record CreateInterfaceParameterAsComposition( + INamedTypeSymbol InterfaceType, + INamedTypeSymbol ImplementationType, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters, + CompositionInterfaceExtension Composition) + : CreateInterfaceParameter(InterfaceType, ImplementationType, CurrentParameters) +{ + public override string KeySuffix() => ":::CompositeInterface"; + + public override string RootFunctionSuffix() => "_CompositeInterface"; +} + +internal record SwitchClassParameter( + ITypeSymbol TypeSymbol, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters); + +internal record SwitchImplementationParameter( + INamedTypeSymbol ImplementationType, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters) + : IScopeRootParameter +{ + public virtual string KeySuffix() => ":::Implementation"; + + public virtual string RootFunctionSuffix() => ""; +} + +internal record SwitchImplementationParameterWithDecoration( + INamedTypeSymbol ImplementationType, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters, + DecorationInterfaceExtension Decoration) + : SwitchImplementationParameter(ImplementationType, CurrentParameters); + +internal record SwitchImplementationParameterWithComposition( + INamedTypeSymbol ImplementationType, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters, + CompositionInterfaceExtension Composition) + : SwitchImplementationParameter(ImplementationType, CurrentParameters); + +internal record ForConstructorParameter( + INamedTypeSymbol ImplementationType, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentFuncParameters); + +internal abstract record ForConstructorParameterWithInterfaceExtension( + INamedTypeSymbol ImplementationType, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentFuncParameters, + InterfaceExtension InterfaceExtension) + : ForConstructorParameter(ImplementationType, CurrentFuncParameters); + +internal record ForConstructorParameterWithDecoration( + INamedTypeSymbol ImplementationType, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentFuncParameters, + DecorationInterfaceExtension Decoration) + : ForConstructorParameterWithInterfaceExtension(ImplementationType, CurrentFuncParameters, Decoration); + +internal record ForConstructorParameterWithComposition( + INamedTypeSymbol ImplementationType, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentFuncParameters, + CompositionInterfaceExtension Composition) + : ForConstructorParameterWithInterfaceExtension(ImplementationType, CurrentFuncParameters, Composition); + +//(RangedInstanceFunction, IReadOnlyList<(ITypeSymbol, ParameterResolution)>, INamedTypeSymbol, InterfaceExtension?) +internal record RangedInstanceResolutionsQueueItem( + RangedInstanceFunction Function, + IReadOnlyList<(ITypeSymbol, ParameterResolution)> Parameters, + INamedTypeSymbol ImplementationType, + InterfaceExtension? InterfaceExtension); \ No newline at end of file diff --git a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs index 8ff35433..0c51700b 100644 --- a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs @@ -5,7 +5,7 @@ internal interface IScopeResolutionBuilder bool HasWorkToDo { get; } ScopeRootResolution AddCreateResolveFunction( - RangeResolutionBaseBuilder.IScopeRootParameter parameter, + IScopeRootParameter parameter, INamedTypeSymbol rootType, string containerInstanceScopeReference, DisposableCollectionResolution disposableCollectionResolution, @@ -19,9 +19,12 @@ ScopeRootResolution AddCreateResolveFunction( internal class ScopeResolutionBuilder : RangeResolutionBaseBuilder, IScopeResolutionBuilder { private readonly IContainerResolutionBuilder _containerResolutionBuilder; + private readonly ITransientScopeInterfaceResolutionBuilder _transientScopeInterfaceResolutionBuilder; private readonly List _rootResolutions = new (); private readonly string _containerReference; private readonly string _containerParameterReference; + private readonly string _transientScopeReference; + private readonly string _transientScopeParameterReference; private readonly Dictionary _scopeRootFunctionResolutions = new (); private readonly HashSet<(ScopeRootFunction, string)> _scopeRootFunctionQueuedOverloads = new (); @@ -29,7 +32,8 @@ internal class ScopeResolutionBuilder : RangeResolutionBaseBuilder, IScopeResolu internal ScopeResolutionBuilder( // parameter - IContainerResolutionBuilder containerResolutionBuilder, + IContainerResolutionBuilder containerResolutionBuilder, + ITransientScopeInterfaceResolutionBuilder transientScopeInterfaceResolutionBuilder, // dependencies WellKnownTypes wellKnownTypes, @@ -48,15 +52,18 @@ internal ScopeResolutionBuilder( userProvidedScopeElements) { _containerResolutionBuilder = containerResolutionBuilder; + _transientScopeInterfaceResolutionBuilder = transientScopeInterfaceResolutionBuilder; _containerReference = RootReferenceGenerator.Generate("_container"); _containerParameterReference = RootReferenceGenerator.Generate("container"); + _transientScopeReference = RootReferenceGenerator.Generate("_transientScope"); + _transientScopeParameterReference = RootReferenceGenerator.Generate("_transientScopeParameter"); } - protected override RangedInstanceReferenceResolution CreateContainerInstanceReferenceResolution( - ForConstructorParameter parameter) => - _containerResolutionBuilder.CreateContainerInstanceReferenceResolution( - parameter, - _containerReference); + protected override RangedInstanceReferenceResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter) => + _containerResolutionBuilder.CreateContainerInstanceReferenceResolution(parameter, _containerReference); + + protected override RangedInstanceReferenceResolution CreateTransientScopeInstanceReferenceResolution(ForConstructorParameter parameter) => + _transientScopeInterfaceResolutionBuilder.CreateTransientScopeInstanceReferenceResolution(parameter, _transientScopeReference); protected override ScopeRootResolution CreateScopeRootResolution( IScopeRootParameter parameter, @@ -154,5 +161,7 @@ public ScopeResolution Build() => .ToList(), _containerReference, _containerParameterReference, + _transientScopeReference, + _transientScopeParameterReference, Name); } \ No newline at end of file diff --git a/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs b/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs new file mode 100644 index 00000000..898f9123 --- /dev/null +++ b/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs @@ -0,0 +1,108 @@ +namespace MrMeeseeks.DIE.ResolutionBuilding; + +internal interface ITransientScopeInterfaceResolutionBuilder +{ + void AddImplementation(ITransientScopeImplementationResolutionBuilder implementation); + RangedInstanceReferenceResolution CreateTransientScopeInstanceReferenceResolution( + ForConstructorParameter parameter, + string containerReference); + + TransientScopeInterfaceResolution Build(); +} + +internal class TransientScopeInterfaceResolutionBuilder : ITransientScopeInterfaceResolutionBuilder +{ + private readonly IReferenceGenerator _rootReferenceGenerator; + private readonly IDictionary _rangedInstanceReferenceResolutions = + new Dictionary(); + private readonly HashSet<(RangedInstanceFunction, string)> _rangedInstanceQueuedOverloads = new (); + + private readonly HashSet _pastQueuedItems = new(); + private readonly IList _implementations = + new List(); + + private readonly string _name; + private readonly string _containerAdapterName; + + + public TransientScopeInterfaceResolutionBuilder( + IReferenceGeneratorFactory referenceGeneratorFactory) + { + _rootReferenceGenerator = referenceGeneratorFactory.Create(); + + _name = _rootReferenceGenerator.Generate("ITransientScope"); + + _containerAdapterName = _rootReferenceGenerator.Generate("ContainerTransientScopeAdapter"); + } + + + public void AddImplementation(ITransientScopeImplementationResolutionBuilder implementation) + { + foreach (var item in _pastQueuedItems) + implementation.EnqueueRangedInstanceResolution(item); + + _implementations.Add(implementation); + } + + public RangedInstanceReferenceResolution CreateTransientScopeInstanceReferenceResolution(ForConstructorParameter parameter, string containerReference) => + CreateRangedInstanceReferenceResolution( + parameter, + "TransientScope", + containerReference); + + public TransientScopeInterfaceResolution Build() => new( + _pastQueuedItems + .Select(i => new TransientScopeInstanceInterfaceFunction( + i.Parameters.Select(p => new ParameterResolution(p.Item2.Reference, p.Item2.TypeFullName)).ToList(), + i.Function.Reference, + i.Function.TypeFullName)) + .ToList(), + _name, + _containerAdapterName); + + private RangedInstanceReferenceResolution CreateRangedInstanceReferenceResolution( + ForConstructorParameter parameter, + string label, + string owningObjectReference) + { + var (implementationType, currentParameters) = parameter; + InterfaceExtension? interfaceExtension = parameter switch + { + ForConstructorParameterWithComposition withComposition => withComposition.Composition, + ForConstructorParameterWithDecoration withDecoration => withDecoration.Decoration, + _ => null + }; + var key = $"{implementationType.FullName()}{interfaceExtension?.KeySuffix() ?? ""}"; + if (!_rangedInstanceReferenceResolutions.TryGetValue( + key, + out RangedInstanceFunction function)) + { + var decorationSuffix = interfaceExtension?.RangedNameSuffix() ?? ""; + function = new RangedInstanceFunction( + _rootReferenceGenerator.Generate($"Get{label}Instance", implementationType, decorationSuffix), + implementationType.FullName(), + _rootReferenceGenerator.Generate($"_{label.ToLower()}InstanceField", implementationType, decorationSuffix), + _rootReferenceGenerator.Generate($"_{label.ToLower()}InstanceLock{decorationSuffix}")); + _rangedInstanceReferenceResolutions[key] = function; + } + + var listedParameterTypes = string.Join(",", currentParameters.Select(p => p.Item2.TypeFullName)); + if (!_rangedInstanceQueuedOverloads.Contains((function, listedParameterTypes))) + { + var tempParameter = currentParameters + .Select(t => (t.Type, new ParameterResolution(_rootReferenceGenerator.Generate(t.Type), t.Type.FullName()))) + .ToList(); + var queueItem = new RangedInstanceResolutionsQueueItem(function, tempParameter, implementationType, interfaceExtension); + foreach (var implementation in _implementations) + implementation.EnqueueRangedInstanceResolution(queueItem); + _pastQueuedItems.Add(queueItem); + _rangedInstanceQueuedOverloads.Add((function, listedParameterTypes)); + } + + return new RangedInstanceReferenceResolution( + _rootReferenceGenerator.Generate(implementationType), + function, + currentParameters.Select(t => t.Resolution).ToList(), + owningObjectReference); + } +} \ No newline at end of file diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index 267881bd..91fb0763 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -65,6 +65,11 @@ internal record RangedInstanceFunction( string FieldReference, string LockReference); +internal record TransientScopeInstanceInterfaceFunction( + IReadOnlyList Parameter, + string Reference, + string TypeFullName); + internal record RangedInstanceFunctionOverload( Resolvable Dependency, IReadOnlyList Parameter); @@ -108,12 +113,19 @@ internal abstract record RangeResolution( DisposalHandling DisposalHandling, IReadOnlyList RangedInstances) : ResolutionTreeItem; +internal record TransientScopeInterfaceResolution( + IReadOnlyList Functions, + string Name, + string ContainerAdapterName); + internal record ScopeResolution( IReadOnlyList RootResolutions, DisposalHandling DisposalHandling, IReadOnlyList RangedInstances, string ContainerReference, string ContainerParameterReference, + string TransientScopeReference, + string TransientScopeParameterReference, string Name) : RangeResolution(RootResolutions, DisposalHandling, RangedInstances); @@ -121,6 +133,8 @@ internal record ContainerResolution( IReadOnlyList RootResolutions, DisposalHandling DisposalHandling, IReadOnlyList RangedInstances, + TransientScopeInterfaceResolution TransientScopeInterface, + string TransientScopeAdapterReference, ScopeResolution DefaultScope) : RangeResolution(RootResolutions, DisposalHandling, RangedInstances); diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index 1423d807..54c0ee70 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -40,6 +40,8 @@ public void Execute(GeneratorExecutionContext context) IContainerResolutionBuilder ResolutionTreeFactory(IContainerInfo ci) => new ContainerResolutionBuilder( ci, + + new TransientScopeInterfaceResolutionBuilder(referenceGeneratorFactory), typeToImplementationMapper, referenceGeneratorFactory, checkTypeProperties, @@ -47,8 +49,10 @@ public void Execute(GeneratorExecutionContext context) wellKnownTypes, ScopeResolutionBuilderFactory, new UserProvidedScopeElements(ci.ContainerType)); - IScopeResolutionBuilder ScopeResolutionBuilderFactory(IContainerResolutionBuilder containerBuilder) => new ScopeResolutionBuilder( + IScopeResolutionBuilder ScopeResolutionBuilderFactory(IContainerResolutionBuilder containerBuilder, ITransientScopeInterfaceResolutionBuilder transientScopeInterfaceResolutionBuilder) => new ScopeResolutionBuilder( containerBuilder, + transientScopeInterfaceResolutionBuilder, + wellKnownTypes, typeToImplementationMapper, referenceGeneratorFactory, @@ -69,9 +73,11 @@ IContainerCodeBuilder ContainerCodeBuilderFactory( IScopeCodeBuilder ScopeCodeBuilderFactory( IContainerInfo containerInfo, - ScopeResolution containerResolution) => new ScopeCodeBuilder( + ScopeResolution containerResolution, + TransientScopeInterfaceResolution transientScopeInterfaceResolution) => new ScopeCodeBuilder( containerInfo, containerResolution, + transientScopeInterfaceResolution, wellKnownTypes); } } \ No newline at end of file diff --git a/Main/TypesFromTypeAggregatingAttributes.cs b/Main/TypesFromTypeAggregatingAttributes.cs index eacda2b5..d3e702e7 100644 --- a/Main/TypesFromTypeAggregatingAttributes.cs +++ b/Main/TypesFromTypeAggregatingAttributes.cs @@ -6,6 +6,7 @@ internal interface ITypesFromTypeAggregatingAttributes IReadOnlyList Implementation { get; } IReadOnlyList Transient { get; } IReadOnlyList ContainerInstance { get; } + IReadOnlyList TransientScopeInstance { get; } IReadOnlyList ScopeInstance { get; } IReadOnlyList ScopeRoot { get; } IReadOnlyList Decorator { get; } @@ -22,6 +23,7 @@ internal TypesFromTypeAggregatingAttributes( Implementation = GetTypesFromAttribute(wellKnownTypes.ImplementationAggregationAttribute).ToList(); Transient = GetTypesFromAttribute(wellKnownTypes.TransientAggregationAttribute).ToList(); ContainerInstance = GetTypesFromAttribute(wellKnownTypes.ContainerInstanceAggregationAttribute).ToList(); + TransientScopeInstance = GetTypesFromAttribute(wellKnownTypes.TransientScopeInstanceAggregationAttribute).ToList(); ScopeInstance = GetTypesFromAttribute(wellKnownTypes.ScopeInstanceAggregationAttribute).ToList(); ScopeRoot = GetTypesFromAttribute(wellKnownTypes.ScopeRootAggregationAttribute).ToList(); Decorator = GetTypesFromAttribute(wellKnownTypes.DecoratorAggregationAttribute).ToList(); @@ -64,6 +66,7 @@ bool CheckValidType(TypedConstant typedConstant, out INamedTypeSymbol type) public IReadOnlyList Implementation { get; } public IReadOnlyList Transient { get; } public IReadOnlyList ContainerInstance { get; } + public IReadOnlyList TransientScopeInstance { get; } public IReadOnlyList ScopeInstance { get; } public IReadOnlyList ScopeRoot { get; } public IReadOnlyList Decorator { get; } diff --git a/Main/WellKnownTypes.cs b/Main/WellKnownTypes.cs index f14a62d9..519d75ee 100644 --- a/Main/WellKnownTypes.cs +++ b/Main/WellKnownTypes.cs @@ -7,6 +7,7 @@ internal record WellKnownTypes( INamedTypeSymbol ImplementationAggregationAttribute, INamedTypeSymbol TransientAggregationAttribute, INamedTypeSymbol ContainerInstanceAggregationAttribute, + INamedTypeSymbol TransientScopeInstanceAggregationAttribute, INamedTypeSymbol ScopeInstanceAggregationAttribute, INamedTypeSymbol ScopeRootAggregationAttribute, INamedTypeSymbol DecoratorAggregationAttribute, @@ -66,6 +67,9 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK var containerInstanceAggregationAttribute = compilation .GetTypeByMetadataName(typeof(ContainerInstanceAggregationAttribute).FullName ?? ""); + var transientScopeInstanceAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(TransientScopeInstanceAggregationAttribute).FullName ?? ""); + var scopeInstanceAggregationAttribute = compilation .GetTypeByMetadataName(typeof(ScopeInstanceAggregationAttribute).FullName ?? ""); @@ -90,6 +94,7 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK || implementationAggregationAttribute is null || transientAggregationAttribute is null || containerInstanceAggregationAttribute is null + || transientScopeInstanceAggregationAttribute is null || scopeInstanceAggregationAttribute is null || scopeRootAggregationAttribute is null || decoratorAggregationAttribute is null @@ -123,6 +128,7 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK ImplementationAggregationAttribute: implementationAggregationAttribute, TransientAggregationAttribute: transientAggregationAttribute, ContainerInstanceAggregationAttribute: containerInstanceAggregationAttribute, + TransientScopeInstanceAggregationAttribute: transientScopeInstanceAggregationAttribute, ScopeInstanceAggregationAttribute: scopeInstanceAggregationAttribute, ScopeRootAggregationAttribute: scopeRootAggregationAttribute, DecoratorAggregationAttribute: decoratorAggregationAttribute, diff --git a/Sample/Container.cs b/Sample/Container.cs index a34879aa..0277af18 100644 --- a/Sample/Container.cs +++ b/Sample/Container.cs @@ -2,6 +2,7 @@ using MrMeeseeks.DIE.Sample; [assembly:ContainerInstanceAggregation(typeof(IContainerInstance))] +[assembly:TransientScopeInstanceAggregation(typeof(ITransientScopeInstance))] [assembly:ScopeInstanceAggregation(typeof(IScopeInstance))] [assembly:ScopeRootAggregation(typeof(IScopeRoot))] [assembly:TransientAggregation(typeof(ITransient))] diff --git a/Sample/MarkerInterfaces.cs b/Sample/MarkerInterfaces.cs index ea36dee9..13db59d5 100644 --- a/Sample/MarkerInterfaces.cs +++ b/Sample/MarkerInterfaces.cs @@ -1,6 +1,7 @@ namespace MrMeeseeks.DIE.Sample; public interface IContainerInstance { } +public interface ITransientScopeInstance { } public interface IScopeInstance { } public interface IScopeRoot { } public interface ITransient { } diff --git a/Test/AssemblyInfo.cs b/Test/AssemblyInfo.cs index a14d9c8c..c7c15dad 100644 --- a/Test/AssemblyInfo.cs +++ b/Test/AssemblyInfo.cs @@ -2,6 +2,7 @@ using MrMeeseeks.DIE.Test; [assembly:ContainerInstanceAggregation(typeof(IContainerInstance))] +[assembly:TransientScopeInstanceAggregation(typeof(ITransientScopeInstance))] [assembly:ScopeInstanceAggregation(typeof(IScopeInstance))] [assembly:ScopeRootAggregation(typeof(IScopeRoot))] [assembly:TransientAggregation(typeof(ITransient))] diff --git a/Test/MarkerInterfaces.cs b/Test/MarkerInterfaces.cs index d77894cb..36d41dd5 100644 --- a/Test/MarkerInterfaces.cs +++ b/Test/MarkerInterfaces.cs @@ -1,6 +1,7 @@ namespace MrMeeseeks.DIE.Test; public interface IContainerInstance { } +public interface ITransientScopeInstance { } public interface IScopeInstance { } public interface IScopeRoot { } public interface ITransient { } diff --git a/Test/TransientScopeInstanceTests.cs b/Test/TransientScopeInstanceTests.cs new file mode 100644 index 00000000..74df03fb --- /dev/null +++ b/Test/TransientScopeInstanceTests.cs @@ -0,0 +1,65 @@ +using Xunit; + +namespace MrMeeseeks.DIE.Test; + +internal interface ITransientScopeInstanceInner {} +internal class TransientScopeInstance : ITransientScopeInstanceInner, ITransientScopeInstance {} + +internal partial class TransientScopeInstanceContainer : IContainer +{ + +} + +public partial class TransientScopeInstanceTests +{ + [Fact] + public void InContainer() + { + using var container = new TransientScopeInstanceContainer(); + var _ = ((IContainer) container).Resolve(); + } +} + +internal interface IScopeWithTransientScopeInstance {} + +internal class ScopeWithTransientScopeInstance : IScopeWithTransientScopeInstance, IScopeRoot +{ + public ScopeWithTransientScopeInstance(ITransientScopeInstanceInner _) {} +} + +internal partial class TransientScopeInstanceContainer : IContainer +{ + +} + +public partial class TransientScopeInstanceTests +{ + [Fact] + public void InScope() + { + using var container = new TransientScopeInstanceContainer(); + var _ = ((IContainer) container).Resolve(); + } +} + +internal interface IScopeWithTransientScopeInstanceAbove {} + +internal class ScopeWithTransientScopeInstanceAbove : IScopeWithTransientScopeInstanceAbove, IScopeRoot +{ + public ScopeWithTransientScopeInstanceAbove(IScopeWithTransientScopeInstance _) {} +} + +internal partial class TransientScopeInstanceContainer : IContainer +{ + +} + +public partial class TransientScopeInstanceTests +{ + [Fact] + public void InScopeInScope() + { + using var container = new TransientScopeInstanceContainer(); + var _ = ((IContainer) container).Resolve(); + } +} \ No newline at end of file From 90823cb0d6b7210943280519469f62e98adc9234 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Wed, 19 Jan 2022 16:30:54 +0100 Subject: [PATCH 041/162] Implemented TransientScopes but with missing details (disposal) --- Main/Attributes.cs | 6 + Main/CheckTypeProperties.cs | 11 +- Main/CodeBuilding/ContainerCodeBuilder.cs | 13 +- Main/CodeBuilding/ContainerGenerator.cs | 12 +- Main/CodeBuilding/RangeCodeBaseBuilder.cs | 20 +- Main/CodeBuilding/ScopeCodeBuilder.cs | 7 +- .../CodeBuilding/TransientScopeCodeBuilder.cs | 51 +++++ .../ContainerResolutionBuilder.cs | 26 ++- .../RangeResolutionBaseBuilder.cs | 62 +++++-- .../ScopeResolutionBuilder.cs | 21 ++- .../TransientScopeResolutionBuilder.cs | 175 ++++++++++++++++++ Main/ResolutionTreeItem.cs | 21 +++ Main/SourceGenerator.cs | 29 ++- Main/TypesFromTypeAggregatingAttributes.cs | 3 + Main/WellKnownTypes.cs | 6 + Sample/Container.cs | 1 + Sample/Context.cs | 37 +--- Sample/MarkerInterfaces.cs | 1 + Sample/Program.cs | 4 +- Test/AssemblyInfo.cs | 1 + Test/MarkerInterfaces.cs | 1 + Test/TransientScopeInstanceTests.cs | 22 +++ 22 files changed, 451 insertions(+), 79 deletions(-) create mode 100644 Main/CodeBuilding/TransientScopeCodeBuilder.cs create mode 100644 Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs diff --git a/Main/Attributes.cs b/Main/Attributes.cs index d07b3cd3..ea3c0a89 100644 --- a/Main/Attributes.cs +++ b/Main/Attributes.cs @@ -43,6 +43,12 @@ public class ScopeInstanceAggregationAttribute : Attribute public ScopeInstanceAggregationAttribute(params Type[] types) {} } +[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] +public class TransientScopeRootAggregationAttribute : Attribute +{ + public TransientScopeRootAggregationAttribute(params Type[] types) {} +} + [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] public class ScopeRootAggregationAttribute : Attribute { diff --git a/Main/CheckTypeProperties.cs b/Main/CheckTypeProperties.cs index 9f76d993..1cdb7ce2 100644 --- a/Main/CheckTypeProperties.cs +++ b/Main/CheckTypeProperties.cs @@ -11,7 +11,7 @@ internal enum ScopeLevel internal interface ICheckTypeProperties { bool ShouldBeManaged(INamedTypeSymbol implementationType); - bool ShouldBeScopeRoot(INamedTypeSymbol implementationType); + ScopeLevel ShouldBeScopeRoot(INamedTypeSymbol implementationType); bool ShouldBeComposite(INamedTypeSymbol interfaceType); ScopeLevel GetScopeLevelFor(INamedTypeSymbol implementationType); INamedTypeSymbol GetCompositeFor(INamedTypeSymbol interfaceType); @@ -25,6 +25,7 @@ internal class CheckTypeProperties : ICheckTypeProperties private readonly IImmutableSet _containerInstanceTypes; private readonly IImmutableSet _transientScopeInstanceTypes; private readonly IImmutableSet _scopeInstanceTypes; + private readonly IImmutableSet _transientScopeRootTypes; private readonly IImmutableSet _scopeRootTypes; private readonly IImmutableSet _compositeTypes; private readonly Dictionary _interfaceToComposite; @@ -40,6 +41,7 @@ internal CheckTypeProperties( _containerInstanceTypes = getSetOfTypesWithProperties.Get(typesFromTypeAggregatingAttributes.ContainerInstance); _transientScopeInstanceTypes = getSetOfTypesWithProperties.Get(typesFromTypeAggregatingAttributes.TransientScopeInstance); _scopeInstanceTypes = getSetOfTypesWithProperties.Get(typesFromTypeAggregatingAttributes.ScopeInstance); + _transientScopeRootTypes = getSetOfTypesWithProperties.Get(typesFromTypeAggregatingAttributes.TransientScopeRoot); _scopeRootTypes = getSetOfTypesWithProperties.Get(typesFromTypeAggregatingAttributes.ScopeRoot); _compositeTypes = getSetOfTypesWithProperties.Get(typesFromTypeAggregatingAttributes.Composite); _interfaceToComposite = _compositeTypes @@ -102,7 +104,12 @@ internal CheckTypeProperties( } public bool ShouldBeManaged(INamedTypeSymbol implementationType) => !_transientTypes.Contains(implementationType); - public bool ShouldBeScopeRoot(INamedTypeSymbol implementationType) => _scopeRootTypes.Contains(implementationType); + public ScopeLevel ShouldBeScopeRoot(INamedTypeSymbol implementationType) + { + if (_transientScopeRootTypes.Contains(implementationType)) return ScopeLevel.TransientScope; + return _scopeRootTypes.Contains(implementationType) ? ScopeLevel.Scope : ScopeLevel.None; + } + public bool ShouldBeComposite(INamedTypeSymbol interfaceType) => _interfaceToComposite.ContainsKey(interfaceType); public ScopeLevel GetScopeLevelFor(INamedTypeSymbol implementationType) { diff --git a/Main/CodeBuilding/ContainerCodeBuilder.cs b/Main/CodeBuilding/ContainerCodeBuilder.cs index c2f522f0..fa42da86 100644 --- a/Main/CodeBuilding/ContainerCodeBuilder.cs +++ b/Main/CodeBuilding/ContainerCodeBuilder.cs @@ -9,10 +9,9 @@ internal class ContainerCodeBuilder : RangeCodeBaseBuilder, IContainerCodeBuilde { private readonly IContainerInfo _containerInfo; private readonly ContainerResolution _containerResolution; + private readonly ITransientScopeCodeBuilder _defaultTransientScopeCodeBuilder; private readonly IScopeCodeBuilder _defaultScopeBuilder; - protected override string TransientScopeReference { get; } - public override StringBuilder Build(StringBuilder stringBuilder) { stringBuilder = stringBuilder @@ -51,9 +50,11 @@ public override StringBuilder Build(StringBuilder stringBuilder) stringBuilder = stringBuilder .AppendLine($"}}") - .AppendLine($"private {_containerResolution.TransientScopeInterface.ContainerAdapterName} _{TransientScopeReference};") - .AppendLine($"private {_containerResolution.TransientScopeInterface.ContainerAdapterName} {TransientScopeReference} => _{TransientScopeReference} ??= new {_containerResolution.TransientScopeInterface.ContainerAdapterName}(this);"); + .AppendLine($"private {_containerResolution.TransientScopeInterface.ContainerAdapterName} _{_containerResolution.TransientScopeAdapterReference};") + .AppendLine($"private {_containerResolution.TransientScopeInterface.ContainerAdapterName} {_containerResolution.TransientScopeAdapterReference} => _{_containerResolution.TransientScopeAdapterReference} ??= new {_containerResolution.TransientScopeInterface.ContainerAdapterName}(this);"); + stringBuilder = _defaultTransientScopeCodeBuilder.Build(stringBuilder); + stringBuilder = _defaultScopeBuilder.Build(stringBuilder); return stringBuilder @@ -65,6 +66,7 @@ public ContainerCodeBuilder( // parameter IContainerInfo containerInfo, ContainerResolution containerResolution, + ITransientScopeCodeBuilder defaultTransientScopeCodeBuilder, IScopeCodeBuilder defaultScopeBuilder, // dependencies @@ -73,8 +75,7 @@ public ContainerCodeBuilder( { _containerInfo = containerInfo; _containerResolution = containerResolution; + _defaultTransientScopeCodeBuilder = defaultTransientScopeCodeBuilder; _defaultScopeBuilder = defaultScopeBuilder; - - TransientScopeReference = containerResolution.TransientScopeAdapterReference; } } \ No newline at end of file diff --git a/Main/CodeBuilding/ContainerGenerator.cs b/Main/CodeBuilding/ContainerGenerator.cs index 01bb48f7..3a5d94bc 100644 --- a/Main/CodeBuilding/ContainerGenerator.cs +++ b/Main/CodeBuilding/ContainerGenerator.cs @@ -12,18 +12,21 @@ internal class ContainerGenerator : IContainerGenerator { private readonly GeneratorExecutionContext _context; private readonly IDiagLogger _diagLogger; - private readonly Func _containerCodeBuilderFactory; + private readonly Func _containerCodeBuilderFactory; + private readonly Func _transientScopeCodeBuilderFactory; private readonly Func _scopeCodeBuilderFactory; internal ContainerGenerator( GeneratorExecutionContext context, IDiagLogger diagLogger, - Func containerCodeBuilderFactory, + Func containerCodeBuilderFactory, + Func transientScopeCodeBuilderFactory, Func scopeCodeBuilderFactory) { _context = context; _diagLogger = diagLogger; _containerCodeBuilderFactory = containerCodeBuilderFactory; + _transientScopeCodeBuilderFactory = transientScopeCodeBuilderFactory; _scopeCodeBuilderFactory = scopeCodeBuilderFactory; } @@ -35,7 +38,10 @@ public void Generate(IContainerInfo containerInfo, ContainerResolution container return; } - var containerCodeBuilder = _containerCodeBuilderFactory(containerInfo, containerResolution, + var containerCodeBuilder = _containerCodeBuilderFactory( + containerInfo, + containerResolution, + _transientScopeCodeBuilderFactory(containerInfo, containerResolution.DefaultTransientScope), _scopeCodeBuilderFactory(containerInfo, containerResolution.DefaultScope, containerResolution.TransientScopeInterface)); var generatedContainer = containerCodeBuilder.Build(new StringBuilder()); diff --git a/Main/CodeBuilding/RangeCodeBaseBuilder.cs b/Main/CodeBuilding/RangeCodeBaseBuilder.cs index 6241633a..cc7b6d98 100644 --- a/Main/CodeBuilding/RangeCodeBaseBuilder.cs +++ b/Main/CodeBuilding/RangeCodeBaseBuilder.cs @@ -16,8 +16,6 @@ internal RangeCodeBaseBuilder( WellKnownTypes = wellKnownTypes; } - protected abstract string TransientScopeReference { get; } - protected StringBuilder GenerateResolutionRange( StringBuilder stringBuilder, RangeResolution rangeResolution) @@ -111,7 +109,12 @@ protected StringBuilder GenerateFields( { switch (resolution) { - case ScopeRootResolution(var reference, var typeFullName, var scopeReference, var scopeTypeFullName, _, _, _, _): + case TransientScopeRootResolution(var reference, var typeFullName, var transientScopeReference, var transientScopeTypeFullName, _, _, _, _): + stringBuilder = stringBuilder + .AppendLine($"{transientScopeTypeFullName} {transientScopeReference};") + .AppendLine($"{typeFullName} {reference};"); + break; + case ScopeRootResolution(var reference, var typeFullName, var scopeReference, var scopeTypeFullName, _, _, _, _, _): stringBuilder = stringBuilder .AppendLine($"{scopeTypeFullName} {scopeReference};") .AppendLine($"{typeFullName} {reference};"); @@ -164,9 +167,16 @@ protected StringBuilder GenerateResolutions( { switch (resolution) { - case ScopeRootResolution(var reference, var typeFullName, var scopeReference, var scopeTypeFullName, var containerInstanceScopeReference, var parameter, var (disposableCollectionReference, _, _, _, _), var (createFunctionReference, _)): + case TransientScopeRootResolution(var reference, var typeFullName, var transientScopeReference, var transientScopeTypeFullName, var containerInstanceScopeReference, var parameter, var (disposableCollectionReference, _, _, _, _), var (createFunctionReference, _)): + stringBuilder = stringBuilder + .AppendLine($"{transientScopeReference} = new {transientScopeTypeFullName}({containerInstanceScopeReference});") + .AppendLine($"{disposableCollectionReference}.Add(({WellKnownTypes.Disposable.FullName()}) {transientScopeReference});") + .AppendLine($"{reference} = ({typeFullName}) {transientScopeReference}.{createFunctionReference}({string.Join(", ", parameter.Select(p => p.Reference))});"); + IsDisposalHandlingRequired = true; + break; + case ScopeRootResolution(var reference, var typeFullName, var scopeReference, var scopeTypeFullName, var containerInstanceScopeReference, var transientInstanceScopeReference, var parameter, var (disposableCollectionReference, _, _, _, _), var (createFunctionReference, _)): stringBuilder = stringBuilder - .AppendLine($"{scopeReference} = new {scopeTypeFullName}({containerInstanceScopeReference}, {TransientScopeReference});") + .AppendLine($"{scopeReference} = new {scopeTypeFullName}({containerInstanceScopeReference}, {transientInstanceScopeReference});") .AppendLine($"{disposableCollectionReference}.Add(({WellKnownTypes.Disposable.FullName()}) {scopeReference});") .AppendLine($"{reference} = ({typeFullName}) {scopeReference}.{createFunctionReference}({string.Join(", ", parameter.Select(p => p.Reference))});"); IsDisposalHandlingRequired = true; diff --git a/Main/CodeBuilding/ScopeCodeBuilder.cs b/Main/CodeBuilding/ScopeCodeBuilder.cs index d084d067..6a83dcb4 100644 --- a/Main/CodeBuilding/ScopeCodeBuilder.cs +++ b/Main/CodeBuilding/ScopeCodeBuilder.cs @@ -11,8 +11,6 @@ internal class ScopeCodeBuilder : RangeCodeBaseBuilder, IScopeCodeBuilder private readonly ScopeResolution _scopeResolution; private readonly TransientScopeInterfaceResolution _transientScopeInterfaceResolution; - protected override string TransientScopeReference { get; } - public override StringBuilder Build(StringBuilder stringBuilder) { if (!_scopeResolution.RootResolutions.Any() && !_scopeResolution.RangedInstances.Any()) @@ -23,13 +21,13 @@ public override StringBuilder Build(StringBuilder stringBuilder) $"internal partial class {_scopeResolution.Name} : {WellKnownTypes.Disposable.FullName()}") .AppendLine($"{{") .AppendLine($"private readonly {_containerInfo.FullName} {_scopeResolution.ContainerReference};") - .AppendLine($"private readonly {_transientScopeInterfaceResolution.Name} {TransientScopeReference};") + .AppendLine($"private readonly {_transientScopeInterfaceResolution.Name} {_scopeResolution.TransientScopeReference};") .AppendLine($"internal {_scopeResolution.Name}(") .AppendLine($"{_containerInfo.FullName} {_scopeResolution.ContainerParameterReference},") .AppendLine($"{_transientScopeInterfaceResolution.Name} {_scopeResolution.TransientScopeParameterReference})") .AppendLine($"{{") .AppendLine($"{_scopeResolution.ContainerReference} = {_scopeResolution.ContainerParameterReference};") - .AppendLine($"{TransientScopeReference} = {_scopeResolution.TransientScopeParameterReference};") + .AppendLine($"{_scopeResolution.TransientScopeReference} = {_scopeResolution.TransientScopeParameterReference};") .AppendLine($"}}"); stringBuilder = GenerateResolutionRange( @@ -55,6 +53,5 @@ public ScopeCodeBuilder( _containerInfo = containerInfo; _scopeResolution = scopeResolution; _transientScopeInterfaceResolution = transientScopeInterfaceResolution; - TransientScopeReference = _scopeResolution.TransientScopeReference; } } \ No newline at end of file diff --git a/Main/CodeBuilding/TransientScopeCodeBuilder.cs b/Main/CodeBuilding/TransientScopeCodeBuilder.cs new file mode 100644 index 00000000..742cf5f6 --- /dev/null +++ b/Main/CodeBuilding/TransientScopeCodeBuilder.cs @@ -0,0 +1,51 @@ +namespace MrMeeseeks.DIE.CodeBuilding; + +internal interface ITransientScopeCodeBuilder : IRangeCodeBaseBuilder +{ + +} + +internal class TransientScopeCodeBuilder : RangeCodeBaseBuilder, ITransientScopeCodeBuilder +{ + private readonly IContainerInfo _containerInfo; + private readonly TransientScopeResolution _transientScopeResolution; + + public override StringBuilder Build(StringBuilder stringBuilder) + { + if (!_transientScopeResolution.RootResolutions.Any() && !_transientScopeResolution.RangedInstances.Any()) + return stringBuilder; + + stringBuilder = stringBuilder + .AppendLine( + $"internal partial class {_transientScopeResolution.Name} : {WellKnownTypes.Disposable.FullName()}") + .AppendLine($"{{") + .AppendLine($"private readonly {_containerInfo.FullName} {_transientScopeResolution.ContainerReference};") + .AppendLine($"internal {_transientScopeResolution.Name}(") + .AppendLine($"{_containerInfo.FullName} {_transientScopeResolution.ContainerParameterReference})") + .AppendLine($"{{") + .AppendLine($"{_transientScopeResolution.ContainerReference} = {_transientScopeResolution.ContainerParameterReference};") + .AppendLine($"}}"); + + stringBuilder = GenerateResolutionRange( + stringBuilder, + _transientScopeResolution); + + stringBuilder = stringBuilder + .AppendLine($"}}"); + + return stringBuilder; + } + + public TransientScopeCodeBuilder( + // parameter + IContainerInfo containerInfo, + TransientScopeResolution transientScopeResolution, + + // dependencies + WellKnownTypes wellKnownTypes) + : base(wellKnownTypes) + { + _containerInfo = containerInfo; + _transientScopeResolution = transientScopeResolution; + } +} \ No newline at end of file diff --git a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs index ed262e02..b964d8ad 100644 --- a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs @@ -19,6 +19,7 @@ internal class ContainerResolutionBuilder : RangeResolutionBaseBuilder, IContain private readonly List _rootResolutions = new (); private readonly IScopeResolutionBuilder _scopeResolutionBuilder; private readonly string _transientScopeAdapterReference; + private readonly ITransientScopeResolutionBuilder _transientScopeResolutionBuilder; internal ContainerResolutionBuilder( // parameters @@ -31,7 +32,8 @@ internal ContainerResolutionBuilder( ICheckTypeProperties checkTypeProperties, ICheckDecorators checkDecorators, WellKnownTypes wellKnownTypes, - Func scopeResolutionBuilderFactory, + Func transientScopeResolutionBuilderFactory, + Func scopeResolutionBuilderFactory, IUserProvidedScopeElements userProvidedScopeElements) : base( (containerInfo.Name, false), @@ -44,9 +46,13 @@ internal ContainerResolutionBuilder( { _containerInfo = containerInfo; _transientScopeInterfaceResolutionBuilder = transientScopeInterfaceResolutionBuilder; - _scopeResolutionBuilder = scopeResolutionBuilderFactory(this, transientScopeInterfaceResolutionBuilder); + _transientScopeResolutionBuilder = transientScopeResolutionBuilderFactory(this, _transientScopeInterfaceResolutionBuilder); + _scopeResolutionBuilder = scopeResolutionBuilderFactory(this, _transientScopeResolutionBuilder, _transientScopeInterfaceResolutionBuilder); + if (_transientScopeResolutionBuilder is TransientScopeResolutionBuilder transientScopeResolutionBuilder) + transientScopeResolutionBuilder.ScopeResolutionBuilder = _scopeResolutionBuilder; transientScopeInterfaceResolutionBuilder.AddImplementation(this); + transientScopeInterfaceResolutionBuilder.AddImplementation(_transientScopeResolutionBuilder); _transientScopeAdapterReference = RootReferenceGenerator.Generate("TransientScopeAdapter"); } @@ -78,6 +84,15 @@ protected override RangedInstanceReferenceResolution CreateContainerInstanceRefe protected override RangedInstanceReferenceResolution CreateTransientScopeInstanceReferenceResolution(ForConstructorParameter parameter) => _transientScopeInterfaceResolutionBuilder.CreateTransientScopeInstanceReferenceResolution(parameter, "this"); + protected override TransientScopeRootResolution CreateTransientScopeRootResolution(IScopeRootParameter parameter, INamedTypeSymbol rootType, + DisposableCollectionResolution disposableCollectionResolution, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) => + _transientScopeResolutionBuilder.AddCreateResolveFunction( + parameter, + rootType, + "this", + disposableCollectionResolution, + currentParameters); + protected override ScopeRootResolution CreateScopeRootResolution( IScopeRootParameter parameter, INamedTypeSymbol rootType, @@ -87,14 +102,18 @@ protected override ScopeRootResolution CreateScopeRootResolution( parameter, rootType, "this", + _transientScopeAdapterReference, disposableCollectionResolution, currentParameters); public ContainerResolution Build() { - while (RangedInstanceResolutionsQueue.Any() || _scopeResolutionBuilder.HasWorkToDo) + while (RangedInstanceResolutionsQueue.Any() + || _transientScopeResolutionBuilder.HasWorkToDo + || _scopeResolutionBuilder.HasWorkToDo) { DoRangedInstancesWork(); + _transientScopeResolutionBuilder.DoWork(); _scopeResolutionBuilder.DoWork(); } @@ -110,6 +129,7 @@ public ContainerResolution Build() .ToList(), _transientScopeInterfaceResolutionBuilder.Build(), _transientScopeAdapterReference, + _transientScopeResolutionBuilder.Build(), _scopeResolutionBuilder.Build()); } diff --git a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs index b0f01e7b..8a4fb2bd 100644 --- a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs +++ b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs @@ -57,6 +57,12 @@ protected RangeResolutionBaseBuilder( protected abstract RangedInstanceReferenceResolution CreateTransientScopeInstanceReferenceResolution(ForConstructorParameter parameter); + protected abstract TransientScopeRootResolution CreateTransientScopeRootResolution( + IScopeRootParameter parameter, + INamedTypeSymbol rootType, + DisposableCollectionResolution disposableCollectionResolution, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters); + protected abstract ScopeRootResolution CreateScopeRootResolution( IScopeRootParameter parameter, INamedTypeSymbol rootType, @@ -239,23 +245,27 @@ private Resolvable SwitchInterface(SwitchInterfaceParameter parameter) var interfaceType = (INamedTypeSymbol) typeSymbol; var implementations = TypeToImplementationsMapper .Map(typeSymbol); - var shouldBeScopeRoot = implementations.Any(i => CheckTypeProperties.ShouldBeScopeRoot(i)); + var shouldBeScopeRoot = implementations.Max(i => CheckTypeProperties.ShouldBeScopeRoot(i)); var nextParameter = new SwitchInterfaceAfterScopeRootParameter( interfaceType, implementations, currentParameters); - if (shouldBeScopeRoot) + return shouldBeScopeRoot switch { - return CreateScopeRootResolution( + ScopeLevel.TransientScope => CreateTransientScopeRootResolution( nextParameter, interfaceType, DisposableCollectionResolution, - currentParameters); - } - - return SwitchInterfaceAfterScopeRoot(nextParameter); + currentParameters), + ScopeLevel.Scope => CreateScopeRootResolution( + nextParameter, + interfaceType, + DisposableCollectionResolution, + currentParameters), + _ => SwitchInterfaceAfterScopeRoot(nextParameter) + }; } protected Resolvable SwitchInterfaceAfterScopeRoot( @@ -306,17 +316,21 @@ private Resolvable SwitchInterfaceForSpecificImplementation( interfaceType, implementationType, currentParameters); - - if (CheckTypeProperties.ShouldBeScopeRoot(implementationType)) + + return CheckTypeProperties.ShouldBeScopeRoot(implementationType) switch { - return CreateScopeRootResolution( + ScopeLevel.TransientScope => CreateTransientScopeRootResolution( nextParameter, interfaceType, DisposableCollectionResolution, - currentParameters); - } - - return CreateInterface(nextParameter); + currentParameters), + ScopeLevel.Scope => CreateScopeRootResolution( + nextParameter, + interfaceType, + DisposableCollectionResolution, + currentParameters), + _ => CreateInterface(nextParameter) + }; } internal InterfaceResolution CreateInterface(CreateInterfaceParameter parameter) @@ -382,11 +396,21 @@ protected Resolvable SwitchClass(SwitchClassParameter parameter) var nextParameter = new SwitchImplementationParameter( implementationType, currentParameters); - - if (CheckTypeProperties.ShouldBeScopeRoot(implementationType)) - return CreateScopeRootResolution(nextParameter, implementationType, DisposableCollectionResolution, currentParameters); - - return SwitchImplementation(nextParameter); + + return CheckTypeProperties.ShouldBeScopeRoot(implementationType) switch + { + ScopeLevel.TransientScope => CreateTransientScopeRootResolution( + nextParameter, + implementationType, + DisposableCollectionResolution, + currentParameters), + ScopeLevel.Scope => CreateScopeRootResolution( + nextParameter, + implementationType, + DisposableCollectionResolution, + currentParameters), + _ => SwitchImplementation(nextParameter) + }; } protected Resolvable SwitchImplementation(SwitchImplementationParameter parameter) diff --git a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs index 0c51700b..21a3e64c 100644 --- a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs @@ -8,6 +8,7 @@ ScopeRootResolution AddCreateResolveFunction( IScopeRootParameter parameter, INamedTypeSymbol rootType, string containerInstanceScopeReference, + string transientInstanceScopeReference, DisposableCollectionResolution disposableCollectionResolution, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters); @@ -19,6 +20,7 @@ ScopeRootResolution AddCreateResolveFunction( internal class ScopeResolutionBuilder : RangeResolutionBaseBuilder, IScopeResolutionBuilder { private readonly IContainerResolutionBuilder _containerResolutionBuilder; + private readonly ITransientScopeResolutionBuilder _transientScopeResolutionBuilder; private readonly ITransientScopeInterfaceResolutionBuilder _transientScopeInterfaceResolutionBuilder; private readonly List _rootResolutions = new (); private readonly string _containerReference; @@ -33,6 +35,7 @@ internal class ScopeResolutionBuilder : RangeResolutionBaseBuilder, IScopeResolu internal ScopeResolutionBuilder( // parameter IContainerResolutionBuilder containerResolutionBuilder, + ITransientScopeResolutionBuilder transientScopeResolutionBuilder, ITransientScopeInterfaceResolutionBuilder transientScopeInterfaceResolutionBuilder, // dependencies @@ -52,11 +55,12 @@ internal ScopeResolutionBuilder( userProvidedScopeElements) { _containerResolutionBuilder = containerResolutionBuilder; + _transientScopeResolutionBuilder = transientScopeResolutionBuilder; _transientScopeInterfaceResolutionBuilder = transientScopeInterfaceResolutionBuilder; _containerReference = RootReferenceGenerator.Generate("_container"); _containerParameterReference = RootReferenceGenerator.Generate("container"); _transientScopeReference = RootReferenceGenerator.Generate("_transientScope"); - _transientScopeParameterReference = RootReferenceGenerator.Generate("_transientScopeParameter"); + _transientScopeParameterReference = RootReferenceGenerator.Generate("transientScope"); } protected override RangedInstanceReferenceResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter) => @@ -65,6 +69,18 @@ protected override RangedInstanceReferenceResolution CreateContainerInstanceRefe protected override RangedInstanceReferenceResolution CreateTransientScopeInstanceReferenceResolution(ForConstructorParameter parameter) => _transientScopeInterfaceResolutionBuilder.CreateTransientScopeInstanceReferenceResolution(parameter, _transientScopeReference); + protected override TransientScopeRootResolution CreateTransientScopeRootResolution( + IScopeRootParameter parameter, + INamedTypeSymbol rootType, + DisposableCollectionResolution disposableCollectionResolution, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) => + _transientScopeResolutionBuilder.AddCreateResolveFunction( + parameter, + rootType, + _containerReference, + disposableCollectionResolution, + currentParameters); + protected override ScopeRootResolution CreateScopeRootResolution( IScopeRootParameter parameter, INamedTypeSymbol rootType, @@ -74,6 +90,7 @@ protected override ScopeRootResolution CreateScopeRootResolution( parameter, rootType, _containerReference, + _transientScopeReference, disposableCollectionResolution, currentParameters); @@ -83,6 +100,7 @@ public ScopeRootResolution AddCreateResolveFunction( IScopeRootParameter parameter, INamedTypeSymbol rootType, string containerInstanceScopeReference, + string transientInstanceScopeReference, DisposableCollectionResolution disposableCollectionResolution, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) { @@ -113,6 +131,7 @@ public ScopeRootResolution AddCreateResolveFunction( RootReferenceGenerator.Generate("scopeRoot"), Name, containerInstanceScopeReference, + transientInstanceScopeReference, currentParameters.Select(t => t.Resolution).ToList(), disposableCollectionResolution, function); diff --git a/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs b/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs new file mode 100644 index 00000000..0826011b --- /dev/null +++ b/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs @@ -0,0 +1,175 @@ +namespace MrMeeseeks.DIE.ResolutionBuilding; + +internal interface ITransientScopeResolutionBuilder : ITransientScopeImplementationResolutionBuilder +{ + bool HasWorkToDo { get; } + + TransientScopeRootResolution AddCreateResolveFunction( + IScopeRootParameter parameter, + INamedTypeSymbol rootType, + string containerInstanceScopeReference, + DisposableCollectionResolution disposableCollectionResolution, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters); + + void DoWork(); + + TransientScopeResolution Build(); +} + +internal class TransientScopeResolutionBuilder : RangeResolutionBaseBuilder, ITransientScopeResolutionBuilder +{ + private readonly IContainerResolutionBuilder _containerResolutionBuilder; + private readonly ITransientScopeInterfaceResolutionBuilder _transientScopeInterfaceResolutionBuilder; + private readonly List _rootResolutions = new (); + private readonly string _containerReference; + private readonly string _containerParameterReference; + + private readonly Dictionary _transientScopeRootFunctionResolutions = new (); + private readonly HashSet<(ScopeRootFunction, string)> _transientScopeRootFunctionQueuedOverloads = new (); + private readonly Queue<(ScopeRootFunction, IReadOnlyList, INamedTypeSymbol, IScopeRootParameter)> _transientScopeRootFunctionResolutionsQueue = new(); + + public IScopeResolutionBuilder? ScopeResolutionBuilder { get; set; } + + internal TransientScopeResolutionBuilder( + // parameter + IContainerResolutionBuilder containerResolutionBuilder, + ITransientScopeInterfaceResolutionBuilder transientScopeInterfaceResolutionBuilder, + + // dependencies + WellKnownTypes wellKnownTypes, + ITypeToImplementationsMapper typeToImplementationsMapper, + IReferenceGeneratorFactory referenceGeneratorFactory, + ICheckTypeProperties checkTypeProperties, + ICheckDecorators checkDecorators, + IUserProvidedScopeElements userProvidedScopeElements) + : base( + ("DefaultTransientScope", true), + wellKnownTypes, + typeToImplementationsMapper, + referenceGeneratorFactory, + checkTypeProperties, + checkDecorators, + userProvidedScopeElements) + { + _containerResolutionBuilder = containerResolutionBuilder; + _transientScopeInterfaceResolutionBuilder = transientScopeInterfaceResolutionBuilder; + _containerReference = RootReferenceGenerator.Generate("_container"); + _containerParameterReference = RootReferenceGenerator.Generate("container"); + } + + protected override RangedInstanceReferenceResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter) => + _containerResolutionBuilder.CreateContainerInstanceReferenceResolution(parameter, _containerReference); + + protected override RangedInstanceReferenceResolution CreateTransientScopeInstanceReferenceResolution(ForConstructorParameter parameter) => + _transientScopeInterfaceResolutionBuilder.CreateTransientScopeInstanceReferenceResolution(parameter, "this"); + + protected override TransientScopeRootResolution CreateTransientScopeRootResolution(IScopeRootParameter parameter, INamedTypeSymbol rootType, + DisposableCollectionResolution disposableCollectionResolution, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) => + AddCreateResolveFunction( + parameter, + rootType, + _containerReference, + disposableCollectionResolution, + currentParameters); + + protected override ScopeRootResolution CreateScopeRootResolution( + IScopeRootParameter parameter, + INamedTypeSymbol rootType, + DisposableCollectionResolution disposableCollectionResolution, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) => + ScopeResolutionBuilder!.AddCreateResolveFunction( + parameter, + rootType, + _containerReference, + "this", + disposableCollectionResolution, + currentParameters); + + public bool HasWorkToDo => _transientScopeRootFunctionResolutionsQueue.Any() || RangedInstanceResolutionsQueue.Any(); + + public TransientScopeRootResolution AddCreateResolveFunction( + IScopeRootParameter parameter, + INamedTypeSymbol rootType, + string containerInstanceScopeReference, + DisposableCollectionResolution disposableCollectionResolution, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) + { + var key = $"{rootType.FullName()}{parameter.KeySuffix()}"; + if (!_transientScopeRootFunctionResolutions.TryGetValue( + key, + out ScopeRootFunction function)) + { + function = new ScopeRootFunction( + RootReferenceGenerator.Generate("Create", rootType, parameter.RootFunctionSuffix()), + rootType.FullName()); + _transientScopeRootFunctionResolutions[key] = function; + } + + var listedParameterTypes = string.Join(",", currentParameters.Select(p => p.Item2.TypeFullName)); + if (!_transientScopeRootFunctionQueuedOverloads.Contains((function, listedParameterTypes))) + { + var currParameter = currentParameters + .Select(t => new ParameterResolution(RootReferenceGenerator.Generate(t.Type), t.Type.FullName())) + .ToList(); + _transientScopeRootFunctionResolutionsQueue.Enqueue((function, currParameter, rootType, parameter)); + _transientScopeRootFunctionQueuedOverloads.Add((function, listedParameterTypes)); + } + + return new TransientScopeRootResolution( + RootReferenceGenerator.Generate(rootType), + rootType.FullName(), + RootReferenceGenerator.Generate("transientScopeRoot"), + Name, + containerInstanceScopeReference, + currentParameters.Select(t => t.Resolution).ToList(), + disposableCollectionResolution, + function); + } + + public void DoWork() + { + while (HasWorkToDo) + { + while (_transientScopeRootFunctionResolutionsQueue.Any()) + { + var (scopeRootFunction, parameter, type, functionParameter) = _transientScopeRootFunctionResolutionsQueue.Dequeue(); + + var resolvable = functionParameter switch + { + CreateInterfaceParameter createInterfaceParameter => CreateInterface(createInterfaceParameter), + SwitchImplementationParameter switchImplementationParameter => SwitchImplementation(switchImplementationParameter), + SwitchInterfaceAfterScopeRootParameter switchInterfaceAfterScopeRootParameter => SwitchInterfaceAfterScopeRoot(switchInterfaceAfterScopeRootParameter), + _ => throw new ArgumentOutOfRangeException(nameof(functionParameter)) + }; + + _rootResolutions.Add(new RootResolutionFunction( + scopeRootFunction.Reference, + type.FullName(), + "internal", + resolvable, + parameter, + "", + Name, + DisposalHandling)); + } + + DoRangedInstancesWork(); + } + } + + public TransientScopeResolution Build() => + new(_rootResolutions, + DisposalHandling, + RangedInstances + .GroupBy(t => t.Item1) + .Select(g => new RangedInstance( + g.Key, + g.Select(t => t.Item2).ToList(), + DisposalHandling)) + .ToList(), + _containerReference, + _containerParameterReference, + Name); + + public void EnqueueRangedInstanceResolution(RangedInstanceResolutionsQueueItem item) => RangedInstanceResolutionsQueue.Enqueue(item); +} \ No newline at end of file diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index 91fb0763..111f6bea 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -36,12 +36,23 @@ internal record SyntaxValueTupleResolution( string TypeFullName, IReadOnlyList Items) : Resolvable(Reference, TypeFullName); +internal record TransientScopeRootResolution( + string Reference, + string TypeFullName, + string TransientScopeReference, + string TransientScopeTypeFullName, + string ContainerInstanceScopeReference, + IReadOnlyList Parameter, + DisposableCollectionResolution DisposableCollectionResolution, + ScopeRootFunction ScopeRootFunction) : Resolvable(Reference, TypeFullName); + internal record ScopeRootResolution( string Reference, string TypeFullName, string ScopeReference, string ScopeTypeFullName, string ContainerInstanceScopeReference, + string TransientInstanceScopeReference, IReadOnlyList Parameter, DisposableCollectionResolution DisposableCollectionResolution, ScopeRootFunction ScopeRootFunction) : Resolvable(Reference, TypeFullName); @@ -129,12 +140,22 @@ internal record ScopeResolution( string Name) : RangeResolution(RootResolutions, DisposalHandling, RangedInstances); +internal record TransientScopeResolution( + IReadOnlyList RootResolutions, + DisposalHandling DisposalHandling, + IReadOnlyList RangedInstances, + string ContainerReference, + string ContainerParameterReference, + string Name) + : RangeResolution(RootResolutions, DisposalHandling, RangedInstances); + internal record ContainerResolution( IReadOnlyList RootResolutions, DisposalHandling DisposalHandling, IReadOnlyList RangedInstances, TransientScopeInterfaceResolution TransientScopeInterface, string TransientScopeAdapterReference, + TransientScopeResolution DefaultTransientScope, ScopeResolution DefaultScope) : RangeResolution(RootResolutions, DisposalHandling, RangedInstances); diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index 54c0ee70..172dc72b 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -24,7 +24,7 @@ public void Execute(GeneratorExecutionContext context) var checkDecorators = new CheckDecorators(wellKnownTypes, getAssemblyAttributes, typesFromTypeAggregatingAttributes, getSetOfTypesWithProperties); var checkTypeProperties = new CheckTypeProperties(typesFromTypeAggregatingAttributes, getAssemblyAttributes, wellKnownTypes, getSetOfTypesWithProperties); var typeToImplementationMapper = new TypeToImplementationsMapper(getAllImplementations, checkDecorators, checkTypeProperties); - var containerGenerator = new ContainerGenerator(context, diagLogger, ContainerCodeBuilderFactory, ScopeCodeBuilderFactory); + var containerGenerator = new ContainerGenerator(context, diagLogger, ContainerCodeBuilderFactory, TransientScopeCodeBuilderFactory, ScopeCodeBuilderFactory); var referenceGeneratorFactory = new ReferenceGeneratorFactory(ReferenceGeneratorFactory); var containerErrorGenerator = new ContainerErrorGenerator(context); var resolutionTreeCreationErrorHarvester = new ResolutionTreeCreationErrorHarvester(); @@ -47,12 +47,24 @@ public void Execute(GeneratorExecutionContext context) checkTypeProperties, checkDecorators, wellKnownTypes, + TransientScopeResolutionBuilderFactory, ScopeResolutionBuilderFactory, new UserProvidedScopeElements(ci.ContainerType)); - IScopeResolutionBuilder ScopeResolutionBuilderFactory(IContainerResolutionBuilder containerBuilder, ITransientScopeInterfaceResolutionBuilder transientScopeInterfaceResolutionBuilder) => new ScopeResolutionBuilder( + ITransientScopeResolutionBuilder TransientScopeResolutionBuilderFactory(IContainerResolutionBuilder containerBuilder, ITransientScopeInterfaceResolutionBuilder transientScopeInterfaceResolutionBuilder) => new TransientScopeResolutionBuilder( containerBuilder, transientScopeInterfaceResolutionBuilder, + wellKnownTypes, + typeToImplementationMapper, + referenceGeneratorFactory, + checkTypeProperties, + checkDecorators, + new EmptyUserProvidedScopeElements()); // todo Replace EmptyUserProvidedScopeElements with one for the scope specifically + IScopeResolutionBuilder ScopeResolutionBuilderFactory(IContainerResolutionBuilder containerBuilder, ITransientScopeResolutionBuilder transientScopeResolutionBuilder, ITransientScopeInterfaceResolutionBuilder transientScopeInterfaceResolutionBuilder) => new ScopeResolutionBuilder( + containerBuilder, + transientScopeResolutionBuilder, + transientScopeInterfaceResolutionBuilder, + wellKnownTypes, typeToImplementationMapper, referenceGeneratorFactory, @@ -65,18 +77,27 @@ public void Execute(GeneratorExecutionContext context) IContainerCodeBuilder ContainerCodeBuilderFactory( IContainerInfo containerInfo, ContainerResolution containerResolution, + ITransientScopeCodeBuilder transientScopeCodeBuilder, IScopeCodeBuilder scopeCodeBuilder) => new ContainerCodeBuilder( containerInfo, containerResolution, + transientScopeCodeBuilder, scopeCodeBuilder, wellKnownTypes); + ITransientScopeCodeBuilder TransientScopeCodeBuilderFactory( + IContainerInfo containerInfo, + TransientScopeResolution transientScopeResolution) => new TransientScopeCodeBuilder( + containerInfo, + transientScopeResolution, + wellKnownTypes); + IScopeCodeBuilder ScopeCodeBuilderFactory( IContainerInfo containerInfo, - ScopeResolution containerResolution, + ScopeResolution scopeResolution, TransientScopeInterfaceResolution transientScopeInterfaceResolution) => new ScopeCodeBuilder( containerInfo, - containerResolution, + scopeResolution, transientScopeInterfaceResolution, wellKnownTypes); } diff --git a/Main/TypesFromTypeAggregatingAttributes.cs b/Main/TypesFromTypeAggregatingAttributes.cs index d3e702e7..9d20ae67 100644 --- a/Main/TypesFromTypeAggregatingAttributes.cs +++ b/Main/TypesFromTypeAggregatingAttributes.cs @@ -8,6 +8,7 @@ internal interface ITypesFromTypeAggregatingAttributes IReadOnlyList ContainerInstance { get; } IReadOnlyList TransientScopeInstance { get; } IReadOnlyList ScopeInstance { get; } + IReadOnlyList TransientScopeRoot { get; } IReadOnlyList ScopeRoot { get; } IReadOnlyList Decorator { get; } IReadOnlyList Composite { get; } @@ -25,6 +26,7 @@ internal TypesFromTypeAggregatingAttributes( ContainerInstance = GetTypesFromAttribute(wellKnownTypes.ContainerInstanceAggregationAttribute).ToList(); TransientScopeInstance = GetTypesFromAttribute(wellKnownTypes.TransientScopeInstanceAggregationAttribute).ToList(); ScopeInstance = GetTypesFromAttribute(wellKnownTypes.ScopeInstanceAggregationAttribute).ToList(); + TransientScopeRoot = GetTypesFromAttribute(wellKnownTypes.TransientScopeRootAggregationAttribute).ToList(); ScopeRoot = GetTypesFromAttribute(wellKnownTypes.ScopeRootAggregationAttribute).ToList(); Decorator = GetTypesFromAttribute(wellKnownTypes.DecoratorAggregationAttribute).ToList(); Composite = GetTypesFromAttribute(wellKnownTypes.CompositeAggregationAttribute).ToList(); @@ -68,6 +70,7 @@ bool CheckValidType(TypedConstant typedConstant, out INamedTypeSymbol type) public IReadOnlyList ContainerInstance { get; } public IReadOnlyList TransientScopeInstance { get; } public IReadOnlyList ScopeInstance { get; } + public IReadOnlyList TransientScopeRoot { get; } public IReadOnlyList ScopeRoot { get; } public IReadOnlyList Decorator { get; } public IReadOnlyList Composite { get; } diff --git a/Main/WellKnownTypes.cs b/Main/WellKnownTypes.cs index 519d75ee..06189427 100644 --- a/Main/WellKnownTypes.cs +++ b/Main/WellKnownTypes.cs @@ -9,6 +9,7 @@ internal record WellKnownTypes( INamedTypeSymbol ContainerInstanceAggregationAttribute, INamedTypeSymbol TransientScopeInstanceAggregationAttribute, INamedTypeSymbol ScopeInstanceAggregationAttribute, + INamedTypeSymbol TransientScopeRootAggregationAttribute, INamedTypeSymbol ScopeRootAggregationAttribute, INamedTypeSymbol DecoratorAggregationAttribute, INamedTypeSymbol CompositeAggregationAttribute, @@ -73,6 +74,9 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK var scopeInstanceAggregationAttribute = compilation .GetTypeByMetadataName(typeof(ScopeInstanceAggregationAttribute).FullName ?? ""); + var transientScopeRootAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(TransientScopeRootAggregationAttribute).FullName ?? ""); + var scopeRootAggregationAttribute = compilation .GetTypeByMetadataName(typeof(ScopeRootAggregationAttribute).FullName ?? ""); @@ -96,6 +100,7 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK || containerInstanceAggregationAttribute is null || transientScopeInstanceAggregationAttribute is null || scopeInstanceAggregationAttribute is null + || transientScopeRootAggregationAttribute is null || scopeRootAggregationAttribute is null || decoratorAggregationAttribute is null || compositeAggregationAttribute is null @@ -130,6 +135,7 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK ContainerInstanceAggregationAttribute: containerInstanceAggregationAttribute, TransientScopeInstanceAggregationAttribute: transientScopeInstanceAggregationAttribute, ScopeInstanceAggregationAttribute: scopeInstanceAggregationAttribute, + TransientScopeRootAggregationAttribute: transientScopeRootAggregationAttribute, ScopeRootAggregationAttribute: scopeRootAggregationAttribute, DecoratorAggregationAttribute: decoratorAggregationAttribute, CompositeAggregationAttribute: compositeAggregationAttribute, diff --git a/Sample/Container.cs b/Sample/Container.cs index 0277af18..cec86553 100644 --- a/Sample/Container.cs +++ b/Sample/Container.cs @@ -4,6 +4,7 @@ [assembly:ContainerInstanceAggregation(typeof(IContainerInstance))] [assembly:TransientScopeInstanceAggregation(typeof(ITransientScopeInstance))] [assembly:ScopeInstanceAggregation(typeof(IScopeInstance))] +[assembly:TransientScopeRootAggregation(typeof(ITransientScopeRoot))] [assembly:ScopeRootAggregation(typeof(IScopeRoot))] [assembly:TransientAggregation(typeof(ITransient))] [assembly:DecoratorAggregation(typeof(IDecorator<>))] diff --git a/Sample/Context.cs b/Sample/Context.cs index 9c90c4a7..14fc3d27 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -1,37 +1,16 @@ namespace MrMeeseeks.DIE.Sample; -internal interface IValueTupleBase -{ - (int _0, int _1, int _2, int _3, int _4, - int _5, int _6, int _7, int _8, int _9, - int _10, int _11, int _12, int _13, int _14, - int _15, int _16, int _17, int _18, int _19, - int _20, int _21, int _22, int _23, int _24, - int _25) Dependency { get; } -} +internal interface ITransientScopeInstanceInner {} +internal class TransientScopeInstance : ITransientScopeInstanceInner, ITransientScopeInstance {} -internal class ValueTupleBase : IValueTupleBase -{ - public ValueTupleBase( - (int _0, int _1, int _2, int _3, int _4, - int _5, int _6, int _7, int _8, int _9, - int _10, int _11, int _12, int _13, int _14, - int _15, int _16, int _17, int _18, int _19, - int _20, int _21, int _22, int _23, int _24, - int _25) dependency) => - Dependency = dependency; +internal interface ITransientScopeWithTransientScopeInstance {} - public (int _0, int _1, int _2, int _3, int _4, - int _5, int _6, int _7, int _8, int _9, - int _10, int _11, int _12, int _13, int _14, - int _15, int _16, int _17, int _18, int _19, - int _20, int _21, int _22, int _23, int _24, - int _25) Dependency { get; } +internal class TransientScopeWithTransientScopeInstance : ITransientScopeWithTransientScopeInstance, ITransientScopeRoot +{ + public TransientScopeWithTransientScopeInstance(ITransientScopeInstanceInner _) {} } -internal partial class ValueTupleContainer : IContainer +internal partial class TransientScopeInstanceContainer : IContainer { - private int _i; - - private int DIE_Counter() => _i++; + } \ No newline at end of file diff --git a/Sample/MarkerInterfaces.cs b/Sample/MarkerInterfaces.cs index 13db59d5..558e0576 100644 --- a/Sample/MarkerInterfaces.cs +++ b/Sample/MarkerInterfaces.cs @@ -3,6 +3,7 @@ namespace MrMeeseeks.DIE.Sample; public interface IContainerInstance { } public interface ITransientScopeInstance { } public interface IScopeInstance { } +public interface ITransientScopeRoot { } public interface IScopeRoot { } public interface ITransient { } public interface IDecorator { } diff --git a/Sample/Program.cs b/Sample/Program.cs index a91985db..6e1e1d30 100644 --- a/Sample/Program.cs +++ b/Sample/Program.cs @@ -3,5 +3,5 @@ using MrMeeseeks.DIE.Sample; Console.WriteLine("Hello, world!"); -var container = new ValueTupleContainer(); -Console.WriteLine(((IContainer) container).Resolve()); \ No newline at end of file +var container = new TransientScopeInstanceContainer(); +Console.WriteLine(((IContainer) container).Resolve()); \ No newline at end of file diff --git a/Test/AssemblyInfo.cs b/Test/AssemblyInfo.cs index c7c15dad..ba29ff54 100644 --- a/Test/AssemblyInfo.cs +++ b/Test/AssemblyInfo.cs @@ -4,6 +4,7 @@ [assembly:ContainerInstanceAggregation(typeof(IContainerInstance))] [assembly:TransientScopeInstanceAggregation(typeof(ITransientScopeInstance))] [assembly:ScopeInstanceAggregation(typeof(IScopeInstance))] +[assembly:TransientScopeRootAggregation(typeof(ITransientScopeRoot))] [assembly:ScopeRootAggregation(typeof(IScopeRoot))] [assembly:TransientAggregation(typeof(ITransient))] [assembly:DecoratorAggregation(typeof(IDecorator<>))] diff --git a/Test/MarkerInterfaces.cs b/Test/MarkerInterfaces.cs index 36d41dd5..f62270ec 100644 --- a/Test/MarkerInterfaces.cs +++ b/Test/MarkerInterfaces.cs @@ -3,6 +3,7 @@ namespace MrMeeseeks.DIE.Test; public interface IContainerInstance { } public interface ITransientScopeInstance { } public interface IScopeInstance { } +public interface ITransientScopeRoot { } public interface IScopeRoot { } public interface ITransient { } public interface IDecorator { } diff --git a/Test/TransientScopeInstanceTests.cs b/Test/TransientScopeInstanceTests.cs index 74df03fb..d43aa0a9 100644 --- a/Test/TransientScopeInstanceTests.cs +++ b/Test/TransientScopeInstanceTests.cs @@ -62,4 +62,26 @@ public void InScopeInScope() using var container = new TransientScopeInstanceContainer(); var _ = ((IContainer) container).Resolve(); } +} + +internal interface ITransientScopeWithTransientScopeInstance {} + +internal class TransientScopeWithTransientScopeInstance : ITransientScopeWithTransientScopeInstance, ITransientScopeRoot +{ + public TransientScopeWithTransientScopeInstance(ITransientScopeInstanceInner _) {} +} + +internal partial class TransientScopeInstanceContainer : IContainer +{ + +} + +public partial class TransientScopeInstanceTests +{ + [Fact] + public void InTransientScope() + { + using var container = new TransientScopeInstanceContainer(); + var _ = ((IContainer) container).Resolve(); + } } \ No newline at end of file From b6925802bd758e09dff4a172d6de10a898f4444d Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Thu, 20 Jan 2022 19:49:57 +0100 Subject: [PATCH 042/162] Implemented Disposal handling of TransientScopes --- Main/CodeBuilding/ContainerCodeBuilder.cs | 2 +- Main/CodeBuilding/ContainerGenerator.cs | 12 ++-- Main/CodeBuilding/RangeCodeBaseBuilder.cs | 44 +++++++----- Main/CodeBuilding/ScopeCodeBuilder.cs | 3 +- .../CodeBuilding/TransientScopeCodeBuilder.cs | 7 +- .../RangeResolutionBaseBuilder.cs | 22 +++--- .../TransientScopeResolutionBuilder.cs | 4 ++ Main/ResolutionTreeCreationErrorHarvester.cs | 2 + Main/ResolutionTreeItem.cs | 13 ++-- Main/SourceGenerator.cs | 8 ++- Test/TransientScopeInstanceTests.cs | 70 ++++++++++++++++++- 11 files changed, 146 insertions(+), 41 deletions(-) diff --git a/Main/CodeBuilding/ContainerCodeBuilder.cs b/Main/CodeBuilding/ContainerCodeBuilder.cs index fa42da86..82169424 100644 --- a/Main/CodeBuilding/ContainerCodeBuilder.cs +++ b/Main/CodeBuilding/ContainerCodeBuilder.cs @@ -71,7 +71,7 @@ public ContainerCodeBuilder( // dependencies WellKnownTypes wellKnownTypes) - : base(wellKnownTypes) + : base(containerResolution, containerResolution, wellKnownTypes) { _containerInfo = containerInfo; _containerResolution = containerResolution; diff --git a/Main/CodeBuilding/ContainerGenerator.cs b/Main/CodeBuilding/ContainerGenerator.cs index 3a5d94bc..8835e9d4 100644 --- a/Main/CodeBuilding/ContainerGenerator.cs +++ b/Main/CodeBuilding/ContainerGenerator.cs @@ -13,15 +13,15 @@ internal class ContainerGenerator : IContainerGenerator private readonly GeneratorExecutionContext _context; private readonly IDiagLogger _diagLogger; private readonly Func _containerCodeBuilderFactory; - private readonly Func _transientScopeCodeBuilderFactory; - private readonly Func _scopeCodeBuilderFactory; + private readonly Func _transientScopeCodeBuilderFactory; + private readonly Func _scopeCodeBuilderFactory; internal ContainerGenerator( GeneratorExecutionContext context, IDiagLogger diagLogger, Func containerCodeBuilderFactory, - Func transientScopeCodeBuilderFactory, - Func scopeCodeBuilderFactory) + Func transientScopeCodeBuilderFactory, + Func scopeCodeBuilderFactory) { _context = context; _diagLogger = diagLogger; @@ -41,8 +41,8 @@ public void Generate(IContainerInfo containerInfo, ContainerResolution container var containerCodeBuilder = _containerCodeBuilderFactory( containerInfo, containerResolution, - _transientScopeCodeBuilderFactory(containerInfo, containerResolution.DefaultTransientScope), - _scopeCodeBuilderFactory(containerInfo, containerResolution.DefaultScope, containerResolution.TransientScopeInterface)); + _transientScopeCodeBuilderFactory(containerInfo, containerResolution.DefaultTransientScope, containerResolution), + _scopeCodeBuilderFactory(containerInfo, containerResolution.DefaultScope, containerResolution.TransientScopeInterface, containerResolution)); var generatedContainer = containerCodeBuilder.Build(new StringBuilder()); diff --git a/Main/CodeBuilding/RangeCodeBaseBuilder.cs b/Main/CodeBuilding/RangeCodeBaseBuilder.cs index cc7b6d98..18efb88e 100644 --- a/Main/CodeBuilding/RangeCodeBaseBuilder.cs +++ b/Main/CodeBuilding/RangeCodeBaseBuilder.cs @@ -7,12 +7,18 @@ internal interface IRangeCodeBaseBuilder internal abstract class RangeCodeBaseBuilder : IRangeCodeBaseBuilder { + private readonly RangeResolution _rangeResolution; + private readonly ContainerResolution _containerResolution; protected readonly WellKnownTypes WellKnownTypes; - protected bool IsDisposalHandlingRequired = false; + private bool _isDisposalHandlingRequired; internal RangeCodeBaseBuilder( + RangeResolution rangeResolution, + ContainerResolution containerResolution, WellKnownTypes wellKnownTypes) { + _rangeResolution = rangeResolution; + _containerResolution = containerResolution; WellKnownTypes = wellKnownTypes; } @@ -28,8 +34,8 @@ protected StringBuilder GenerateResolutionRange( stringBuilder, rangeResolution); } - - protected StringBuilder GenerateContainerDisposalFunction( + + private StringBuilder GenerateContainerDisposalFunction( StringBuilder stringBuilder, RangeResolution rangeResolution) { @@ -42,8 +48,8 @@ protected StringBuilder GenerateContainerDisposalFunction( .AppendLine($"{{") .AppendLine($"var {disposalHandling.DisposedLocalReference} = global::System.Threading.Interlocked.Exchange(ref this.{disposalHandling.DisposedFieldReference}, 1);") .AppendLine($"if ({disposalHandling.DisposedLocalReference} != 0) return;"); - - if (IsDisposalHandlingRequired) + + if (_isDisposalHandlingRequired) { stringBuilder = rangeResolution.RangedInstances.Aggregate( stringBuilder, @@ -80,7 +86,7 @@ protected StringBuilder GenerateContainerDisposalFunction( .AppendLine($"}}"); } - protected StringBuilder GenerateResolutionFunction( + private StringBuilder GenerateResolutionFunction( StringBuilder stringBuilder, RootResolutionFunction resolution) { @@ -95,7 +101,7 @@ protected StringBuilder GenerateResolutionFunction( .AppendLine($"}}"); } - protected StringBuilder GenerateResolutionFunctionContent( + private StringBuilder GenerateResolutionFunctionContent( StringBuilder stringBuilder, Resolvable resolution) { @@ -103,7 +109,7 @@ protected StringBuilder GenerateResolutionFunctionContent( return GenerateResolutions(stringBuilder, resolution); } - protected StringBuilder GenerateFields( + private static StringBuilder GenerateFields( StringBuilder stringBuilder, Resolvable resolution) { @@ -119,6 +125,9 @@ protected StringBuilder GenerateFields( .AppendLine($"{scopeTypeFullName} {scopeReference};") .AppendLine($"{typeFullName} {reference};"); break; + case TransientScopeAsDisposableResolution(var reference, var typeFullName): + stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); + break; case InterfaceResolution(var reference, var typeFullName, Resolvable resolutionBase): stringBuilder = GenerateFields(stringBuilder, resolutionBase); stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); @@ -161,25 +170,25 @@ protected StringBuilder GenerateFields( return stringBuilder; } - protected StringBuilder GenerateResolutions( + private StringBuilder GenerateResolutions( StringBuilder stringBuilder, Resolvable resolution) { switch (resolution) { - case TransientScopeRootResolution(var reference, var typeFullName, var transientScopeReference, var transientScopeTypeFullName, var containerInstanceScopeReference, var parameter, var (disposableCollectionReference, _, _, _, _), var (createFunctionReference, _)): + case TransientScopeRootResolution(var reference, var typeFullName, var transientScopeReference, var transientScopeTypeFullName, var containerInstanceScopeReference, var parameter, var (_, _, _, _, _), var (createFunctionReference, _)): stringBuilder = stringBuilder .AppendLine($"{transientScopeReference} = new {transientScopeTypeFullName}({containerInstanceScopeReference});") - .AppendLine($"{disposableCollectionReference}.Add(({WellKnownTypes.Disposable.FullName()}) {transientScopeReference});") + .AppendLine($"{_rangeResolution.ContainerReference}.{_containerResolution.DisposalHandling.DisposableCollection.Reference}.Add(({WellKnownTypes.Disposable.FullName()}) {transientScopeReference});") .AppendLine($"{reference} = ({typeFullName}) {transientScopeReference}.{createFunctionReference}({string.Join(", ", parameter.Select(p => p.Reference))});"); - IsDisposalHandlingRequired = true; + _isDisposalHandlingRequired = true; break; case ScopeRootResolution(var reference, var typeFullName, var scopeReference, var scopeTypeFullName, var containerInstanceScopeReference, var transientInstanceScopeReference, var parameter, var (disposableCollectionReference, _, _, _, _), var (createFunctionReference, _)): stringBuilder = stringBuilder .AppendLine($"{scopeReference} = new {scopeTypeFullName}({containerInstanceScopeReference}, {transientInstanceScopeReference});") .AppendLine($"{disposableCollectionReference}.Add(({WellKnownTypes.Disposable.FullName()}) {scopeReference});") .AppendLine($"{reference} = ({typeFullName}) {scopeReference}.{createFunctionReference}({string.Join(", ", parameter.Select(p => p.Reference))});"); - IsDisposalHandlingRequired = true; + _isDisposalHandlingRequired = true; break; case RangedInstanceReferenceResolution(var reference, { Reference: {} functionReference}, var parameter, var owningObjectReference): stringBuilder = stringBuilder.AppendLine($"{reference} = {owningObjectReference}.{functionReference}({string.Join(", ", parameter.Select(p => p.Reference))});"); @@ -189,6 +198,9 @@ protected StringBuilder GenerateResolutions( stringBuilder = stringBuilder.AppendLine( $"{reference} = ({typeFullName}) {resolutionBase.Reference};"); break; + case TransientScopeAsDisposableResolution(var reference, var typeFullName): + stringBuilder = stringBuilder.AppendLine($"{reference} = ({typeFullName}) this;"); + break; case ConstructorResolution(var reference, var typeFullName, var disposableCollectionResolution, var parameters, var initializedProperties): stringBuilder = parameters.Aggregate(stringBuilder, (builder, tuple) => GenerateResolutions(builder, tuple.Dependency)); @@ -205,10 +217,10 @@ protected StringBuilder GenerateResolutions( { stringBuilder = stringBuilder.AppendLine( $"{disposableCollectionResolution.Reference}.Add(({WellKnownTypes.Disposable.FullName()}) {reference});"); - IsDisposalHandlingRequired = true; + _isDisposalHandlingRequired = true; } break; - case SyntaxValueTupleResolution(var reference, var typeFullName, var items): + case SyntaxValueTupleResolution(var reference, _, var items): stringBuilder = items.Aggregate(stringBuilder, GenerateResolutions); stringBuilder = stringBuilder.AppendLine($"{reference} = ({string.Join(", ", items.Select(d => d.Reference))});"); break; @@ -241,7 +253,7 @@ protected StringBuilder GenerateResolutions( return stringBuilder; } - protected StringBuilder GenerateRangedInstanceFunction(StringBuilder stringBuilder, RangedInstance rangedInstance) + private StringBuilder GenerateRangedInstanceFunction(StringBuilder stringBuilder, RangedInstance rangedInstance) { stringBuilder = stringBuilder .AppendLine( diff --git a/Main/CodeBuilding/ScopeCodeBuilder.cs b/Main/CodeBuilding/ScopeCodeBuilder.cs index 6a83dcb4..9869e5e5 100644 --- a/Main/CodeBuilding/ScopeCodeBuilder.cs +++ b/Main/CodeBuilding/ScopeCodeBuilder.cs @@ -45,10 +45,11 @@ public ScopeCodeBuilder( IContainerInfo containerInfo, ScopeResolution scopeResolution, TransientScopeInterfaceResolution transientScopeInterfaceResolution, + ContainerResolution containerResolution, // dependencies WellKnownTypes wellKnownTypes) - : base(wellKnownTypes) + : base(scopeResolution, containerResolution, wellKnownTypes) { _containerInfo = containerInfo; _scopeResolution = scopeResolution; diff --git a/Main/CodeBuilding/TransientScopeCodeBuilder.cs b/Main/CodeBuilding/TransientScopeCodeBuilder.cs index 742cf5f6..2ab14058 100644 --- a/Main/CodeBuilding/TransientScopeCodeBuilder.cs +++ b/Main/CodeBuilding/TransientScopeCodeBuilder.cs @@ -9,6 +9,7 @@ internal class TransientScopeCodeBuilder : RangeCodeBaseBuilder, ITransientScope { private readonly IContainerInfo _containerInfo; private readonly TransientScopeResolution _transientScopeResolution; + private readonly ContainerResolution _containerResolution; public override StringBuilder Build(StringBuilder stringBuilder) { @@ -17,7 +18,7 @@ public override StringBuilder Build(StringBuilder stringBuilder) stringBuilder = stringBuilder .AppendLine( - $"internal partial class {_transientScopeResolution.Name} : {WellKnownTypes.Disposable.FullName()}") + $"internal partial class {_transientScopeResolution.Name} : {_containerResolution.TransientScopeInterface.Name}, {WellKnownTypes.Disposable.FullName()}") .AppendLine($"{{") .AppendLine($"private readonly {_containerInfo.FullName} {_transientScopeResolution.ContainerReference};") .AppendLine($"internal {_transientScopeResolution.Name}(") @@ -40,12 +41,14 @@ public TransientScopeCodeBuilder( // parameter IContainerInfo containerInfo, TransientScopeResolution transientScopeResolution, + ContainerResolution containerResolution, // dependencies WellKnownTypes wellKnownTypes) - : base(wellKnownTypes) + : base(transientScopeResolution, containerResolution, wellKnownTypes) { _containerInfo = containerInfo; _transientScopeResolution = transientScopeResolution; + _containerResolution = containerResolution; } } \ No newline at end of file diff --git a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs index 8a4fb2bd..a1a45faf 100644 --- a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs +++ b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs @@ -477,6 +477,9 @@ protected Resolvable CreateConstructorResolution(ForConstructorParameter paramet checkForComposition = true; composition = withComposition.Composition; } + + var isTransientScopeRoot = + CheckTypeProperties.ShouldBeScopeRoot(implementationType) == ScopeLevel.TransientScope; return new ConstructorResolution( RootReferenceGenerator.Generate(implementationType), @@ -497,31 +500,34 @@ protected Resolvable CreateConstructorResolution(ForConstructorParameter paramet .Select(p => ProcessChildType(p.Type, p.Name, implementationType, currentParameters)) .ToList())); - (string Name, Resolvable Dependency) ProcessChildType(ITypeSymbol typeSymbol, string parameterName, INamedTypeSymbol impType, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currParameter) + (string Name, Resolvable Dependency) ProcessChildType( + ITypeSymbol typeSymbol, + string parameterName, + INamedTypeSymbol impType, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currParameter) { if (checkForDecoration && typeSymbol.Equals(decoration?.InterfaceType, SymbolEqualityComparer.Default)) - { return (parameterName, decoration.CurrentInterfaceResolution); - } if (checkForComposition && composition is {} && (typeSymbol.Equals(WellKnownTypes.Enumerable1.Construct(composition.InterfaceType), SymbolEqualityComparer.Default) || typeSymbol.Equals(WellKnownTypes.ReadOnlyCollection1.Construct(composition.InterfaceType), SymbolEqualityComparer.Default) || typeSymbol.Equals(WellKnownTypes.ReadOnlyList1.Construct(composition.InterfaceType), SymbolEqualityComparer.Default))) - { - return (parameterName, new CollectionResolution( RootReferenceGenerator.Generate(typeSymbol), typeSymbol.FullName(), composition.InterfaceType.FullName(), composition.InterfaceResolutionComposition)); - } + + if (isTransientScopeRoot + && typeSymbol.Equals(WellKnownTypes.Disposable, SymbolEqualityComparer.Default)) + return (parameterName, new TransientScopeAsDisposableResolution( + RootReferenceGenerator.Generate(WellKnownTypes.Disposable), + WellKnownTypes.Disposable.FullName())); if (typeSymbol is not INamedTypeSymbol parameterType) - { return ("", new ErrorTreeItem( $"[{impType.FullName()}] Class.Constructor.Parameter: Parameter type {typeSymbol.FullName()} is not a named type symbol")); - } return ( parameterName, diff --git a/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs b/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs index 0826011b..31605dc5 100644 --- a/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs @@ -23,6 +23,8 @@ internal class TransientScopeResolutionBuilder : RangeResolutionBaseBuilder, ITr private readonly List _rootResolutions = new (); private readonly string _containerReference; private readonly string _containerParameterReference; + private readonly string _parentDisposablesReference; + private readonly string _parentDisposablesParameterReference; private readonly Dictionary _transientScopeRootFunctionResolutions = new (); private readonly HashSet<(ScopeRootFunction, string)> _transientScopeRootFunctionQueuedOverloads = new (); @@ -55,6 +57,8 @@ internal TransientScopeResolutionBuilder( _transientScopeInterfaceResolutionBuilder = transientScopeInterfaceResolutionBuilder; _containerReference = RootReferenceGenerator.Generate("_container"); _containerParameterReference = RootReferenceGenerator.Generate("container"); + _parentDisposablesReference = RootReferenceGenerator.Generate("_parentDisposables"); + _parentDisposablesParameterReference = RootReferenceGenerator.Generate("parentDisposables"); } protected override RangedInstanceReferenceResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter) => diff --git a/Main/ResolutionTreeCreationErrorHarvester.cs b/Main/ResolutionTreeCreationErrorHarvester.cs index 066f1c3b..83af3b46 100644 --- a/Main/ResolutionTreeCreationErrorHarvester.cs +++ b/Main/ResolutionTreeCreationErrorHarvester.cs @@ -19,6 +19,8 @@ static void Inner(ResolutionTreeItem item, ICollection errorTreeI { case RootResolutionFunction: break; + case TransientScopeAsDisposableResolution: + break; case RangedInstanceReferenceResolution: break; case ScopeRootFunction: diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index 111f6bea..4b669190 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -16,6 +16,10 @@ internal record RootResolutionFunction( string RangeName, DisposalHandling DisposalHandling) : Resolvable(Reference, TypeFullName); +internal record TransientScopeAsDisposableResolution( + string Reference, + string TypeFullName) : Resolvable(Reference, TypeFullName); + internal record ErrorTreeItem( string Message) : Resolvable("error_99_99", "Error"); @@ -122,7 +126,8 @@ internal record DisposableCollectionResolution( internal abstract record RangeResolution( IReadOnlyList RootResolutions, DisposalHandling DisposalHandling, - IReadOnlyList RangedInstances) : ResolutionTreeItem; + IReadOnlyList RangedInstances, + string ContainerReference) : ResolutionTreeItem; internal record TransientScopeInterfaceResolution( IReadOnlyList Functions, @@ -138,7 +143,7 @@ internal record ScopeResolution( string TransientScopeReference, string TransientScopeParameterReference, string Name) - : RangeResolution(RootResolutions, DisposalHandling, RangedInstances); + : RangeResolution(RootResolutions, DisposalHandling, RangedInstances, ContainerReference); internal record TransientScopeResolution( IReadOnlyList RootResolutions, @@ -147,7 +152,7 @@ internal record TransientScopeResolution( string ContainerReference, string ContainerParameterReference, string Name) - : RangeResolution(RootResolutions, DisposalHandling, RangedInstances); + : RangeResolution(RootResolutions, DisposalHandling, RangedInstances, ContainerReference); internal record ContainerResolution( IReadOnlyList RootResolutions, @@ -157,7 +162,7 @@ internal record ContainerResolution( string TransientScopeAdapterReference, TransientScopeResolution DefaultTransientScope, ScopeResolution DefaultScope) - : RangeResolution(RootResolutions, DisposalHandling, RangedInstances); + : RangeResolution(RootResolutions, DisposalHandling, RangedInstances, "this"); internal record DisposalHandling( DisposableCollectionResolution DisposableCollection, diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index 172dc72b..ddae2b88 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -87,18 +87,22 @@ IContainerCodeBuilder ContainerCodeBuilderFactory( ITransientScopeCodeBuilder TransientScopeCodeBuilderFactory( IContainerInfo containerInfo, - TransientScopeResolution transientScopeResolution) => new TransientScopeCodeBuilder( + TransientScopeResolution transientScopeResolution, + ContainerResolution containerResolution) => new TransientScopeCodeBuilder( containerInfo, transientScopeResolution, + containerResolution, wellKnownTypes); IScopeCodeBuilder ScopeCodeBuilderFactory( IContainerInfo containerInfo, ScopeResolution scopeResolution, - TransientScopeInterfaceResolution transientScopeInterfaceResolution) => new ScopeCodeBuilder( + TransientScopeInterfaceResolution transientScopeInterfaceResolution, + ContainerResolution containerResolution) => new ScopeCodeBuilder( containerInfo, scopeResolution, transientScopeInterfaceResolution, + containerResolution, wellKnownTypes); } } \ No newline at end of file diff --git a/Test/TransientScopeInstanceTests.cs b/Test/TransientScopeInstanceTests.cs index d43aa0a9..8a84a2ff 100644 --- a/Test/TransientScopeInstanceTests.cs +++ b/Test/TransientScopeInstanceTests.cs @@ -1,3 +1,4 @@ +using System; using Xunit; namespace MrMeeseeks.DIE.Test; @@ -68,7 +69,7 @@ internal interface ITransientScopeWithTransientScopeInstance {} internal class TransientScopeWithTransientScopeInstance : ITransientScopeWithTransientScopeInstance, ITransientScopeRoot { - public TransientScopeWithTransientScopeInstance(ITransientScopeInstanceInner _) {} + public TransientScopeWithTransientScopeInstance(IDisposable scopeDisposal, ITransientScopeInstanceInner _) {} } internal partial class TransientScopeInstanceContainer : IContainer @@ -84,4 +85,71 @@ public void InTransientScope() using var container = new TransientScopeInstanceContainer(); var _ = ((IContainer) container).Resolve(); } +} + +internal interface ITransientScopeChild +{ + ITransientScopeInstanceInner TransientScopeInstance { get; } + bool Disposed { get; } +} + +internal class TransientScopeChild : ITransientScopeChild, IScopeRoot, IDisposable +{ + public TransientScopeChild(ITransientScopeInstanceInner transientScopeInstance) + { + TransientScopeInstance = transientScopeInstance; + } + + public ITransientScopeInstanceInner TransientScopeInstance { get; } + public bool Disposed { get; private set; } + + public void Dispose() + { + Disposed = true; + } +} + +internal interface ITransientScopeWithScopes +{ + ITransientScopeChild A { get; } + ITransientScopeChild B { get; } + void CleanUp(); +} + +internal class TransientScopeWithScopes : ITransientScopeWithScopes, ITransientScopeRoot +{ + private readonly IDisposable _scopeDisposal; + + public TransientScopeWithScopes(IDisposable scopeDisposal, ITransientScopeChild a, ITransientScopeChild b) + { + _scopeDisposal = scopeDisposal; + A = a; + B = b; + } + public ITransientScopeChild A { get; } + public ITransientScopeChild B { get; } + public void CleanUp() + { + _scopeDisposal.Dispose(); + } +} + +internal partial class TransientScopeInstanceContainer : IContainer +{ + +} + +public partial class TransientScopeInstanceTests +{ + [Fact] + public void TransientScopeWithScopes() + { + using var container = new TransientScopeInstanceContainer(); + var transientScopeRoot = ((IContainer) container).Resolve(); + Assert.NotEqual(transientScopeRoot.A, transientScopeRoot.B); + Assert.Equal(transientScopeRoot.A.TransientScopeInstance, transientScopeRoot.B.TransientScopeInstance); + transientScopeRoot.CleanUp(); + Assert.True(transientScopeRoot.A.Disposed); + Assert.True(transientScopeRoot.B.Disposed); + } } \ No newline at end of file From 1d769d37a636e11e8d176504f03638f903dbe966 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Mon, 24 Jan 2022 22:07:55 +0100 Subject: [PATCH 043/162] Implemented scope specific attributes --- Main/CheckDecorators.cs | 81 -------- Main/CheckTypeProperties.cs | 137 ------------- Main/{ => Configuration}/Attributes.cs | 28 +-- Main/Configuration/CheckTypeProperties.cs | 85 ++++++++ .../Configuration/CurrentlyConsideredTypes.cs | 183 ++++++++++++++++++ .../GetAssemblyAttributes.cs | 2 +- Main/Configuration/TypesFromAttributes.cs | 148 ++++++++++++++ Main/Constants.cs | 10 + Main/GetAllImplementations.cs | 41 ---- Main/GetSetOfTypesWithProperties.cs | 46 ----- .../ContainerResolutionBuilder.cs | 8 +- .../RangeResolutionBaseBuilder.cs | 28 ++- Main/ResolutionBuilding/ResolutionDtos.cs | 2 +- .../ScopeResolutionBuilder.cs | 8 +- .../TransientScopeResolutionBuilder.cs | 12 +- Main/SourceGenerator.cs | 89 +++++---- Main/TypeToImplementationMapper.cs | 28 --- Main/TypesFromTypeAggregatingAttributes.cs | 77 -------- Main/WellKnownTypes.cs | 4 +- Sample/Container.cs | 1 + Test/AssemblyInfo.cs | 1 + Test/CompositeTests.cs | 1 + Test/ConstructorChoiceTests.cs | 1 + Test/DecoratorTests.cs | 1 + Test/FactoryTests.cs | 49 ++++- Test/ImplementationAggregationTests.cs | 2 +- Test/ScopeSpecificAttributesTests.cs | 107 ++++++++++ 27 files changed, 679 insertions(+), 501 deletions(-) delete mode 100644 Main/CheckDecorators.cs delete mode 100644 Main/CheckTypeProperties.cs rename Main/{ => Configuration}/Attributes.cs (61%) create mode 100644 Main/Configuration/CheckTypeProperties.cs create mode 100644 Main/Configuration/CurrentlyConsideredTypes.cs rename Main/{ => Configuration}/GetAssemblyAttributes.cs (92%) create mode 100644 Main/Configuration/TypesFromAttributes.cs create mode 100644 Main/Constants.cs delete mode 100644 Main/GetAllImplementations.cs delete mode 100644 Main/GetSetOfTypesWithProperties.cs delete mode 100644 Main/TypeToImplementationMapper.cs delete mode 100644 Main/TypesFromTypeAggregatingAttributes.cs create mode 100644 Test/ScopeSpecificAttributesTests.cs diff --git a/Main/CheckDecorators.cs b/Main/CheckDecorators.cs deleted file mode 100644 index 0b61a31e..00000000 --- a/Main/CheckDecorators.cs +++ /dev/null @@ -1,81 +0,0 @@ -namespace MrMeeseeks.DIE; - -internal interface ICheckDecorators -{ - bool ShouldBeDecorated(INamedTypeSymbol interfaceType); - bool IsDecorator(INamedTypeSymbol implementationType); - IReadOnlyList GetSequenceFor(INamedTypeSymbol interfaceType, INamedTypeSymbol implementationType); -} - -internal class CheckDecorators : ICheckDecorators -{ - private readonly IImmutableSet _decoratorTypes; - private readonly IDictionary> _interfaceToDecorators; - private readonly IDictionary> _interfaceSequenceChoices; - private readonly IDictionary> _implementationSequenceChoices; - - internal CheckDecorators( - WellKnownTypes wellKnownTypes, - IGetAssemblyAttributes getAssemblyAttributes, - ITypesFromTypeAggregatingAttributes typesFromTypeAggregatingAttributes, - IGetSetOfTypesWithProperties getSetOfTypesWithProperties) - { - _decoratorTypes = getSetOfTypesWithProperties.Get(typesFromTypeAggregatingAttributes.Decorator); - _interfaceToDecorators = _decoratorTypes - .OfType() - .GroupBy(nts => - { - var namedTypeSymbol = nts.AllInterfaces - .Single(t => - typesFromTypeAggregatingAttributes.Decorator.Contains(t.OriginalDefinition, SymbolEqualityComparer.Default)); - return namedTypeSymbol.TypeArguments.First(); - }, SymbolEqualityComparer.Default) - .ToDictionary(g => g.Key, g => g.ToList(), SymbolEqualityComparer.Default); - var sequenceChoices = getAssemblyAttributes - .AllAssemblyAttributes - .Where(ad => - ad.AttributeClass?.Equals(wellKnownTypes.DecoratorSequenceChoiceAttribute, - SymbolEqualityComparer.Default) ?? false) - .Select(ad => - { - if (ad.ConstructorArguments.Length < 2) - return null; - var decoratedType = ad.ConstructorArguments[0].Value; - var decorators = ad - .ConstructorArguments[1] - .Values - .Select(tc => tc.Value) - .OfType() - .ToList(); - - return decoratedType is null - ? null - : ((INamedTypeSymbol, IReadOnlyList)?) (decoratedType, decorators); - }) - .OfType<(INamedTypeSymbol, IReadOnlyList)>() - .ToList(); - - _interfaceSequenceChoices = sequenceChoices - .Where(t => t.Item1.TypeKind == TypeKind.Interface) - .ToDictionary(t => t.Item1, t => t.Item2); - - _implementationSequenceChoices = sequenceChoices - .Where(t => t.Item1.TypeKind == TypeKind.Class || t.Item1.TypeKind == TypeKind.Struct) - .ToDictionary(t => t.Item1, t => t.Item2); - } - - public bool ShouldBeDecorated(INamedTypeSymbol interfaceType) => _interfaceToDecorators.ContainsKey(interfaceType); - public bool IsDecorator(INamedTypeSymbol implementationType) => _decoratorTypes.Contains(implementationType); - - public IReadOnlyList GetSequenceFor(INamedTypeSymbol interfaceType, INamedTypeSymbol implementationType) - { - if (_implementationSequenceChoices.TryGetValue(implementationType, out var implementationSequence)) - return implementationSequence; - if (_interfaceSequenceChoices.TryGetValue(interfaceType, out var interfaceSequence)) - return interfaceSequence; - if (_interfaceToDecorators.TryGetValue(interfaceType, out var allDecorators) - && allDecorators.Count == 1) - return allDecorators; - throw new Exception("Couldn't find unambiguous sequence of decorators"); - } -} \ No newline at end of file diff --git a/Main/CheckTypeProperties.cs b/Main/CheckTypeProperties.cs deleted file mode 100644 index 1cdb7ce2..00000000 --- a/Main/CheckTypeProperties.cs +++ /dev/null @@ -1,137 +0,0 @@ -namespace MrMeeseeks.DIE; - -internal enum ScopeLevel -{ - None, - Scope, - TransientScope, - Container -} - -internal interface ICheckTypeProperties -{ - bool ShouldBeManaged(INamedTypeSymbol implementationType); - ScopeLevel ShouldBeScopeRoot(INamedTypeSymbol implementationType); - bool ShouldBeComposite(INamedTypeSymbol interfaceType); - ScopeLevel GetScopeLevelFor(INamedTypeSymbol implementationType); - INamedTypeSymbol GetCompositeFor(INamedTypeSymbol interfaceType); - bool IsComposite(INamedTypeSymbol implementationType); - IMethodSymbol? GetConstructorChoiceFor(INamedTypeSymbol implementationType); -} - -internal class CheckTypeProperties : ICheckTypeProperties -{ - private readonly IImmutableSet _transientTypes; - private readonly IImmutableSet _containerInstanceTypes; - private readonly IImmutableSet _transientScopeInstanceTypes; - private readonly IImmutableSet _scopeInstanceTypes; - private readonly IImmutableSet _transientScopeRootTypes; - private readonly IImmutableSet _scopeRootTypes; - private readonly IImmutableSet _compositeTypes; - private readonly Dictionary _interfaceToComposite; - private readonly Dictionary _implementationToConstructorChoice; - - internal CheckTypeProperties( - ITypesFromTypeAggregatingAttributes typesFromTypeAggregatingAttributes, - IGetAssemblyAttributes getAssemblyAttributes, - WellKnownTypes wellKnownTypes, - IGetSetOfTypesWithProperties getSetOfTypesWithProperties) - { - _transientTypes = getSetOfTypesWithProperties.Get(typesFromTypeAggregatingAttributes.Transient); - _containerInstanceTypes = getSetOfTypesWithProperties.Get(typesFromTypeAggregatingAttributes.ContainerInstance); - _transientScopeInstanceTypes = getSetOfTypesWithProperties.Get(typesFromTypeAggregatingAttributes.TransientScopeInstance); - _scopeInstanceTypes = getSetOfTypesWithProperties.Get(typesFromTypeAggregatingAttributes.ScopeInstance); - _transientScopeRootTypes = getSetOfTypesWithProperties.Get(typesFromTypeAggregatingAttributes.TransientScopeRoot); - _scopeRootTypes = getSetOfTypesWithProperties.Get(typesFromTypeAggregatingAttributes.ScopeRoot); - _compositeTypes = getSetOfTypesWithProperties.Get(typesFromTypeAggregatingAttributes.Composite); - _interfaceToComposite = _compositeTypes - .OfType() - .GroupBy(nts => - { - var namedTypeSymbol = nts.AllInterfaces - .Single(t => - typesFromTypeAggregatingAttributes.Composite.Contains(t.OriginalDefinition, SymbolEqualityComparer.Default)); - return namedTypeSymbol.TypeArguments.First(); - }, SymbolEqualityComparer.Default) - .Where(g => g.Count() == 1) - .ToDictionary(g => g.Key, g => g.Single(), SymbolEqualityComparer.Default); - - _implementationToConstructorChoice = getAssemblyAttributes - .AllAssemblyAttributes - .Concat(getAssemblyAttributes - .AllAssemblyAttributes - .Where(ad => - ad.AttributeClass?.Equals(wellKnownTypes.SpyConstructorChoiceAggregationAttribute, - SymbolEqualityComparer.Default) ?? false) - .SelectMany(ad => ad - .ConstructorArguments - .Where(ca => ca.Kind == TypedConstantKind.Enum) - .Select(ca => ca.Value as INamedTypeSymbol) - .OfType() - .SelectMany(e => e.GetAttributes()))) - .Where(ad => - ad.AttributeClass?.Equals(wellKnownTypes.ConstructorChoiceAttribute, - SymbolEqualityComparer.Default) ?? false) - .Select(ad => - { - if (ad.ConstructorArguments.Length < 2) - return null; - var implementationType = ad.ConstructorArguments[0].Value as INamedTypeSymbol; - var parameterTypes = ad - .ConstructorArguments[1] - .Values - .Select(tc => tc.Value) - .OfType() - .ToList(); - - if (implementationType is { }) - { - var constructorChoice = implementationType - .Constructors - .Where(c => c.Parameters.Length == parameterTypes.Count) - .SingleOrDefault(c => c.Parameters.Select(p => p.Type) - .Zip(parameterTypes, (pLeft, pRight) => pLeft.Equals(pRight, SymbolEqualityComparer.Default)) - .All(b => b)); - return constructorChoice is { } - ? (implementationType, constructorChoice) - : ((INamedTypeSymbol, IMethodSymbol)?) null; - } - - return null; - }) - .OfType<(INamedTypeSymbol, IMethodSymbol)>() - .ToDictionary(t => t.Item1, t => t.Item2); - } - - public bool ShouldBeManaged(INamedTypeSymbol implementationType) => !_transientTypes.Contains(implementationType); - public ScopeLevel ShouldBeScopeRoot(INamedTypeSymbol implementationType) - { - if (_transientScopeRootTypes.Contains(implementationType)) return ScopeLevel.TransientScope; - return _scopeRootTypes.Contains(implementationType) ? ScopeLevel.Scope : ScopeLevel.None; - } - - public bool ShouldBeComposite(INamedTypeSymbol interfaceType) => _interfaceToComposite.ContainsKey(interfaceType); - public ScopeLevel GetScopeLevelFor(INamedTypeSymbol implementationType) - { - if (_containerInstanceTypes.Contains(implementationType)) - return ScopeLevel.Container; - if (_transientScopeInstanceTypes.Contains(implementationType)) - return ScopeLevel.TransientScope; - if (_scopeInstanceTypes.Contains(implementationType)) - return ScopeLevel.Scope; - return ScopeLevel.None; - } - - public INamedTypeSymbol GetCompositeFor(INamedTypeSymbol interfaceType) => _interfaceToComposite[interfaceType]; - public bool IsComposite(INamedTypeSymbol implementationType) => _compositeTypes.Contains(implementationType); - public IMethodSymbol? GetConstructorChoiceFor(INamedTypeSymbol implementationType) - { - if (implementationType.Constructors.Length == 1 - && implementationType.Constructors.SingleOrDefault() is { } constructor) - return constructor; - - return _implementationToConstructorChoice.TryGetValue(implementationType, out var constr) - ? constr : - null; - } -} \ No newline at end of file diff --git a/Main/Attributes.cs b/Main/Configuration/Attributes.cs similarity index 61% rename from Main/Attributes.cs rename to Main/Configuration/Attributes.cs index ea3c0a89..a6244325 100644 --- a/Main/Attributes.cs +++ b/Main/Configuration/Attributes.cs @@ -1,79 +1,79 @@ -namespace MrMeeseeks.DIE; +namespace MrMeeseeks.DIE.Configuration; // ReSharper disable UnusedParameter.Local *** The constructor parameters of the attributes will be used. Trust me, imma dev. -[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class SpyAggregationAttribute : Attribute { public SpyAggregationAttribute(params Type[] types) {} } -[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class SpyConstructorChoiceAggregationAttribute : Attribute { public SpyConstructorChoiceAggregationAttribute(params Enum[] references) {} } -[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class ImplementationAggregationAttribute : Attribute { public ImplementationAggregationAttribute(params Type[] types) {} } -[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class TransientAggregationAttribute : Attribute { public TransientAggregationAttribute(params Type[] types) {} } -[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class ContainerInstanceAggregationAttribute : Attribute { public ContainerInstanceAggregationAttribute(params Type[] types) {} } -[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class TransientScopeInstanceAggregationAttribute : Attribute { public TransientScopeInstanceAggregationAttribute(params Type[] types) {} } -[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class ScopeInstanceAggregationAttribute : Attribute { public ScopeInstanceAggregationAttribute(params Type[] types) {} } -[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class TransientScopeRootAggregationAttribute : Attribute { public TransientScopeRootAggregationAttribute(params Type[] types) {} } -[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class ScopeRootAggregationAttribute : Attribute { public ScopeRootAggregationAttribute(params Type[] types) {} } -[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class DecoratorAggregationAttribute : Attribute { public DecoratorAggregationAttribute(params Type[] types) {} } -[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class CompositeAggregationAttribute : Attribute { public CompositeAggregationAttribute(params Type[] types) {} } -[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class DecoratorSequenceChoiceAttribute : Attribute { public DecoratorSequenceChoiceAttribute(Type decoratedType, params Type[] types) {} } -[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class ConstructorChoiceAttribute : Attribute { public ConstructorChoiceAttribute(Type implementationType, params Type[] parameterTypes) diff --git a/Main/Configuration/CheckTypeProperties.cs b/Main/Configuration/CheckTypeProperties.cs new file mode 100644 index 00000000..df1d3816 --- /dev/null +++ b/Main/Configuration/CheckTypeProperties.cs @@ -0,0 +1,85 @@ +namespace MrMeeseeks.DIE.Configuration; + +internal enum ScopeLevel +{ + None, + Scope, + TransientScope, + Container +} + +internal interface ICheckTypeProperties +{ + bool ShouldBeManaged(INamedTypeSymbol implementationType); + ScopeLevel ShouldBeScopeRoot(INamedTypeSymbol implementationType); + bool ShouldBeComposite(INamedTypeSymbol interfaceType); + ScopeLevel GetScopeLevelFor(INamedTypeSymbol implementationType); + INamedTypeSymbol GetCompositeFor(INamedTypeSymbol interfaceType); + IMethodSymbol? GetConstructorChoiceFor(INamedTypeSymbol implementationType); + + bool ShouldBeDecorated(INamedTypeSymbol interfaceType); + IReadOnlyList GetSequenceFor(INamedTypeSymbol interfaceType, INamedTypeSymbol implementationType); + + IReadOnlyList MapToImplementations(ITypeSymbol typeSymbol); +} + +internal class CheckTypeProperties : ICheckTypeProperties +{ + private readonly ICurrentlyConsideredTypes _currentlyConsideredTypes; + + internal CheckTypeProperties( + ICurrentlyConsideredTypes currentlyConsideredTypes) + { + _currentlyConsideredTypes = currentlyConsideredTypes; + } + + public bool ShouldBeManaged(INamedTypeSymbol implementationType) => !_currentlyConsideredTypes.TransientTypes.Contains(implementationType); + public ScopeLevel ShouldBeScopeRoot(INamedTypeSymbol implementationType) + { + if (_currentlyConsideredTypes.TransientScopeRootTypes.Contains(implementationType)) return ScopeLevel.TransientScope; + return _currentlyConsideredTypes.ScopeRootTypes.Contains(implementationType) ? ScopeLevel.Scope : ScopeLevel.None; + } + + public bool ShouldBeComposite(INamedTypeSymbol interfaceType) => _currentlyConsideredTypes.InterfaceToComposite.ContainsKey(interfaceType); + public ScopeLevel GetScopeLevelFor(INamedTypeSymbol implementationType) + { + if (_currentlyConsideredTypes.ContainerInstanceTypes.Contains(implementationType)) + return ScopeLevel.Container; + if (_currentlyConsideredTypes.TransientScopeInstanceTypes.Contains(implementationType)) + return ScopeLevel.TransientScope; + if (_currentlyConsideredTypes.ScopeInstanceTypes.Contains(implementationType)) + return ScopeLevel.Scope; + return ScopeLevel.None; + } + + public INamedTypeSymbol GetCompositeFor(INamedTypeSymbol interfaceType) => _currentlyConsideredTypes.InterfaceToComposite[interfaceType]; + public IMethodSymbol? GetConstructorChoiceFor(INamedTypeSymbol implementationType) + { + if (implementationType.Constructors.Length == 1 + && implementationType.Constructors.SingleOrDefault() is { } constructor) + return constructor; + + return _currentlyConsideredTypes.ImplementationToConstructorChoice.TryGetValue(implementationType, out var constr) + ? constr : + null; + } + + public bool ShouldBeDecorated(INamedTypeSymbol interfaceType) => _currentlyConsideredTypes.InterfaceToDecorators.ContainsKey(interfaceType); + + public IReadOnlyList GetSequenceFor(INamedTypeSymbol interfaceType, INamedTypeSymbol implementationType) + { + if (_currentlyConsideredTypes.ImplementationSequenceChoices.TryGetValue(implementationType, out var implementationSequence)) + return implementationSequence; + if (_currentlyConsideredTypes.InterfaceSequenceChoices.TryGetValue(interfaceType, out var interfaceSequence)) + return interfaceSequence; + if (_currentlyConsideredTypes.InterfaceToDecorators.TryGetValue(interfaceType, out var allDecorators) + && allDecorators.Count == 1) + return allDecorators; + throw new Exception("Couldn't find unambiguous sequence of decorators"); + } + + public IReadOnlyList MapToImplementations(ITypeSymbol typeSymbol) => + _currentlyConsideredTypes.ImplementationMap.TryGetValue(typeSymbol, out var implementations) + ? implementations + : new List(); +} \ No newline at end of file diff --git a/Main/Configuration/CurrentlyConsideredTypes.cs b/Main/Configuration/CurrentlyConsideredTypes.cs new file mode 100644 index 00000000..7adf9237 --- /dev/null +++ b/Main/Configuration/CurrentlyConsideredTypes.cs @@ -0,0 +1,183 @@ +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace MrMeeseeks.DIE.Configuration; + +internal interface ICurrentlyConsideredTypes +{ + IImmutableSet TransientTypes { get; } + IImmutableSet ContainerInstanceTypes { get; } + IImmutableSet TransientScopeInstanceTypes { get; } + IImmutableSet ScopeInstanceTypes { get; } + IImmutableSet TransientScopeRootTypes { get; } + IImmutableSet ScopeRootTypes { get; } + IReadOnlyDictionary InterfaceToComposite { get; } + IReadOnlyDictionary ImplementationToConstructorChoice { get; } + IReadOnlyDictionary> InterfaceToDecorators { get; } + IReadOnlyDictionary> InterfaceSequenceChoices { get; } + IReadOnlyDictionary> ImplementationSequenceChoices { get; } + IReadOnlyDictionary> ImplementationMap { get; } +} + +internal class CurrentlyConsideredTypes : ICurrentlyConsideredTypes +{ + public CurrentlyConsideredTypes( + IReadOnlyList typesFromAttributes, + GeneratorExecutionContext context) + { + var tempAllImplementations = new List(); + + tempAllImplementations.AddRange(context.Compilation.SyntaxTrees + .Select(st => (st, context.Compilation.GetSemanticModel(st))) + .SelectMany(t => t.st + .GetRoot() + .DescendantNodesAndSelf() + .Where(e => e is ClassDeclarationSyntax or StructDeclarationSyntax or RecordDeclarationSyntax) + .Select(c => t.Item2.GetDeclaredSymbol(c)) + .Where(c => c is not null) + .OfType())); + + foreach (var types in typesFromAttributes) + { + var spiedImplementations = types + .Spy + .SelectMany(t => t?.GetMembers() + .OfType() + .Where(ms => !ms.ReturnsVoid) + .Select(ms => ms.ReturnType) + .OfType()); + + tempAllImplementations.AddRange(types.Implementation + .Concat(spiedImplementations)); + } + + var allImplementations = tempAllImplementations; + + TransientTypes = GetSetOfTypesWithProperties(t => t.Transient); + ContainerInstanceTypes = GetSetOfTypesWithProperties(t => t.ContainerInstance); + TransientScopeInstanceTypes = GetSetOfTypesWithProperties(t => t.TransientScopeInstance); + ScopeInstanceTypes = GetSetOfTypesWithProperties(t => t.ScopeInstance); + TransientScopeRootTypes = GetSetOfTypesWithProperties(t => t.TransientScopeRoot); + ScopeRootTypes = GetSetOfTypesWithProperties(t => t.ScopeRoot); + + var compositeInterfaces = ImmutableHashSet.Empty; + foreach (var types in typesFromAttributes) + { + compositeInterfaces = compositeInterfaces.Union(types.Composite); + } + + var compositeTypes = GetSetOfTypesWithProperties(t => t.Composite); + InterfaceToComposite = compositeTypes + .OfType() + .GroupBy(nts => + { + var namedTypeSymbol = nts.AllInterfaces + .Single(t => compositeInterfaces.Contains(t.OriginalDefinition, SymbolEqualityComparer.Default)); + return namedTypeSymbol.TypeArguments.First(); + }, SymbolEqualityComparer.Default) + .Where(g => g.Count() == 1) + .ToDictionary(g => g.Key, g => g.Single(), SymbolEqualityComparer.Default); + + var constructorChoices = new Dictionary(SymbolEqualityComparer.Default); + + foreach (var types in typesFromAttributes) + { + foreach (var constructorChoice in types.ConstructorChoices) + { + constructorChoices[constructorChoice.Item1] = constructorChoice.Item2; + } + } + + ImplementationToConstructorChoice = constructorChoices; + + var decoratorInterfaces = ImmutableHashSet.Empty; + foreach (var types in typesFromAttributes) + { + decoratorInterfaces = decoratorInterfaces.Union(types.Decorator); + } + + var decoratorTypes = GetSetOfTypesWithProperties(t => t.Decorator); + InterfaceToDecorators = decoratorTypes + .OfType() + .GroupBy(nts => + { + var namedTypeSymbol = nts.AllInterfaces + .Single(t => decoratorInterfaces.Contains(t.OriginalDefinition, SymbolEqualityComparer.Default)); + return namedTypeSymbol.TypeArguments.First(); + }, SymbolEqualityComparer.Default) + .ToDictionary(g => g.Key, g => (IReadOnlyList) g.ToList(), SymbolEqualityComparer.Default); + + var decoratorSequenceChoices = new Dictionary>(SymbolEqualityComparer.Default); + + foreach (var types in typesFromAttributes) + { + foreach (var decoratorSequenceChoice in types.DecoratorSequenceChoices) + { + decoratorSequenceChoices[decoratorSequenceChoice.Item1] = decoratorSequenceChoice.Item2; + } + } + + InterfaceSequenceChoices = decoratorSequenceChoices + .Where(kvp => kvp.Key.TypeKind == TypeKind.Interface) + .ToDictionary(kvp => kvp.Key, kvp => kvp.Value); + + ImplementationSequenceChoices = decoratorSequenceChoices + .Where(kvp => kvp.Key.TypeKind is TypeKind.Class or TypeKind.Struct) + .ToDictionary(kvp => kvp.Key, kvp => kvp.Value); + + ImplementationMap = allImplementations + .Where(t => !decoratorTypes.Contains(t.OriginalDefinition)) + .Where(t => !compositeTypes.Contains(t.OriginalDefinition)) + .SelectMany(i => { return i.AllInterfaces.OfType().Select(ii => (ii, i)).Prepend((i, i)); }) + .GroupBy(t => t.Item1, t => t.Item2) + .ToDictionary(g => g.Key, g => (IReadOnlyList) g.Distinct(SymbolEqualityComparer.Default).OfType().ToList()); + + IImmutableSet GetSetOfTypesWithProperties(Func> propertyGivingTypesGetter) + { + var tempSet = ImmutableHashSet.Empty; + foreach (var types in typesFromAttributes) + { + var propertyGivingTypes = propertyGivingTypesGetter(types); + tempSet = tempSet.Union(allImplementations + .Where(i => + { + var derivedTypes = AllDerivedTypes(i).Select(t => t.OriginalDefinition).ToList(); + return propertyGivingTypes.Any(t => + derivedTypes.Contains(t.OriginalDefinition, SymbolEqualityComparer.Default)); + }) + .Distinct(SymbolEqualityComparer.Default) + .ToImmutableHashSet(SymbolEqualityComparer.Default)); + } + + return tempSet; + + + IEnumerable AllDerivedTypes(INamedTypeSymbol type) + { + var concreteTypes = new List(); + var temp = type; + while (temp is {}) + { + concreteTypes.Add(temp); + temp = temp.BaseType; + } + return type + .AllInterfaces + .Append(type) + .Concat(concreteTypes); + } + } + } + + public IImmutableSet TransientTypes { get; } + public IImmutableSet ContainerInstanceTypes { get; } + public IImmutableSet TransientScopeInstanceTypes { get; } + public IImmutableSet ScopeInstanceTypes { get; } + public IImmutableSet TransientScopeRootTypes { get; } + public IImmutableSet ScopeRootTypes { get; } + public IReadOnlyDictionary InterfaceToComposite { get; } + public IReadOnlyDictionary ImplementationToConstructorChoice { get; } + public IReadOnlyDictionary> InterfaceToDecorators { get; } + public IReadOnlyDictionary> InterfaceSequenceChoices { get; } + public IReadOnlyDictionary> ImplementationSequenceChoices { get; } + public IReadOnlyDictionary> ImplementationMap { get; } +} \ No newline at end of file diff --git a/Main/GetAssemblyAttributes.cs b/Main/Configuration/GetAssemblyAttributes.cs similarity index 92% rename from Main/GetAssemblyAttributes.cs rename to Main/Configuration/GetAssemblyAttributes.cs index 0a2193d9..fbfa5e62 100644 --- a/Main/GetAssemblyAttributes.cs +++ b/Main/Configuration/GetAssemblyAttributes.cs @@ -1,4 +1,4 @@ -namespace MrMeeseeks.DIE; +namespace MrMeeseeks.DIE.Configuration; internal interface IGetAssemblyAttributes { diff --git a/Main/Configuration/TypesFromAttributes.cs b/Main/Configuration/TypesFromAttributes.cs new file mode 100644 index 00000000..676a4c64 --- /dev/null +++ b/Main/Configuration/TypesFromAttributes.cs @@ -0,0 +1,148 @@ +namespace MrMeeseeks.DIE.Configuration; + +internal interface ITypesFromAttributes +{ + IReadOnlyList Spy { get; } + IReadOnlyList Implementation { get; } + IReadOnlyList Transient { get; } + IReadOnlyList ContainerInstance { get; } + IReadOnlyList TransientScopeInstance { get; } + IReadOnlyList ScopeInstance { get; } + IReadOnlyList TransientScopeRoot { get; } + IReadOnlyList ScopeRoot { get; } + IReadOnlyList Decorator { get; } + IReadOnlyList Composite { get; } + IReadOnlyList<(INamedTypeSymbol, IReadOnlyList)> DecoratorSequenceChoices { get; } + IReadOnlyList<(INamedTypeSymbol, IMethodSymbol)> ConstructorChoices { get; } +} + +internal class TypesFromAttributes : ScopeTypesFromAttributes +{ + internal TypesFromAttributes( + // parameter + IReadOnlyList attributeData, + + // dependencies + WellKnownTypes wellKnownTypes) : base(attributeData, wellKnownTypes) + { + ContainerInstance = GetTypesFromAttribute(wellKnownTypes.ContainerInstanceAggregationAttribute).ToList(); + TransientScopeInstance = GetTypesFromAttribute(wellKnownTypes.TransientScopeInstanceAggregationAttribute).ToList(); + TransientScopeRoot = GetTypesFromAttribute(wellKnownTypes.TransientScopeRootAggregationAttribute).ToList(); + ScopeRoot = GetTypesFromAttribute(wellKnownTypes.ScopeRootAggregationAttribute).ToList(); + } +} + +internal class ScopeTypesFromAttributes : ITypesFromAttributes +{ + internal ScopeTypesFromAttributes( + // parameter + IReadOnlyList attributeData, + + // dependencies + WellKnownTypes wellKnownTypes) + { + AttributeDictionary = attributeData + .GroupBy(ad => ad.AttributeClass, SymbolEqualityComparer.Default) + .ToDictionary(g => g.Key, g => g); + + Spy = GetTypesFromAttribute(wellKnownTypes.SpyAggregationAttribute).ToList(); + Implementation = GetTypesFromAttribute(wellKnownTypes.ImplementationAggregationAttribute).ToList(); + Transient = GetTypesFromAttribute(wellKnownTypes.TransientAggregationAttribute).ToList(); + ContainerInstance = new List(); + TransientScopeInstance = new List(); + ScopeInstance = GetTypesFromAttribute(wellKnownTypes.ScopeInstanceAggregationAttribute).ToList(); + TransientScopeRoot = new List(); + ScopeRoot = new List(); + Decorator = GetTypesFromAttribute(wellKnownTypes.DecoratorAggregationAttribute).ToList(); + Composite = GetTypesFromAttribute(wellKnownTypes.CompositeAggregationAttribute).ToList(); + + DecoratorSequenceChoices = (AttributeDictionary.TryGetValue(wellKnownTypes.DecoratorSequenceChoiceAttribute, out var group) ? group : Enumerable.Empty()) + .Select(ad => + { + if (ad.ConstructorArguments.Length < 2) + return null; + var decoratedType = ad.ConstructorArguments[0].Value; + var decorators = ad + .ConstructorArguments[1] + .Values + .Select(tc => tc.Value) + .OfType() + .ToList(); + + return decoratedType is null + ? null + : ((INamedTypeSymbol, IReadOnlyList)?) (decoratedType, decorators); + }) + .OfType<(INamedTypeSymbol, IReadOnlyList)>() + .ToList(); + + ConstructorChoices = (AttributeDictionary.TryGetValue(wellKnownTypes.ConstructorChoiceAttribute, out var group0) ? group0 : Enumerable.Empty()) + .Select(ad => + { + if (ad.ConstructorArguments.Length < 2) + return null; + var implementationType = ad.ConstructorArguments[0].Value as INamedTypeSymbol; + var parameterTypes = ad + .ConstructorArguments[1] + .Values + .Select(tc => tc.Value) + .OfType() + .ToList(); + + if (implementationType is { }) + { + var constructorChoice = implementationType + .Constructors + .Where(c => c.Parameters.Length == parameterTypes.Count) + .SingleOrDefault(c => c.Parameters.Select(p => p.Type) + .Zip(parameterTypes, + (pLeft, pRight) => pLeft.Equals(pRight, SymbolEqualityComparer.Default)) + .All(b => b)); + return constructorChoice is { } + ? (implementationType, constructorChoice) + : ((INamedTypeSymbol, IMethodSymbol)?)null; + } + + return null; + }) + .OfType<(INamedTypeSymbol, IMethodSymbol)>() + .ToList(); + } + + private IReadOnlyDictionary> AttributeDictionary { get; } + + protected IEnumerable GetTypesFromAttribute( + INamedTypeSymbol attribute) + { + return (AttributeDictionary.TryGetValue(attribute, out var group1) ? group1 : Enumerable.Empty()) + .SelectMany(ad => ad.ConstructorArguments + .Where(tc => tc.Kind == TypedConstantKind.Type) + .OfType() + .Concat(ad.ConstructorArguments.SelectMany(ca => ca.Kind is TypedConstantKind.Array + ? (IEnumerable)ca.Values + : Array.Empty()))) + .Select(tc => !CheckValidType(tc, out var type) ? null : type) + .Where(t => t is not null) + .OfType() + .Select(t => t.OriginalDefinition); + + bool CheckValidType(TypedConstant typedConstant, out INamedTypeSymbol type) + { + type = (typedConstant.Value as INamedTypeSymbol)!; + return typedConstant.Value is not null; + } + } + + public IReadOnlyList Spy { get; } + public IReadOnlyList Implementation { get; } + public IReadOnlyList Transient { get; } + public IReadOnlyList ContainerInstance { get; protected init; } + public IReadOnlyList TransientScopeInstance { get; protected init; } + public IReadOnlyList ScopeInstance { get; } + public IReadOnlyList TransientScopeRoot { get; protected init; } + public IReadOnlyList ScopeRoot { get; protected init; } + public IReadOnlyList Decorator { get; } + public IReadOnlyList Composite { get; } + public IReadOnlyList<(INamedTypeSymbol, IReadOnlyList)> DecoratorSequenceChoices { get; } + public IReadOnlyList<(INamedTypeSymbol, IMethodSymbol)> ConstructorChoices { get; } +} \ No newline at end of file diff --git a/Main/Constants.cs b/Main/Constants.cs new file mode 100644 index 00000000..8bd59b15 --- /dev/null +++ b/Main/Constants.cs @@ -0,0 +1,10 @@ +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace MrMeeseeks.DIE; + +internal static class Constants +{ + internal const string ThisKeyword = "this"; + internal const string DefaultScopeName = "DIE_DefaultScope"; + internal const string DefaultTransientScopeName = "DIE_DefaultTransientScope"; +} \ No newline at end of file diff --git a/Main/GetAllImplementations.cs b/Main/GetAllImplementations.cs deleted file mode 100644 index d1eb618c..00000000 --- a/Main/GetAllImplementations.cs +++ /dev/null @@ -1,41 +0,0 @@ -using Microsoft.CodeAnalysis.CSharp.Syntax; - -namespace MrMeeseeks.DIE; - -internal interface IGetAllImplementations -{ - IReadOnlyList AllImplementations { get; } -} - -internal class GetAllImplementations : IGetAllImplementations -{ - internal GetAllImplementations( - GeneratorExecutionContext context, - ITypesFromTypeAggregatingAttributes typesFromTypeAggregatingAttributes) - { - var implementationsOfThisAssembly = context.Compilation.SyntaxTrees - .Select(st => (st, context.Compilation.GetSemanticModel(st))) - .SelectMany(t => t.st - .GetRoot() - .DescendantNodesAndSelf() - .Where(e => e is ClassDeclarationSyntax or StructDeclarationSyntax or RecordDeclarationSyntax) - .Select(c => t.Item2.GetDeclaredSymbol(c)) - .Where(c => c is not null) - .OfType()); - - var spiedImplementations = typesFromTypeAggregatingAttributes - .Spy - .SelectMany(t => t?.GetMembers() - .OfType() - .Where(ms => !ms.ReturnsVoid) - .Select(ms => ms.ReturnType) - .OfType()); - - AllImplementations = implementationsOfThisAssembly - .Concat(typesFromTypeAggregatingAttributes.Implementation) - .Concat(spiedImplementations) - .ToList(); - } - - public IReadOnlyList AllImplementations { get; } -} \ No newline at end of file diff --git a/Main/GetSetOfTypesWithProperties.cs b/Main/GetSetOfTypesWithProperties.cs deleted file mode 100644 index ecb275aa..00000000 --- a/Main/GetSetOfTypesWithProperties.cs +++ /dev/null @@ -1,46 +0,0 @@ -namespace MrMeeseeks.DIE; - -internal interface IGetSetOfTypesWithProperties -{ - IImmutableSet Get(IReadOnlyList propertyGivingTypes); -} - -internal class GetSetOfTypesWithProperties : IGetSetOfTypesWithProperties -{ - private readonly IGetAllImplementations _getAllImplementations; - - internal GetSetOfTypesWithProperties(IGetAllImplementations getAllImplementations) - { - _getAllImplementations = getAllImplementations; - } - - public IImmutableSet Get(IReadOnlyList propertyGivingTypes) - { - return _getAllImplementations - .AllImplementations - .Where(i => - { - var derivedTypes = AllDerivedTypes(i).Select(t => t.OriginalDefinition).ToList(); - return propertyGivingTypes.Any(t => - derivedTypes.Contains(t.OriginalDefinition, SymbolEqualityComparer.Default)); - }) - .Distinct(SymbolEqualityComparer.Default) - .ToImmutableHashSet(SymbolEqualityComparer.Default); - - - IEnumerable AllDerivedTypes(INamedTypeSymbol type) - { - var concreteTypes = new List(); - var temp = type; - while (temp is {}) - { - concreteTypes.Add(temp); - temp = temp.BaseType; - } - return type - .AllInterfaces - .Append(type) - .Concat(concreteTypes); - } - } -} \ No newline at end of file diff --git a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs index b964d8ad..b87e8b5b 100644 --- a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs @@ -1,3 +1,5 @@ +using MrMeeseeks.DIE.Configuration; + namespace MrMeeseeks.DIE.ResolutionBuilding; internal interface IContainerResolutionBuilder @@ -27,21 +29,17 @@ internal ContainerResolutionBuilder( // dependencies ITransientScopeInterfaceResolutionBuilder transientScopeInterfaceResolutionBuilder, - ITypeToImplementationsMapper typeToImplementationsMapper, IReferenceGeneratorFactory referenceGeneratorFactory, ICheckTypeProperties checkTypeProperties, - ICheckDecorators checkDecorators, WellKnownTypes wellKnownTypes, Func transientScopeResolutionBuilderFactory, Func scopeResolutionBuilderFactory, IUserProvidedScopeElements userProvidedScopeElements) : base( - (containerInfo.Name, false), + containerInfo.Name, wellKnownTypes, - typeToImplementationsMapper, referenceGeneratorFactory, checkTypeProperties, - checkDecorators, userProvidedScopeElements) { _containerInfo = containerInfo; diff --git a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs index a1a45faf..2679ff68 100644 --- a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs +++ b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs @@ -1,12 +1,12 @@ +using MrMeeseeks.DIE.Configuration; + namespace MrMeeseeks.DIE.ResolutionBuilding; internal abstract class RangeResolutionBaseBuilder { protected readonly WellKnownTypes WellKnownTypes; - protected readonly ITypeToImplementationsMapper TypeToImplementationsMapper; protected readonly ICheckTypeProperties CheckTypeProperties; - protected readonly ICheckDecorators CheckDecorators; protected readonly IReferenceGenerator RootReferenceGenerator; protected readonly IDictionary RangedInstanceReferenceResolutions = @@ -22,20 +22,16 @@ internal abstract class RangeResolutionBaseBuilder protected RangeResolutionBaseBuilder( // parameters - (string, bool) name, + string name, // dependencies WellKnownTypes wellKnownTypes, - ITypeToImplementationsMapper typeToImplementationsMapper, IReferenceGeneratorFactory referenceGeneratorFactory, ICheckTypeProperties checkTypeProperties, - ICheckDecorators checkDecorators, IUserProvidedScopeElements userProvidedScopeElements) { WellKnownTypes = wellKnownTypes; - TypeToImplementationsMapper = typeToImplementationsMapper; CheckTypeProperties = checkTypeProperties; - CheckDecorators = checkDecorators; UserProvidedScopeElements = userProvidedScopeElements; RootReferenceGenerator = referenceGeneratorFactory.Create(); @@ -43,7 +39,7 @@ protected RangeResolutionBaseBuilder( RootReferenceGenerator.Generate(WellKnownTypes.ConcurrentBagOfDisposable), WellKnownTypes.ConcurrentBagOfDisposable.FullName()); - Name = name.Item2 ? RootReferenceGenerator.Generate(name.Item1) : name.Item1; + Name = name; DisposalHandling = new DisposalHandling( DisposableCollectionResolution, Name, @@ -195,8 +191,8 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup } var itemFullName = itemType.FullName(); var itemTypeIsInterface = itemType.TypeKind == TypeKind.Interface; - var items = TypeToImplementationsMapper - .Map(itemType) + var items = CheckTypeProperties + .MapToImplementations(itemType) .Select(i => itemTypeIsInterface ? SwitchInterfaceForSpecificImplementation(new SwitchInterfaceForSpecificImplementationParameter(itemType, i, currentFuncParameters)) : SwitchClass(new SwitchClassParameter(i, currentFuncParameters))) @@ -243,8 +239,8 @@ private Resolvable SwitchInterface(SwitchInterfaceParameter parameter) { var (typeSymbol, currentParameters) = parameter; var interfaceType = (INamedTypeSymbol) typeSymbol; - var implementations = TypeToImplementationsMapper - .Map(typeSymbol); + var implementations = CheckTypeProperties + .MapToImplementations(typeSymbol); var shouldBeScopeRoot = implementations.Max(i => CheckTypeProperties.ShouldBeScopeRoot(i)); var nextParameter = new SwitchInterfaceAfterScopeRootParameter( @@ -336,7 +332,7 @@ private Resolvable SwitchInterfaceForSpecificImplementation( internal InterfaceResolution CreateInterface(CreateInterfaceParameter parameter) { var (interfaceType, implementationType, currentParameters) = parameter; - var shouldBeDecorated = CheckDecorators.ShouldBeDecorated(interfaceType); + var shouldBeDecorated = CheckTypeProperties.ShouldBeDecorated(interfaceType); var nextParameter = parameter switch { @@ -356,7 +352,7 @@ internal InterfaceResolution CreateInterface(CreateInterfaceParameter parameter) if (shouldBeDecorated) { - var decorators = new Queue(CheckDecorators.GetSequenceFor(interfaceType, implementationType)); + var decorators = new Queue(CheckTypeProperties.GetSequenceFor(interfaceType, implementationType)); while (decorators.Any()) { var decorator = decorators.Dequeue(); @@ -379,8 +375,8 @@ internal InterfaceResolution CreateInterface(CreateInterfaceParameter parameter) protected Resolvable SwitchClass(SwitchClassParameter parameter) { var (typeSymbol, currentParameters) = parameter; - var implementations = TypeToImplementationsMapper - .Map(typeSymbol); + var implementations = CheckTypeProperties + .MapToImplementations(typeSymbol); var implementationType = implementations.SingleOrDefault(); if (implementationType is not { }) { diff --git a/Main/ResolutionBuilding/ResolutionDtos.cs b/Main/ResolutionBuilding/ResolutionDtos.cs index 9078a3f0..48340ca4 100644 --- a/Main/ResolutionBuilding/ResolutionDtos.cs +++ b/Main/ResolutionBuilding/ResolutionDtos.cs @@ -53,7 +53,7 @@ internal interface IScopeRootParameter internal record SwitchInterfaceAfterScopeRootParameter( INamedTypeSymbol InterfaceType, - IList ImplementationTypes, + IReadOnlyList ImplementationTypes, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters) : IScopeRootParameter { diff --git a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs index 21a3e64c..8d946b83 100644 --- a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs @@ -1,3 +1,5 @@ +using MrMeeseeks.DIE.Configuration; + namespace MrMeeseeks.DIE.ResolutionBuilding; internal interface IScopeResolutionBuilder @@ -40,18 +42,14 @@ internal ScopeResolutionBuilder( // dependencies WellKnownTypes wellKnownTypes, - ITypeToImplementationsMapper typeToImplementationsMapper, IReferenceGeneratorFactory referenceGeneratorFactory, ICheckTypeProperties checkTypeProperties, - ICheckDecorators checkDecorators, IUserProvidedScopeElements userProvidedScopeElements) : base( - ("DefaultScope", true), + Constants.DefaultScopeName, wellKnownTypes, - typeToImplementationsMapper, referenceGeneratorFactory, checkTypeProperties, - checkDecorators, userProvidedScopeElements) { _containerResolutionBuilder = containerResolutionBuilder; diff --git a/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs b/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs index 31605dc5..f67fd841 100644 --- a/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs @@ -1,3 +1,5 @@ +using MrMeeseeks.DIE.Configuration; + namespace MrMeeseeks.DIE.ResolutionBuilding; internal interface ITransientScopeResolutionBuilder : ITransientScopeImplementationResolutionBuilder @@ -23,8 +25,6 @@ internal class TransientScopeResolutionBuilder : RangeResolutionBaseBuilder, ITr private readonly List _rootResolutions = new (); private readonly string _containerReference; private readonly string _containerParameterReference; - private readonly string _parentDisposablesReference; - private readonly string _parentDisposablesParameterReference; private readonly Dictionary _transientScopeRootFunctionResolutions = new (); private readonly HashSet<(ScopeRootFunction, string)> _transientScopeRootFunctionQueuedOverloads = new (); @@ -39,26 +39,20 @@ internal TransientScopeResolutionBuilder( // dependencies WellKnownTypes wellKnownTypes, - ITypeToImplementationsMapper typeToImplementationsMapper, IReferenceGeneratorFactory referenceGeneratorFactory, ICheckTypeProperties checkTypeProperties, - ICheckDecorators checkDecorators, IUserProvidedScopeElements userProvidedScopeElements) : base( - ("DefaultTransientScope", true), + Constants.DefaultTransientScopeName, wellKnownTypes, - typeToImplementationsMapper, referenceGeneratorFactory, checkTypeProperties, - checkDecorators, userProvidedScopeElements) { _containerResolutionBuilder = containerResolutionBuilder; _transientScopeInterfaceResolutionBuilder = transientScopeInterfaceResolutionBuilder; _containerReference = RootReferenceGenerator.Generate("_container"); _containerParameterReference = RootReferenceGenerator.Generate("container"); - _parentDisposablesReference = RootReferenceGenerator.Generate("_parentDisposables"); - _parentDisposablesParameterReference = RootReferenceGenerator.Generate("parentDisposables"); } protected override RangedInstanceReferenceResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter) => diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index ddae2b88..0ed7ac2c 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -1,4 +1,5 @@ using MrMeeseeks.DIE.CodeBuilding; +using MrMeeseeks.DIE.Configuration; using MrMeeseeks.DIE.ResolutionBuilding; namespace MrMeeseeks.DIE; @@ -17,13 +18,7 @@ public void Execute(GeneratorExecutionContext context) { var diagLogger = new DiagLogger(context); var _ = WellKnownTypes.TryCreate(context.Compilation, out var wellKnownTypes); - var getAssemblyAttributes = new GetAssemblyAttributes(context); - var typesFromTypeAggregatingAttributes = new TypesFromTypeAggregatingAttributes(wellKnownTypes, getAssemblyAttributes); - var getAllImplementations = new GetAllImplementations(context, typesFromTypeAggregatingAttributes); - var getSetOfTypesWithProperties = new GetSetOfTypesWithProperties(getAllImplementations); - var checkDecorators = new CheckDecorators(wellKnownTypes, getAssemblyAttributes, typesFromTypeAggregatingAttributes, getSetOfTypesWithProperties); - var checkTypeProperties = new CheckTypeProperties(typesFromTypeAggregatingAttributes, getAssemblyAttributes, wellKnownTypes, getSetOfTypesWithProperties); - var typeToImplementationMapper = new TypeToImplementationsMapper(getAllImplementations, checkDecorators, checkTypeProperties); + var attributeTypesFromAttributes = new TypesFromAttributes(context.Compilation.Assembly.GetAttributes(), wellKnownTypes); var containerGenerator = new ContainerGenerator(context, diagLogger, ContainerCodeBuilderFactory, TransientScopeCodeBuilderFactory, ScopeCodeBuilderFactory); var referenceGeneratorFactory = new ReferenceGeneratorFactory(ReferenceGeneratorFactory); var containerErrorGenerator = new ContainerErrorGenerator(context); @@ -38,39 +33,59 @@ public void Execute(GeneratorExecutionContext context) ContainerInfoFactory, diagLogger).Execute(); - IContainerResolutionBuilder ResolutionTreeFactory(IContainerInfo ci) => new ContainerResolutionBuilder( - ci, + IContainerResolutionBuilder ResolutionTreeFactory(IContainerInfo ci) + { + var containerTypesFromAttributesList = ImmutableList.Create( + (ITypesFromAttributes) attributeTypesFromAttributes, + new TypesFromAttributes(ci.ContainerType.GetAttributes(), wellKnownTypes)); + + var defaultTransientScopeType = ci.ContainerType.GetTypeMembers(Constants.DefaultTransientScopeName).FirstOrDefault(); + var defaultTransientScopeTypesFromAttributes = new ScopeTypesFromAttributes(defaultTransientScopeType?.GetAttributes() ?? ImmutableArray.Empty, wellKnownTypes); + + var defaultScopeType = ci.ContainerType.GetTypeMembers(Constants.DefaultScopeName).FirstOrDefault(); + var defaultScopeTypesFromAttributes = new ScopeTypesFromAttributes(defaultScopeType?.GetAttributes() ?? ImmutableArray.Empty, wellKnownTypes); + + return new ContainerResolutionBuilder( + ci, + + new TransientScopeInterfaceResolutionBuilder(referenceGeneratorFactory), + referenceGeneratorFactory, + new CheckTypeProperties(new CurrentlyConsideredTypes(containerTypesFromAttributesList, context)), + wellKnownTypes, + TransientScopeResolutionBuilderFactory, + ScopeResolutionBuilderFactory, + new UserProvidedScopeElements(ci.ContainerType)); + + ITransientScopeResolutionBuilder TransientScopeResolutionBuilderFactory(IContainerResolutionBuilder containerBuilder, ITransientScopeInterfaceResolutionBuilder transientScopeInterfaceResolutionBuilder) => new TransientScopeResolutionBuilder( + containerBuilder, + transientScopeInterfaceResolutionBuilder, - new TransientScopeInterfaceResolutionBuilder(referenceGeneratorFactory), - typeToImplementationMapper, - referenceGeneratorFactory, - checkTypeProperties, - checkDecorators, - wellKnownTypes, - TransientScopeResolutionBuilderFactory, - ScopeResolutionBuilderFactory, - new UserProvidedScopeElements(ci.ContainerType)); - ITransientScopeResolutionBuilder TransientScopeResolutionBuilderFactory(IContainerResolutionBuilder containerBuilder, ITransientScopeInterfaceResolutionBuilder transientScopeInterfaceResolutionBuilder) => new TransientScopeResolutionBuilder( - containerBuilder, - transientScopeInterfaceResolutionBuilder, + wellKnownTypes, + referenceGeneratorFactory, + new CheckTypeProperties( + new CurrentlyConsideredTypes( + containerTypesFromAttributesList.Add(defaultTransientScopeTypesFromAttributes), + context)), + defaultTransientScopeType is {} + ? new UserProvidedScopeElements(defaultTransientScopeType) + : new EmptyUserProvidedScopeElements()); + IScopeResolutionBuilder ScopeResolutionBuilderFactory(IContainerResolutionBuilder containerBuilder, ITransientScopeResolutionBuilder transientScopeResolutionBuilder, ITransientScopeInterfaceResolutionBuilder transientScopeInterfaceResolutionBuilder) => new ScopeResolutionBuilder( + containerBuilder, + transientScopeResolutionBuilder, + transientScopeInterfaceResolutionBuilder, + + wellKnownTypes, + referenceGeneratorFactory, + new CheckTypeProperties( + new CurrentlyConsideredTypes( + containerTypesFromAttributesList.Add(defaultScopeTypesFromAttributes), + context)), + defaultScopeType is {} + ? new UserProvidedScopeElements(defaultScopeType) + : new EmptyUserProvidedScopeElements()); - wellKnownTypes, - typeToImplementationMapper, - referenceGeneratorFactory, - checkTypeProperties, - checkDecorators, - new EmptyUserProvidedScopeElements()); // todo Replace EmptyUserProvidedScopeElements with one for the scope specifically - IScopeResolutionBuilder ScopeResolutionBuilderFactory(IContainerResolutionBuilder containerBuilder, ITransientScopeResolutionBuilder transientScopeResolutionBuilder, ITransientScopeInterfaceResolutionBuilder transientScopeInterfaceResolutionBuilder) => new ScopeResolutionBuilder( - containerBuilder, - transientScopeResolutionBuilder, - transientScopeInterfaceResolutionBuilder, - wellKnownTypes, - typeToImplementationMapper, - referenceGeneratorFactory, - checkTypeProperties, - checkDecorators, - new EmptyUserProvidedScopeElements()); // todo Replace EmptyUserProvidedScopeElements with one for the scope specifically + } IContainerInfo ContainerInfoFactory(INamedTypeSymbol type) => new ContainerInfo(type, wellKnownTypes); IReferenceGenerator ReferenceGeneratorFactory(int j) => new ReferenceGenerator(j); diff --git a/Main/TypeToImplementationMapper.cs b/Main/TypeToImplementationMapper.cs deleted file mode 100644 index f7a5bcc0..00000000 --- a/Main/TypeToImplementationMapper.cs +++ /dev/null @@ -1,28 +0,0 @@ -namespace MrMeeseeks.DIE; - -internal interface ITypeToImplementationsMapper -{ - IList Map(ITypeSymbol typeSymbol); -} - -internal class TypeToImplementationsMapper : ITypeToImplementationsMapper -{ - private readonly Dictionary> _map; - - internal TypeToImplementationsMapper( - IGetAllImplementations getAllImplementations, - ICheckDecorators checkDecorators, - ICheckTypeProperties checkTypeProperties) => - _map = getAllImplementations - .AllImplementations - .Where(t => !checkDecorators.IsDecorator(t.OriginalDefinition)) - .Where(t => !checkTypeProperties.IsComposite(t.OriginalDefinition)) - .SelectMany(i => { return i.AllInterfaces.OfType().Select(ii => (ii, i)).Prepend((i, i)); }) - .GroupBy(t => t.Item1, t => t.Item2) - .ToDictionary(g => g.Key, g => g.Distinct(SymbolEqualityComparer.Default).OfType().ToList()); - - public IList Map(ITypeSymbol typeSymbol) => - _map.TryGetValue(typeSymbol, out var implementations) - ? implementations - : new List(); -} \ No newline at end of file diff --git a/Main/TypesFromTypeAggregatingAttributes.cs b/Main/TypesFromTypeAggregatingAttributes.cs deleted file mode 100644 index 9d20ae67..00000000 --- a/Main/TypesFromTypeAggregatingAttributes.cs +++ /dev/null @@ -1,77 +0,0 @@ -namespace MrMeeseeks.DIE; - -internal interface ITypesFromTypeAggregatingAttributes -{ - IReadOnlyList Spy { get; } - IReadOnlyList Implementation { get; } - IReadOnlyList Transient { get; } - IReadOnlyList ContainerInstance { get; } - IReadOnlyList TransientScopeInstance { get; } - IReadOnlyList ScopeInstance { get; } - IReadOnlyList TransientScopeRoot { get; } - IReadOnlyList ScopeRoot { get; } - IReadOnlyList Decorator { get; } - IReadOnlyList Composite { get; } -} - -internal class TypesFromTypeAggregatingAttributes : ITypesFromTypeAggregatingAttributes -{ - internal TypesFromTypeAggregatingAttributes( - WellKnownTypes wellKnownTypes, - IGetAssemblyAttributes getAssemblyAttributes) - { - Spy = GetTypesFromAttribute(wellKnownTypes.SpyAggregationAttribute).ToList(); - Implementation = GetTypesFromAttribute(wellKnownTypes.ImplementationAggregationAttribute).ToList(); - Transient = GetTypesFromAttribute(wellKnownTypes.TransientAggregationAttribute).ToList(); - ContainerInstance = GetTypesFromAttribute(wellKnownTypes.ContainerInstanceAggregationAttribute).ToList(); - TransientScopeInstance = GetTypesFromAttribute(wellKnownTypes.TransientScopeInstanceAggregationAttribute).ToList(); - ScopeInstance = GetTypesFromAttribute(wellKnownTypes.ScopeInstanceAggregationAttribute).ToList(); - TransientScopeRoot = GetTypesFromAttribute(wellKnownTypes.TransientScopeRootAggregationAttribute).ToList(); - ScopeRoot = GetTypesFromAttribute(wellKnownTypes.ScopeRootAggregationAttribute).ToList(); - Decorator = GetTypesFromAttribute(wellKnownTypes.DecoratorAggregationAttribute).ToList(); - Composite = GetTypesFromAttribute(wellKnownTypes.CompositeAggregationAttribute).ToList(); - - IEnumerable GetTypesFromAttribute(INamedTypeSymbol attribute) => getAssemblyAttributes - .AllAssemblyAttributes - .Where(ad => - ad.AttributeClass?.Equals(attribute, SymbolEqualityComparer.Default) ?? false) - .SelectMany(ad => ad.ConstructorArguments - .Where(tc => tc.Kind == TypedConstantKind.Type) - .OfType() - .Concat(ad.ConstructorArguments.SelectMany(ca => ca.Kind is TypedConstantKind.Array - ? (IEnumerable)ca.Values - : Array.Empty()))) - .Select(tc => - { - if (!CheckValidType(tc, out var type)) - { - return null; - } - - return type; - }) - .Where(t => t is not null) - .OfType() - .Select(t => t.OriginalDefinition); - - bool CheckValidType(TypedConstant typedConstant, out INamedTypeSymbol type) - { - type = (typedConstant.Value as INamedTypeSymbol)!; - if (typedConstant.Value is null) - return false; - - return true; - } - } - - public IReadOnlyList Spy { get; } - public IReadOnlyList Implementation { get; } - public IReadOnlyList Transient { get; } - public IReadOnlyList ContainerInstance { get; } - public IReadOnlyList TransientScopeInstance { get; } - public IReadOnlyList ScopeInstance { get; } - public IReadOnlyList TransientScopeRoot { get; } - public IReadOnlyList ScopeRoot { get; } - public IReadOnlyList Decorator { get; } - public IReadOnlyList Composite { get; } -} \ No newline at end of file diff --git a/Main/WellKnownTypes.cs b/Main/WellKnownTypes.cs index 06189427..19b97133 100644 --- a/Main/WellKnownTypes.cs +++ b/Main/WellKnownTypes.cs @@ -1,4 +1,6 @@ -namespace MrMeeseeks.DIE; +using MrMeeseeks.DIE.Configuration; + +namespace MrMeeseeks.DIE; internal record WellKnownTypes( INamedTypeSymbol Container, diff --git a/Sample/Container.cs b/Sample/Container.cs index cec86553..25355bc1 100644 --- a/Sample/Container.cs +++ b/Sample/Container.cs @@ -1,4 +1,5 @@ using MrMeeseeks.DIE; +using MrMeeseeks.DIE.Configuration; using MrMeeseeks.DIE.Sample; [assembly:ContainerInstanceAggregation(typeof(IContainerInstance))] diff --git a/Test/AssemblyInfo.cs b/Test/AssemblyInfo.cs index ba29ff54..e09eda1f 100644 --- a/Test/AssemblyInfo.cs +++ b/Test/AssemblyInfo.cs @@ -1,4 +1,5 @@ using MrMeeseeks.DIE; +using MrMeeseeks.DIE.Configuration; using MrMeeseeks.DIE.Test; [assembly:ContainerInstanceAggregation(typeof(IContainerInstance))] diff --git a/Test/CompositeTests.cs b/Test/CompositeTests.cs index 68cc699f..316866fd 100644 --- a/Test/CompositeTests.cs +++ b/Test/CompositeTests.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using MrMeeseeks.DIE; +using MrMeeseeks.DIE.Configuration; using MrMeeseeks.DIE.Test; using Xunit; diff --git a/Test/ConstructorChoiceTests.cs b/Test/ConstructorChoiceTests.cs index e3e59fc3..8263b93f 100644 --- a/Test/ConstructorChoiceTests.cs +++ b/Test/ConstructorChoiceTests.cs @@ -1,5 +1,6 @@ using System; using MrMeeseeks.DIE; +using MrMeeseeks.DIE.Configuration; using Xunit; [assembly:ImplementationAggregation(typeof(DateTime))] diff --git a/Test/DecoratorTests.cs b/Test/DecoratorTests.cs index 4d33434e..318ad53d 100644 --- a/Test/DecoratorTests.cs +++ b/Test/DecoratorTests.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using MrMeeseeks.DIE; +using MrMeeseeks.DIE.Configuration; using MrMeeseeks.DIE.Test; using Xunit; diff --git a/Test/FactoryTests.cs b/Test/FactoryTests.cs index d9ab9585..4f7771d5 100644 --- a/Test/FactoryTests.cs +++ b/Test/FactoryTests.cs @@ -3,13 +3,42 @@ namespace MrMeeseeks.DIE.Test; -internal partial class FactoryContainer : IContainer +internal class FactoryContainerTransientScope : ITransientScopeRoot +{ + public int Number { get; } + + internal FactoryContainerTransientScope(int number) + { + Number = number; + } +} +internal class FactoryContainerScope : IScopeRoot +{ + public string Yeah { get; } + + internal FactoryContainerScope(string yeah) + { + Yeah = yeah; + } +} + +internal partial class FactoryContainer : IContainer, IContainer, IContainer { private string DIE_Path { get; } private FileInfo DIE_FileInfo(string path) => new (path); public FactoryContainer(string diePath) => DIE_Path = diePath; + + internal partial class DIE_DefaultTransientScope + { + private int DIE_Num => 69; + } + + internal partial class DIE_DefaultScope + { + private string DIE_Yeah => "Yeah"; + } } public partial class FactoryTests @@ -22,4 +51,22 @@ public void ResolveExternalType() var fileInfo = ((IContainer) container).Resolve(); Assert.Equal(check, fileInfo.FullName); } + + [Fact] + public void ResolveFromFactoryInTransientScope() + { + var check = @"C:\HelloWorld.txt"; + using var container = new FactoryContainer(check); + var transientScope = ((IContainer) container).Resolve(); + Assert.Equal(69, transientScope.Number); + } + + [Fact] + public void ResolveFromFactoryInScope() + { + var check = @"C:\HelloWorld.txt"; + using var container = new FactoryContainer(check); + var scope = ((IContainer) container).Resolve(); + Assert.Equal("Yeah", scope.Yeah); + } } \ No newline at end of file diff --git a/Test/ImplementationAggregationTests.cs b/Test/ImplementationAggregationTests.cs index 923a4016..a0edc273 100644 --- a/Test/ImplementationAggregationTests.cs +++ b/Test/ImplementationAggregationTests.cs @@ -1,6 +1,6 @@ using System; using System.IO; -using MrMeeseeks.DIE; +using MrMeeseeks.DIE.Configuration; using Xunit; [assembly:ImplementationAggregation(typeof(FileInfo))] diff --git a/Test/ScopeSpecificAttributesTests.cs b/Test/ScopeSpecificAttributesTests.cs new file mode 100644 index 00000000..f89ed648 --- /dev/null +++ b/Test/ScopeSpecificAttributesTests.cs @@ -0,0 +1,107 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test; + +internal interface IScopeSpecificAttributesInterface +{ + int Number { get; } +} + +internal class ScopeSpecificAttributesImplementation : IScopeSpecificAttributesInterface +{ + public int Number => 1; +} + +internal class ScopeSpecificAttributesContai : IScopeSpecificAttributesInterface, IDecorator +{ + public int Number => 69; + + internal ScopeSpecificAttributesContai(IScopeSpecificAttributesInterface _) {} +} + +internal class ScopeSpecificAttributesScope : IScopeSpecificAttributesInterface, IDecorator +{ + public int Number => 3; + + internal ScopeSpecificAttributesScope(IScopeSpecificAttributesInterface _) {} +} + +internal class ScopeSpecificAttributesTransientScope : IScopeSpecificAttributesInterface, IDecorator +{ + public int Number => 23; + + internal ScopeSpecificAttributesTransientScope(IScopeSpecificAttributesInterface _) {} +} + +internal class ScopeSpecificAttributesDep +{ + public int Number { get; } + + internal ScopeSpecificAttributesDep(IScopeSpecificAttributesInterface scopeSpecificAttributesInterface) + { + Number = scopeSpecificAttributesInterface.Number; + } +} + +internal class ScopeSpecificAttributesTransientScopeRoot : ITransientScopeRoot +{ + public ScopeSpecificAttributesDep Dep { get; } + + internal ScopeSpecificAttributesTransientScopeRoot(ScopeSpecificAttributesDep dep) + { + Dep = dep; + } +} + +internal class ScopeSpecificAttributesScopeRoot : IScopeRoot +{ + public ScopeSpecificAttributesDep Dep { get; } + + internal ScopeSpecificAttributesScopeRoot(ScopeSpecificAttributesDep dep) + { + Dep = dep; + } +} + + +[DecoratorSequenceChoice(typeof(IScopeSpecificAttributesInterface), typeof(ScopeSpecificAttributesContai))] +internal partial class ScopeSpecificAttributesContainer : IContainer, IContainer, IContainer +{ + [DecoratorSequenceChoice(typeof(IScopeSpecificAttributesInterface), typeof(ScopeSpecificAttributesTransientScope))] + internal partial class DIE_DefaultTransientScope + { + + } + + [DecoratorSequenceChoice(typeof(IScopeSpecificAttributesInterface), typeof(ScopeSpecificAttributesScope))] + internal partial class DIE_DefaultScope + { + + } +} + +public partial class ScopeSpecificAttributesTests +{ + [Fact] + public void Container() + { + using var container = new ScopeSpecificAttributesContainer(); + var instance = ((IContainer) container).Resolve(); + Assert.Equal(69, instance.Number); + } + [Fact] + public void TransientScope() + { + using var container = new ScopeSpecificAttributesContainer(); + var instance = ((IContainer) container).Resolve(); + Assert.Equal(23, instance.Dep.Number); + } + [Fact] + public void Scope() + { + using var container = new ScopeSpecificAttributesContainer(); + var instance = ((IContainer) container).Resolve(); + Assert.Equal(3, instance.Dep.Number); + } +} \ No newline at end of file From 40e414acbb10214fd4fc04aa409c29612edb7cf3 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sat, 29 Jan 2022 12:14:39 +0100 Subject: [PATCH 044/162] Filtering registrations in more specific contexts (container, scopes) --- Main/Configuration/Attributes.cs | 81 +++++++++++++++++++ .../Configuration/CurrentlyConsideredTypes.cs | 51 +++++++----- Main/Configuration/TypesFromAttributes.cs | 61 ++++++++++++++ Main/WellKnownTypes.cs | 78 ++++++++++++++++++ Sample/Container.cs | 3 +- Sample/Context.cs | 44 ++++++++-- Sample/Program.cs | 6 +- ...cAttributesTestsWithImplementationLists.cs | 74 +++++++++++++++++ ...cificAttributesTestsWithImplementations.cs | 70 ++++++++++++++++ 9 files changed, 435 insertions(+), 33 deletions(-) create mode 100644 Test/ScopeSpecificAttributesTestsWithImplementationLists.cs create mode 100644 Test/ScopeSpecificAttributesTestsWithImplementations.cs diff --git a/Main/Configuration/Attributes.cs b/Main/Configuration/Attributes.cs index a6244325..6f3cb3c3 100644 --- a/Main/Configuration/Attributes.cs +++ b/Main/Configuration/Attributes.cs @@ -7,17 +7,36 @@ public class SpyAggregationAttribute : Attribute public SpyAggregationAttribute(params Type[] types) {} } +// ReSharper disable UnusedParameter.Local *** The constructor parameters of the attributes will be used. Trust me, imma dev. +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class FilterSpyAggregationAttribute : Attribute +{ + public FilterSpyAggregationAttribute(params Type[] types) {} +} + [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class SpyConstructorChoiceAggregationAttribute : Attribute { public SpyConstructorChoiceAggregationAttribute(params Enum[] references) {} } +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class FilterSpyConstructorChoiceAggregationAttribute : Attribute +{ + public FilterSpyConstructorChoiceAggregationAttribute(params Enum[] references) {} +} + [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class ImplementationAggregationAttribute : Attribute { public ImplementationAggregationAttribute(params Type[] types) {} } + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class FilterImplementationAggregationAttribute : Attribute +{ + public FilterImplementationAggregationAttribute(params Type[] types) {} +} [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class TransientAggregationAttribute : Attribute @@ -25,53 +44,107 @@ public class TransientAggregationAttribute : Attribute public TransientAggregationAttribute(params Type[] types) {} } +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class FilterTransientAggregationAttribute : Attribute +{ + public FilterTransientAggregationAttribute(params Type[] types) {} +} + [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class ContainerInstanceAggregationAttribute : Attribute { public ContainerInstanceAggregationAttribute(params Type[] types) {} } +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class FilterContainerInstanceAggregationAttribute : Attribute +{ + public FilterContainerInstanceAggregationAttribute(params Type[] types) {} +} + [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class TransientScopeInstanceAggregationAttribute : Attribute { public TransientScopeInstanceAggregationAttribute(params Type[] types) {} } +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class FilterTransientScopeInstanceAggregationAttribute : Attribute +{ + public FilterTransientScopeInstanceAggregationAttribute(params Type[] types) {} +} + [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class ScopeInstanceAggregationAttribute : Attribute { public ScopeInstanceAggregationAttribute(params Type[] types) {} } +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class FilterScopeInstanceAggregationAttribute : Attribute +{ + public FilterScopeInstanceAggregationAttribute(params Type[] types) {} +} + [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class TransientScopeRootAggregationAttribute : Attribute { public TransientScopeRootAggregationAttribute(params Type[] types) {} } +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class FilterTransientScopeRootAggregationAttribute : Attribute +{ + public FilterTransientScopeRootAggregationAttribute(params Type[] types) {} +} + [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class ScopeRootAggregationAttribute : Attribute { public ScopeRootAggregationAttribute(params Type[] types) {} } +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class FilterScopeRootAggregationAttribute : Attribute +{ + public FilterScopeRootAggregationAttribute(params Type[] types) {} +} + [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class DecoratorAggregationAttribute : Attribute { public DecoratorAggregationAttribute(params Type[] types) {} } +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class FilterDecoratorAggregationAttribute : Attribute +{ + public FilterDecoratorAggregationAttribute(params Type[] types) {} +} + [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class CompositeAggregationAttribute : Attribute { public CompositeAggregationAttribute(params Type[] types) {} } +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class FilterCompositeAggregationAttribute : Attribute +{ + public FilterCompositeAggregationAttribute(params Type[] types) {} +} + [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class DecoratorSequenceChoiceAttribute : Attribute { public DecoratorSequenceChoiceAttribute(Type decoratedType, params Type[] types) {} } + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class FilterDecoratorSequenceChoiceAttribute : Attribute +{ + public FilterDecoratorSequenceChoiceAttribute(Type decoratedType) {} +} [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class ConstructorChoiceAttribute : Attribute @@ -80,4 +153,12 @@ public ConstructorChoiceAttribute(Type implementationType, params Type[] paramet { } } + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class FilterConstructorChoiceAttribute : Attribute +{ + public FilterConstructorChoiceAttribute(Type implementationType) + { + } +} // ReSharper enable UnusedParameter.Local \ No newline at end of file diff --git a/Main/Configuration/CurrentlyConsideredTypes.cs b/Main/Configuration/CurrentlyConsideredTypes.cs index 7adf9237..8137b90e 100644 --- a/Main/Configuration/CurrentlyConsideredTypes.cs +++ b/Main/Configuration/CurrentlyConsideredTypes.cs @@ -38,6 +38,9 @@ public CurrentlyConsideredTypes( foreach (var types in typesFromAttributes) { + foreach (var filterType in types.FilterSpy.Concat(types.FilterImplementation)) + tempAllImplementations.Remove(filterType); + var spiedImplementations = types .Spy .SelectMany(t => t?.GetMembers() @@ -52,20 +55,21 @@ public CurrentlyConsideredTypes( var allImplementations = tempAllImplementations; - TransientTypes = GetSetOfTypesWithProperties(t => t.Transient); - ContainerInstanceTypes = GetSetOfTypesWithProperties(t => t.ContainerInstance); - TransientScopeInstanceTypes = GetSetOfTypesWithProperties(t => t.TransientScopeInstance); - ScopeInstanceTypes = GetSetOfTypesWithProperties(t => t.ScopeInstance); - TransientScopeRootTypes = GetSetOfTypesWithProperties(t => t.TransientScopeRoot); - ScopeRootTypes = GetSetOfTypesWithProperties(t => t.ScopeRoot); + TransientTypes = GetSetOfTypesWithProperties(t => t.Transient, t => t.FilterTransient); + ContainerInstanceTypes = GetSetOfTypesWithProperties(t => t.ContainerInstance, t => t.FilterContainerInstance); + TransientScopeInstanceTypes = GetSetOfTypesWithProperties(t => t.TransientScopeInstance, t => t.FilterTransientScopeInstance); + ScopeInstanceTypes = GetSetOfTypesWithProperties(t => t.ScopeInstance, t => t.FilterScopeInstance); + TransientScopeRootTypes = GetSetOfTypesWithProperties(t => t.TransientScopeRoot, t => t.FilterTransientScopeRoot); + ScopeRootTypes = GetSetOfTypesWithProperties(t => t.ScopeRoot, t => t.FilterScopeRoot); var compositeInterfaces = ImmutableHashSet.Empty; foreach (var types in typesFromAttributes) { + compositeInterfaces = compositeInterfaces.Except(types.FilterComposite); compositeInterfaces = compositeInterfaces.Union(types.Composite); } - var compositeTypes = GetSetOfTypesWithProperties(t => t.Composite); + var compositeTypes = GetSetOfTypesWithProperties(t => t.Composite, t => t.FilterComposite); InterfaceToComposite = compositeTypes .OfType() .GroupBy(nts => @@ -81,10 +85,11 @@ public CurrentlyConsideredTypes( foreach (var types in typesFromAttributes) { - foreach (var constructorChoice in types.ConstructorChoices) - { - constructorChoices[constructorChoice.Item1] = constructorChoice.Item2; - } + foreach (var filterConstructorChoice in types.FilterConstructorChoices) + constructorChoices.Remove(filterConstructorChoice); + + foreach (var (implementationType, constructor) in types.ConstructorChoices) + constructorChoices[implementationType] = constructor; } ImplementationToConstructorChoice = constructorChoices; @@ -92,10 +97,11 @@ public CurrentlyConsideredTypes( var decoratorInterfaces = ImmutableHashSet.Empty; foreach (var types in typesFromAttributes) { + decoratorInterfaces = decoratorInterfaces.Except(types.FilterDecorator); decoratorInterfaces = decoratorInterfaces.Union(types.Decorator); } - var decoratorTypes = GetSetOfTypesWithProperties(t => t.Decorator); + var decoratorTypes = GetSetOfTypesWithProperties(t => t.Decorator, t => t.FilterDecorator); InterfaceToDecorators = decoratorTypes .OfType() .GroupBy(nts => @@ -110,10 +116,11 @@ public CurrentlyConsideredTypes( foreach (var types in typesFromAttributes) { - foreach (var decoratorSequenceChoice in types.DecoratorSequenceChoices) - { - decoratorSequenceChoices[decoratorSequenceChoice.Item1] = decoratorSequenceChoice.Item2; - } + foreach (var filterDecoratorSequenceChoice in types.FilterDecoratorSequenceChoices) + decoratorSequenceChoices.Remove(filterDecoratorSequenceChoice); + + foreach (var (decoratedType, decoratorSequence) in types.DecoratorSequenceChoices) + decoratorSequenceChoices[decoratedType] = decoratorSequence; } InterfaceSequenceChoices = decoratorSequenceChoices @@ -131,13 +138,17 @@ public CurrentlyConsideredTypes( .GroupBy(t => t.Item1, t => t.Item2) .ToDictionary(g => g.Key, g => (IReadOnlyList) g.Distinct(SymbolEqualityComparer.Default).OfType().ToList()); - IImmutableSet GetSetOfTypesWithProperties(Func> propertyGivingTypesGetter) + IImmutableSet GetSetOfTypesWithProperties( + Func> propertyGivingTypesGetter, + Func> filteredPropertyGivingTypesGetter) { - var tempSet = ImmutableHashSet.Empty; + var ret = ImmutableHashSet.Empty; foreach (var types in typesFromAttributes) { + ret = ret.Except(filteredPropertyGivingTypesGetter(types)); + var propertyGivingTypes = propertyGivingTypesGetter(types); - tempSet = tempSet.Union(allImplementations + ret = ret.Union(allImplementations .Where(i => { var derivedTypes = AllDerivedTypes(i).Select(t => t.OriginalDefinition).ToList(); @@ -148,7 +159,7 @@ public CurrentlyConsideredTypes( .ToImmutableHashSet(SymbolEqualityComparer.Default)); } - return tempSet; + return ret; IEnumerable AllDerivedTypes(INamedTypeSymbol type) diff --git a/Main/Configuration/TypesFromAttributes.cs b/Main/Configuration/TypesFromAttributes.cs index 676a4c64..9ec3fcb3 100644 --- a/Main/Configuration/TypesFromAttributes.cs +++ b/Main/Configuration/TypesFromAttributes.cs @@ -14,6 +14,18 @@ internal interface ITypesFromAttributes IReadOnlyList Composite { get; } IReadOnlyList<(INamedTypeSymbol, IReadOnlyList)> DecoratorSequenceChoices { get; } IReadOnlyList<(INamedTypeSymbol, IMethodSymbol)> ConstructorChoices { get; } + IReadOnlyList FilterSpy { get; } + IReadOnlyList FilterImplementation { get; } + IReadOnlyList FilterTransient { get; } + IReadOnlyList FilterContainerInstance { get; } + IReadOnlyList FilterTransientScopeInstance { get; } + IReadOnlyList FilterScopeInstance { get; } + IReadOnlyList FilterTransientScopeRoot { get; } + IReadOnlyList FilterScopeRoot { get; } + IReadOnlyList FilterDecorator { get; } + IReadOnlyList FilterComposite { get; } + IReadOnlyList FilterDecoratorSequenceChoices { get; } + IReadOnlyList FilterConstructorChoices { get; } } internal class TypesFromAttributes : ScopeTypesFromAttributes @@ -29,6 +41,10 @@ internal TypesFromAttributes( TransientScopeInstance = GetTypesFromAttribute(wellKnownTypes.TransientScopeInstanceAggregationAttribute).ToList(); TransientScopeRoot = GetTypesFromAttribute(wellKnownTypes.TransientScopeRootAggregationAttribute).ToList(); ScopeRoot = GetTypesFromAttribute(wellKnownTypes.ScopeRootAggregationAttribute).ToList(); + FilterContainerInstance = GetTypesFromAttribute(wellKnownTypes.FilterContainerInstanceAggregationAttribute).ToList(); + FilterTransientScopeInstance = GetTypesFromAttribute(wellKnownTypes.FilterTransientScopeInstanceAggregationAttribute).ToList(); + FilterTransientScopeRoot = GetTypesFromAttribute(wellKnownTypes.FilterTransientScopeRootAggregationAttribute).ToList(); + FilterScopeRoot = GetTypesFromAttribute(wellKnownTypes.FilterScopeRootAggregationAttribute).ToList(); } } @@ -55,6 +71,17 @@ internal ScopeTypesFromAttributes( ScopeRoot = new List(); Decorator = GetTypesFromAttribute(wellKnownTypes.DecoratorAggregationAttribute).ToList(); Composite = GetTypesFromAttribute(wellKnownTypes.CompositeAggregationAttribute).ToList(); + + FilterSpy = GetTypesFromAttribute(wellKnownTypes.FilterSpyAggregationAttribute).ToList(); + FilterImplementation = GetTypesFromAttribute(wellKnownTypes.FilterImplementationAggregationAttribute).ToList(); + FilterTransient = GetTypesFromAttribute(wellKnownTypes.FilterTransientAggregationAttribute).ToList(); + FilterContainerInstance = new List(); + FilterTransientScopeInstance = new List(); + FilterScopeInstance = GetTypesFromAttribute(wellKnownTypes.FilterScopeInstanceAggregationAttribute).ToList(); + FilterTransientScopeRoot = new List(); + FilterScopeRoot = new List(); + FilterDecorator = GetTypesFromAttribute(wellKnownTypes.FilterDecoratorAggregationAttribute).ToList(); + FilterComposite = GetTypesFromAttribute(wellKnownTypes.FilterCompositeAggregationAttribute).ToList(); DecoratorSequenceChoices = (AttributeDictionary.TryGetValue(wellKnownTypes.DecoratorSequenceChoiceAttribute, out var group) ? group : Enumerable.Empty()) .Select(ad => @@ -75,6 +102,18 @@ internal ScopeTypesFromAttributes( }) .OfType<(INamedTypeSymbol, IReadOnlyList)>() .ToList(); + + FilterDecoratorSequenceChoices = (AttributeDictionary.TryGetValue(wellKnownTypes.FilterDecoratorSequenceChoiceAttribute, out var group1) ? group1 : Enumerable.Empty()) + .Select(ad => + { + if (ad.ConstructorArguments.Length < 2) + return null; + var decoratedType = ad.ConstructorArguments[0].Value; + + return decoratedType as INamedTypeSymbol; + }) + .OfType() + .ToList(); ConstructorChoices = (AttributeDictionary.TryGetValue(wellKnownTypes.ConstructorChoiceAttribute, out var group0) ? group0 : Enumerable.Empty()) .Select(ad => @@ -107,6 +146,16 @@ internal ScopeTypesFromAttributes( }) .OfType<(INamedTypeSymbol, IMethodSymbol)>() .ToList(); + + FilterConstructorChoices = (AttributeDictionary.TryGetValue(wellKnownTypes.FilterConstructorChoiceAttribute, out var group2) ? group2 : Enumerable.Empty()) + .Select(ad => + { + if (ad.ConstructorArguments.Length < 2) + return null; + return ad.ConstructorArguments[0].Value as INamedTypeSymbol; + }) + .OfType() + .ToList(); } private IReadOnlyDictionary> AttributeDictionary { get; } @@ -145,4 +194,16 @@ bool CheckValidType(TypedConstant typedConstant, out INamedTypeSymbol type) public IReadOnlyList Composite { get; } public IReadOnlyList<(INamedTypeSymbol, IReadOnlyList)> DecoratorSequenceChoices { get; } public IReadOnlyList<(INamedTypeSymbol, IMethodSymbol)> ConstructorChoices { get; } + public IReadOnlyList FilterSpy { get; } + public IReadOnlyList FilterImplementation { get; } + public IReadOnlyList FilterTransient { get; } + public IReadOnlyList FilterContainerInstance { get; protected init; } + public IReadOnlyList FilterTransientScopeInstance { get; protected init; } + public IReadOnlyList FilterScopeInstance { get; } + public IReadOnlyList FilterTransientScopeRoot { get; protected init; } + public IReadOnlyList FilterScopeRoot { get; protected init; } + public IReadOnlyList FilterDecorator { get; } + public IReadOnlyList FilterComposite { get; } + public IReadOnlyList FilterDecoratorSequenceChoices { get; } + public IReadOnlyList FilterConstructorChoices { get; } } \ No newline at end of file diff --git a/Main/WellKnownTypes.cs b/Main/WellKnownTypes.cs index 19b97133..58760e3a 100644 --- a/Main/WellKnownTypes.cs +++ b/Main/WellKnownTypes.cs @@ -17,6 +17,19 @@ internal record WellKnownTypes( INamedTypeSymbol CompositeAggregationAttribute, INamedTypeSymbol DecoratorSequenceChoiceAttribute, INamedTypeSymbol ConstructorChoiceAttribute, + INamedTypeSymbol FilterSpyAggregationAttribute, + INamedTypeSymbol FilterSpyConstructorChoiceAggregationAttribute, + INamedTypeSymbol FilterImplementationAggregationAttribute, + INamedTypeSymbol FilterTransientAggregationAttribute, + INamedTypeSymbol FilterContainerInstanceAggregationAttribute, + INamedTypeSymbol FilterTransientScopeInstanceAggregationAttribute, + INamedTypeSymbol FilterScopeInstanceAggregationAttribute, + INamedTypeSymbol FilterTransientScopeRootAggregationAttribute, + INamedTypeSymbol FilterScopeRootAggregationAttribute, + INamedTypeSymbol FilterDecoratorAggregationAttribute, + INamedTypeSymbol FilterCompositeAggregationAttribute, + INamedTypeSymbol FilterDecoratorSequenceChoiceAttribute, + INamedTypeSymbol FilterConstructorChoiceAttribute, INamedTypeSymbol Disposable, INamedTypeSymbol AsyncDisposable, INamedTypeSymbol Lazy1, @@ -94,6 +107,45 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK var constructorChoiceAttribute = compilation .GetTypeByMetadataName(typeof(ConstructorChoiceAttribute).FullName ?? ""); + var filterSpyAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(FilterSpyAggregationAttribute).FullName ?? ""); + + var filterSpyConstructorChoiceAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(FilterSpyConstructorChoiceAggregationAttribute).FullName ?? ""); + + var filterImplementationAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(FilterImplementationAggregationAttribute).FullName ?? ""); + + var filterTransientAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(FilterTransientAggregationAttribute).FullName ?? ""); + + var filterContainerInstanceAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(FilterContainerInstanceAggregationAttribute).FullName ?? ""); + + var filterTransientScopeInstanceAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(FilterTransientScopeInstanceAggregationAttribute).FullName ?? ""); + + var filterScopeInstanceAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(FilterScopeInstanceAggregationAttribute).FullName ?? ""); + + var filterTransientScopeRootAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(FilterTransientScopeRootAggregationAttribute).FullName ?? ""); + + var filterScopeRootAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(FilterScopeRootAggregationAttribute).FullName ?? ""); + + var filterDecoratorAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(FilterDecoratorAggregationAttribute).FullName ?? ""); + + var filterCompositeAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(FilterCompositeAggregationAttribute).FullName ?? ""); + + var filterDecoratorSequenceChoiceAttribute = compilation + .GetTypeByMetadataName(typeof(FilterDecoratorSequenceChoiceAttribute).FullName ?? ""); + + var filterConstructorChoiceAttribute = compilation + .GetTypeByMetadataName(typeof(FilterConstructorChoiceAttribute).FullName ?? ""); + if (iContainer is null || spyAggregationAttribute is null || spyConstructorChoiceAggregationAttribute is null @@ -108,6 +160,19 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK || compositeAggregationAttribute is null || decoratorSequenceChoiceAttribute is null || constructorChoiceAttribute is null + || filterSpyAggregationAttribute is null + || filterSpyConstructorChoiceAggregationAttribute is null + || filterImplementationAggregationAttribute is null + || filterTransientAggregationAttribute is null + || filterContainerInstanceAggregationAttribute is null + || filterTransientScopeInstanceAggregationAttribute is null + || filterScopeInstanceAggregationAttribute is null + || filterTransientScopeRootAggregationAttribute is null + || filterScopeRootAggregationAttribute is null + || filterDecoratorAggregationAttribute is null + || filterCompositeAggregationAttribute is null + || filterDecoratorSequenceChoiceAttribute is null + || filterConstructorChoiceAttribute is null || iDisposable is null || iAsyncDisposable is null || lazy1 is null @@ -143,6 +208,19 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK CompositeAggregationAttribute: compositeAggregationAttribute, DecoratorSequenceChoiceAttribute: decoratorSequenceChoiceAttribute, ConstructorChoiceAttribute: constructorChoiceAttribute, + FilterSpyAggregationAttribute: filterSpyAggregationAttribute, + FilterSpyConstructorChoiceAggregationAttribute: filterSpyConstructorChoiceAggregationAttribute, + FilterImplementationAggregationAttribute: filterImplementationAggregationAttribute, + FilterTransientAggregationAttribute: filterTransientAggregationAttribute, + FilterContainerInstanceAggregationAttribute: filterContainerInstanceAggregationAttribute, + FilterTransientScopeInstanceAggregationAttribute: filterTransientScopeInstanceAggregationAttribute, + FilterScopeInstanceAggregationAttribute: filterScopeInstanceAggregationAttribute, + FilterTransientScopeRootAggregationAttribute: filterTransientScopeRootAggregationAttribute, + FilterScopeRootAggregationAttribute: filterScopeRootAggregationAttribute, + FilterDecoratorAggregationAttribute: filterDecoratorAggregationAttribute, + FilterCompositeAggregationAttribute: filterCompositeAggregationAttribute, + FilterDecoratorSequenceChoiceAttribute: filterDecoratorSequenceChoiceAttribute, + FilterConstructorChoiceAttribute: filterConstructorChoiceAttribute, Disposable: iDisposable, AsyncDisposable: iAsyncDisposable, Lazy1: lazy1, diff --git a/Sample/Container.cs b/Sample/Container.cs index 25355bc1..7c7128b5 100644 --- a/Sample/Container.cs +++ b/Sample/Container.cs @@ -1,5 +1,4 @@ -using MrMeeseeks.DIE; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration; using MrMeeseeks.DIE.Sample; [assembly:ContainerInstanceAggregation(typeof(IContainerInstance))] diff --git a/Sample/Context.cs b/Sample/Context.cs index 14fc3d27..4108dbc4 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -1,16 +1,44 @@ -namespace MrMeeseeks.DIE.Sample; +using System.Collections.Generic; +using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Sample; -internal interface ITransientScopeInstanceInner {} -internal class TransientScopeInstance : ITransientScopeInstanceInner, ITransientScopeInstance {} +namespace MrMeeseeks.DIE.Test.ScopeSpecificAttributesTestsWithImplementations; -internal interface ITransientScopeWithTransientScopeInstance {} +internal interface IDependency {} -internal class TransientScopeWithTransientScopeInstance : ITransientScopeWithTransientScopeInstance, ITransientScopeRoot +internal class DependencyContainer : IDependency {} + +internal class DependencyTransientScope : IDependency {} + +internal class DependencyScope : IDependency {} + +internal class TransientScope : ITransientScopeRoot { - public TransientScopeWithTransientScopeInstance(ITransientScopeInstanceInner _) {} + public TransientScope(IReadOnlyList dependencies) => Dependencies = dependencies; + + public IReadOnlyList Dependencies { get; } } -internal partial class TransientScopeInstanceContainer : IContainer +internal class Scope : IScopeRoot { - + public Scope(IReadOnlyList dependencies) => Dependencies = dependencies; + + public IReadOnlyList Dependencies { get; } +} + +internal partial class Container : IContainer>, IContainer, IContainer +{ + [FilterImplementationAggregation(typeof(DependencyContainer))] + [FilterImplementationAggregation(typeof(DependencyScope))] + internal partial class DIE_DefaultTransientScope + { + + } + + [FilterImplementationAggregation(typeof(DependencyContainer))] + [FilterImplementationAggregation(typeof(DependencyTransientScope))] + internal partial class DIE_DefaultScope + { + + } } \ No newline at end of file diff --git a/Sample/Program.cs b/Sample/Program.cs index 6e1e1d30..10ab254a 100644 --- a/Sample/Program.cs +++ b/Sample/Program.cs @@ -1,7 +1,7 @@ using System; using MrMeeseeks.DIE; -using MrMeeseeks.DIE.Sample; +using MrMeeseeks.DIE.Test.ScopeSpecificAttributesTestsWithImplementations; Console.WriteLine("Hello, world!"); -var container = new TransientScopeInstanceContainer(); -Console.WriteLine(((IContainer) container).Resolve()); \ No newline at end of file +var container = new Container(); +Console.WriteLine(((IContainer) container).Resolve()); \ No newline at end of file diff --git a/Test/ScopeSpecificAttributesTestsWithImplementationLists.cs b/Test/ScopeSpecificAttributesTestsWithImplementationLists.cs new file mode 100644 index 00000000..38a7ac95 --- /dev/null +++ b/Test/ScopeSpecificAttributesTestsWithImplementationLists.cs @@ -0,0 +1,74 @@ +using System.Collections.Generic; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.ScopeSpecificAttributesTestsWithImplementationLists; + +internal interface IDependency {} + +internal class DependencyContainer : IDependency {} + +internal class DependencyTransientScope : IDependency {} + +internal class DependencyScope : IDependency {} + +internal class TransientScope : ITransientScopeRoot +{ + public TransientScope(IReadOnlyList dependencies) => Dependencies = dependencies; + + public IReadOnlyList Dependencies { get; } +} + +internal class Scope : IScopeRoot +{ + public Scope(IReadOnlyList dependencies) => Dependencies = dependencies; + + public IReadOnlyList Dependencies { get; } +} + +internal partial class Container : IContainer>, IContainer, IContainer +{ + [FilterImplementationAggregation(typeof(DependencyContainer))] + [FilterImplementationAggregation(typeof(DependencyScope))] + internal partial class DIE_DefaultTransientScope + { + + } + + [FilterImplementationAggregation(typeof(DependencyContainer))] + [FilterImplementationAggregation(typeof(DependencyTransientScope))] + internal partial class DIE_DefaultScope + { + + } +} +public class Tests +{ + + [Fact] + public void Container() + { + using var container = new Container(); + var dependencies = ((IContainer>) container).Resolve(); + Assert.Equal(3, dependencies.Count); + Assert.Contains(dependencies, d => d.GetType() == typeof(DependencyContainer)); + Assert.Contains(dependencies, d => d.GetType() == typeof(DependencyTransientScope)); + Assert.Contains(dependencies, d => d.GetType() == typeof(DependencyScope)); + } + [Fact] + public void TransientScope() + { + using var container = new Container(); + var dependencies = ((IContainer) container).Resolve(); + Assert.Equal(1, dependencies.Dependencies.Count); + Assert.Contains(dependencies.Dependencies, d => d.GetType() == typeof(DependencyTransientScope)); + } + [Fact] + public void Scope() + { + using var container = new Container(); + var dependencies = ((IContainer) container).Resolve(); + Assert.Equal(1, dependencies.Dependencies.Count); + Assert.Contains(dependencies.Dependencies, d => d.GetType() == typeof(DependencyScope)); + } +} \ No newline at end of file diff --git a/Test/ScopeSpecificAttributesTestsWithImplementations.cs b/Test/ScopeSpecificAttributesTestsWithImplementations.cs new file mode 100644 index 00000000..d4817bb6 --- /dev/null +++ b/Test/ScopeSpecificAttributesTestsWithImplementations.cs @@ -0,0 +1,70 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.ScopeSpecificAttributesTestsWithImplementations; + +internal interface IDependency {} + +internal class DependencyContainer : IDependency {} + +internal class DependencyTransientScope : IDependency {} + +internal class DependencyScope : IDependency {} + +internal class TransientScope : ITransientScopeRoot +{ + public TransientScope(IDependency dependency) => Dependency = dependency; + + public IDependency Dependency { get; } +} + +internal class Scope : IScopeRoot +{ + public Scope(IDependency dependency) => Dependency = dependency; + + public IDependency Dependency { get; } +} + +[FilterImplementationAggregation(typeof(DependencyScope))] +[FilterImplementationAggregation(typeof(DependencyTransientScope))] +internal partial class Container : IContainer, IContainer, IContainer +{ + [FilterImplementationAggregation(typeof(DependencyContainer))] + [ImplementationAggregation(typeof(DependencyTransientScope))] + internal partial class DIE_DefaultTransientScope + { + + } + + [FilterImplementationAggregation(typeof(DependencyContainer))] + [ImplementationAggregation(typeof(DependencyScope))] + internal partial class DIE_DefaultScope + { + + } +} +public class Tests +{ + + [Fact] + public void Container() + { + using var container = new Container(); + var dependency = ((IContainer) container).Resolve(); + Assert.IsType(dependency); + } + [Fact] + public void TransientScope() + { + using var container = new Container(); + var dependency = ((IContainer) container).Resolve(); + Assert.IsType(dependency.Dependency); + } + [Fact] + public void Scope() + { + using var container = new Container(); + var dependency = ((IContainer) container).Resolve(); + Assert.IsType(dependency.Dependency); + } +} \ No newline at end of file From e0402a42ba6f699c352beceb05156d2bd6448427 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Mon, 31 Jan 2022 08:00:18 +0100 Subject: [PATCH 045/162] Customizable scopes --- Main/CodeBuilding/ContainerCodeBuilder.cs | 16 +- Main/CodeBuilding/ContainerGenerator.cs | 8 +- Main/Configuration/Attributes.cs | 8 + Main/Constants.cs | 2 + .../ContainerResolutionBuilder.cs | 54 ++-- Main/ResolutionBuilding/ScopeManager.cs | 244 ++++++++++++++++++ .../ScopeResolutionBuilder.cs | 45 ++-- .../TransientScopeResolutionBuilder.cs | 46 ++-- Main/ResolutionTreeItem.cs | 4 +- Main/SourceGenerator.cs | 75 +++--- Main/WellKnownTypes.cs | 6 + Sample/Context.cs | 91 +++++-- Sample/Program.cs | 4 +- Test/ScopeSpecificAttributesTests.cs | 107 -------- ...opeSpecificAttributesTestsWithDecorator.cs | 164 ++++++++++++ 15 files changed, 633 insertions(+), 241 deletions(-) create mode 100644 Main/ResolutionBuilding/ScopeManager.cs delete mode 100644 Test/ScopeSpecificAttributesTests.cs create mode 100644 Test/ScopeSpecificAttributesTestsWithDecorator.cs diff --git a/Main/CodeBuilding/ContainerCodeBuilder.cs b/Main/CodeBuilding/ContainerCodeBuilder.cs index 82169424..15bae3af 100644 --- a/Main/CodeBuilding/ContainerCodeBuilder.cs +++ b/Main/CodeBuilding/ContainerCodeBuilder.cs @@ -9,8 +9,8 @@ internal class ContainerCodeBuilder : RangeCodeBaseBuilder, IContainerCodeBuilde { private readonly IContainerInfo _containerInfo; private readonly ContainerResolution _containerResolution; - private readonly ITransientScopeCodeBuilder _defaultTransientScopeCodeBuilder; - private readonly IScopeCodeBuilder _defaultScopeBuilder; + private readonly IReadOnlyList _transientScopeCodeBuilders; + private readonly IReadOnlyList _scopeCodeBuilders; public override StringBuilder Build(StringBuilder stringBuilder) { @@ -53,9 +53,9 @@ public override StringBuilder Build(StringBuilder stringBuilder) .AppendLine($"private {_containerResolution.TransientScopeInterface.ContainerAdapterName} _{_containerResolution.TransientScopeAdapterReference};") .AppendLine($"private {_containerResolution.TransientScopeInterface.ContainerAdapterName} {_containerResolution.TransientScopeAdapterReference} => _{_containerResolution.TransientScopeAdapterReference} ??= new {_containerResolution.TransientScopeInterface.ContainerAdapterName}(this);"); - stringBuilder = _defaultTransientScopeCodeBuilder.Build(stringBuilder); + stringBuilder = _transientScopeCodeBuilders.Aggregate(stringBuilder, (sb, cb) => cb.Build(sb)); - stringBuilder = _defaultScopeBuilder.Build(stringBuilder); + stringBuilder = _scopeCodeBuilders.Aggregate(stringBuilder, (sb, cb) => cb.Build(sb)); return stringBuilder .AppendLine($"}}") @@ -66,8 +66,8 @@ public ContainerCodeBuilder( // parameter IContainerInfo containerInfo, ContainerResolution containerResolution, - ITransientScopeCodeBuilder defaultTransientScopeCodeBuilder, - IScopeCodeBuilder defaultScopeBuilder, + IReadOnlyList transientScopeCodeBuilders, + IReadOnlyList scopeCodeBuilders, // dependencies WellKnownTypes wellKnownTypes) @@ -75,7 +75,7 @@ public ContainerCodeBuilder( { _containerInfo = containerInfo; _containerResolution = containerResolution; - _defaultTransientScopeCodeBuilder = defaultTransientScopeCodeBuilder; - _defaultScopeBuilder = defaultScopeBuilder; + _transientScopeCodeBuilders = transientScopeCodeBuilders; + _scopeCodeBuilders = scopeCodeBuilders; } } \ No newline at end of file diff --git a/Main/CodeBuilding/ContainerGenerator.cs b/Main/CodeBuilding/ContainerGenerator.cs index 8835e9d4..9fa39ded 100644 --- a/Main/CodeBuilding/ContainerGenerator.cs +++ b/Main/CodeBuilding/ContainerGenerator.cs @@ -12,14 +12,14 @@ internal class ContainerGenerator : IContainerGenerator { private readonly GeneratorExecutionContext _context; private readonly IDiagLogger _diagLogger; - private readonly Func _containerCodeBuilderFactory; + private readonly Func, IReadOnlyList, IContainerCodeBuilder> _containerCodeBuilderFactory; private readonly Func _transientScopeCodeBuilderFactory; private readonly Func _scopeCodeBuilderFactory; internal ContainerGenerator( GeneratorExecutionContext context, IDiagLogger diagLogger, - Func containerCodeBuilderFactory, + Func, IReadOnlyList, IContainerCodeBuilder> containerCodeBuilderFactory, Func transientScopeCodeBuilderFactory, Func scopeCodeBuilderFactory) { @@ -41,8 +41,8 @@ public void Generate(IContainerInfo containerInfo, ContainerResolution container var containerCodeBuilder = _containerCodeBuilderFactory( containerInfo, containerResolution, - _transientScopeCodeBuilderFactory(containerInfo, containerResolution.DefaultTransientScope, containerResolution), - _scopeCodeBuilderFactory(containerInfo, containerResolution.DefaultScope, containerResolution.TransientScopeInterface, containerResolution)); + containerResolution.TransientScopes.Select(ts => _transientScopeCodeBuilderFactory(containerInfo, ts, containerResolution)).ToList(), + containerResolution.Scopes.Select(s => _scopeCodeBuilderFactory(containerInfo, s, containerResolution.TransientScopeInterface, containerResolution)).ToList()); var generatedContainer = containerCodeBuilder.Build(new StringBuilder()); diff --git a/Main/Configuration/Attributes.cs b/Main/Configuration/Attributes.cs index 6f3cb3c3..73e22fd7 100644 --- a/Main/Configuration/Attributes.cs +++ b/Main/Configuration/Attributes.cs @@ -161,4 +161,12 @@ public FilterConstructorChoiceAttribute(Type implementationType) { } } + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class CustomScopeForRootTypesAttribute : Attribute +{ + public CustomScopeForRootTypesAttribute(params Type[] types) + { + } +} // ReSharper enable UnusedParameter.Local \ No newline at end of file diff --git a/Main/Constants.cs b/Main/Constants.cs index 8bd59b15..1e0c504a 100644 --- a/Main/Constants.cs +++ b/Main/Constants.cs @@ -6,5 +6,7 @@ internal static class Constants { internal const string ThisKeyword = "this"; internal const string DefaultScopeName = "DIE_DefaultScope"; + internal const string CustomScopeName = "DIE_Scope"; internal const string DefaultTransientScopeName = "DIE_DefaultTransientScope"; + internal const string CustomTransientScopeName = "DIE_TransientScope"; } \ No newline at end of file diff --git a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs index b87e8b5b..52f3b286 100644 --- a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs @@ -19,9 +19,8 @@ internal class ContainerResolutionBuilder : RangeResolutionBaseBuilder, IContain private readonly ITransientScopeInterfaceResolutionBuilder _transientScopeInterfaceResolutionBuilder; private readonly List _rootResolutions = new (); - private readonly IScopeResolutionBuilder _scopeResolutionBuilder; private readonly string _transientScopeAdapterReference; - private readonly ITransientScopeResolutionBuilder _transientScopeResolutionBuilder; + private readonly IScopeManager _scopeManager; internal ContainerResolutionBuilder( // parameters @@ -32,8 +31,7 @@ internal ContainerResolutionBuilder( IReferenceGeneratorFactory referenceGeneratorFactory, ICheckTypeProperties checkTypeProperties, WellKnownTypes wellKnownTypes, - Func transientScopeResolutionBuilderFactory, - Func scopeResolutionBuilderFactory, + Func scopeManagerFactory, IUserProvidedScopeElements userProvidedScopeElements) : base( containerInfo.Name, @@ -44,13 +42,9 @@ internal ContainerResolutionBuilder( { _containerInfo = containerInfo; _transientScopeInterfaceResolutionBuilder = transientScopeInterfaceResolutionBuilder; - _transientScopeResolutionBuilder = transientScopeResolutionBuilderFactory(this, _transientScopeInterfaceResolutionBuilder); - _scopeResolutionBuilder = scopeResolutionBuilderFactory(this, _transientScopeResolutionBuilder, _transientScopeInterfaceResolutionBuilder); - if (_transientScopeResolutionBuilder is TransientScopeResolutionBuilder transientScopeResolutionBuilder) - transientScopeResolutionBuilder.ScopeResolutionBuilder = _scopeResolutionBuilder; + _scopeManager = scopeManagerFactory(this, transientScopeInterfaceResolutionBuilder); transientScopeInterfaceResolutionBuilder.AddImplementation(this); - transientScopeInterfaceResolutionBuilder.AddImplementation(_transientScopeResolutionBuilder); _transientScopeAdapterReference = RootReferenceGenerator.Generate("TransientScopeAdapter"); } @@ -84,37 +78,41 @@ protected override RangedInstanceReferenceResolution CreateTransientScopeInstanc protected override TransientScopeRootResolution CreateTransientScopeRootResolution(IScopeRootParameter parameter, INamedTypeSymbol rootType, DisposableCollectionResolution disposableCollectionResolution, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) => - _transientScopeResolutionBuilder.AddCreateResolveFunction( - parameter, - rootType, - "this", - disposableCollectionResolution, - currentParameters); + _scopeManager + .GetTransientScopeBuilder(rootType) + .AddCreateResolveFunction( + parameter, + rootType, + "this", + disposableCollectionResolution, + currentParameters); protected override ScopeRootResolution CreateScopeRootResolution( IScopeRootParameter parameter, INamedTypeSymbol rootType, DisposableCollectionResolution disposableCollectionResolution, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) => - _scopeResolutionBuilder.AddCreateResolveFunction( - parameter, - rootType, - "this", - _transientScopeAdapterReference, - disposableCollectionResolution, - currentParameters); + _scopeManager + .GetScopeBuilder(rootType) + .AddCreateResolveFunction( + parameter, + rootType, + "this", + _transientScopeAdapterReference, + disposableCollectionResolution, + currentParameters); public ContainerResolution Build() { while (RangedInstanceResolutionsQueue.Any() - || _transientScopeResolutionBuilder.HasWorkToDo - || _scopeResolutionBuilder.HasWorkToDo) + || _scopeManager.HasWorkToDo) { DoRangedInstancesWork(); - _transientScopeResolutionBuilder.DoWork(); - _scopeResolutionBuilder.DoWork(); + _scopeManager.DoWork(); } + var (transientScopeResolutions, scopeResolutions) = _scopeManager.Build(); + return new( _rootResolutions, DisposalHandling, @@ -127,8 +125,8 @@ public ContainerResolution Build() .ToList(), _transientScopeInterfaceResolutionBuilder.Build(), _transientScopeAdapterReference, - _transientScopeResolutionBuilder.Build(), - _scopeResolutionBuilder.Build()); + transientScopeResolutions, + scopeResolutions); } public void EnqueueRangedInstanceResolution(RangedInstanceResolutionsQueueItem item) => RangedInstanceResolutionsQueue.Enqueue(item); diff --git a/Main/ResolutionBuilding/ScopeManager.cs b/Main/ResolutionBuilding/ScopeManager.cs new file mode 100644 index 00000000..0a55e81a --- /dev/null +++ b/Main/ResolutionBuilding/ScopeManager.cs @@ -0,0 +1,244 @@ +using System.Threading; +using MrMeeseeks.DIE.Configuration; + +namespace MrMeeseeks.DIE.ResolutionBuilding; + +internal interface IScopeManager +{ + IScopeResolutionBuilder GetScopeBuilder(INamedTypeSymbol scopeRootType); + ITransientScopeResolutionBuilder GetTransientScopeBuilder(INamedTypeSymbol transientScopeRootType); + + bool HasWorkToDo { get; } + + void DoWork(); + + (IReadOnlyList, IReadOnlyList) Build(); +} + +internal class ScopeManager : IScopeManager +{ + private readonly IContainerInfo _containerInfo; + private readonly IContainerResolutionBuilder _containerResolutionBuilder; + private readonly ITransientScopeInterfaceResolutionBuilder _transientScopeInterfaceResolutionBuilder; + private readonly ImmutableList _containerTypesFromAttributesList; + + private readonly Func< + string, + IContainerResolutionBuilder, + ITransientScopeInterfaceResolutionBuilder , + IScopeManager, + IUserProvidedScopeElements, + ICheckTypeProperties, + IScopeResolutionBuilder> _scopeResolutionBuilderFactory; + private readonly Func< + string, + IContainerResolutionBuilder, + ITransientScopeInterfaceResolutionBuilder , + IScopeManager, + IUserProvidedScopeElements, + ICheckTypeProperties, + ITransientScopeResolutionBuilder> _transientScopeResolutionBuilderFactory; + private readonly Func, ScopeTypesFromAttributes> _scopeTypesFromAttributesFactory; + private readonly Func, ICheckTypeProperties> _checkTypePropertiesFactory; + private readonly Func _userProvidedScopeElementsFactory; + private readonly Lazy _defaultScopeBuilder; + private readonly Lazy _defaultTransientScopeBuilder; + private readonly IDictionary _customScopeBuilders; + private readonly IDictionary _customTransientScopeBuilders; + private readonly IReadOnlyDictionary _transientScopeRootTypeToScopeType; + private readonly IReadOnlyDictionary _scopeRootTypeToScopeType; + + public ScopeManager( + IContainerInfo containerInfo, + IContainerResolutionBuilder containerResolutionBuilder, + ITransientScopeInterfaceResolutionBuilder transientScopeInterfaceResolutionBuilder, + ImmutableList containerTypesFromAttributesList, + Func< + string, + IContainerResolutionBuilder, + ITransientScopeInterfaceResolutionBuilder , + IScopeManager, + IUserProvidedScopeElements, + ICheckTypeProperties, + ITransientScopeResolutionBuilder> transientScopeResolutionBuilderFactory, + Func< + string, + IContainerResolutionBuilder, + ITransientScopeInterfaceResolutionBuilder , + IScopeManager, + IUserProvidedScopeElements, + ICheckTypeProperties, + IScopeResolutionBuilder> scopeResolutionBuilderFactory, + Func, ScopeTypesFromAttributes> scopeTypesFromAttributesFactory, + Func, ICheckTypeProperties> checkTypePropertiesFactory, + Func userProvidedScopeElementsFactory, + IUserProvidedScopeElements emptyUserProvidedScopeElements, + WellKnownTypes wellKnownTypes) + { + _containerInfo = containerInfo; + _containerResolutionBuilder = containerResolutionBuilder; + _transientScopeInterfaceResolutionBuilder = transientScopeInterfaceResolutionBuilder; + _containerTypesFromAttributesList = containerTypesFromAttributesList; + _scopeResolutionBuilderFactory = scopeResolutionBuilderFactory; + _transientScopeResolutionBuilderFactory = transientScopeResolutionBuilderFactory; + _scopeTypesFromAttributesFactory = scopeTypesFromAttributesFactory; + _checkTypePropertiesFactory = checkTypePropertiesFactory; + _userProvidedScopeElementsFactory = userProvidedScopeElementsFactory; + _defaultScopeBuilder = new Lazy( + () => + { + var defaultScopeType = _containerInfo.ContainerType.GetTypeMembers(Constants.DefaultScopeName).FirstOrDefault(); + var defaultScopeTypesFromAttributes = _scopeTypesFromAttributesFactory(defaultScopeType?.GetAttributes() ?? ImmutableArray.Empty); + return _scopeResolutionBuilderFactory( + Constants.DefaultScopeName, + _containerResolutionBuilder, + _transientScopeInterfaceResolutionBuilder, + this, + defaultScopeType is {} + ? _userProvidedScopeElementsFactory(defaultScopeType) + : emptyUserProvidedScopeElements, + _checkTypePropertiesFactory(_containerTypesFromAttributesList.Add(defaultScopeTypesFromAttributes))); + }, + LazyThreadSafetyMode.ExecutionAndPublication); + _defaultTransientScopeBuilder = new Lazy( + () => + { + var defaultTransientScopeType = _containerInfo.ContainerType.GetTypeMembers(Constants.DefaultTransientScopeName).FirstOrDefault(); + var defaultTransientScopeTypesFromAttributes = _scopeTypesFromAttributesFactory(defaultTransientScopeType?.GetAttributes() ?? ImmutableArray.Empty); + var ret = _transientScopeResolutionBuilderFactory( + Constants.DefaultTransientScopeName, + _containerResolutionBuilder, + _transientScopeInterfaceResolutionBuilder, + this, + defaultTransientScopeType is {} + ? _userProvidedScopeElementsFactory(defaultTransientScopeType) + : emptyUserProvidedScopeElements, + _checkTypePropertiesFactory(_containerTypesFromAttributesList.Add(defaultTransientScopeTypesFromAttributes))); + _transientScopeInterfaceResolutionBuilder.AddImplementation(ret); + return ret; + }, + LazyThreadSafetyMode.ExecutionAndPublication); + _customScopeBuilders = new Dictionary(SymbolEqualityComparer.Default); + _customTransientScopeBuilders = new Dictionary(SymbolEqualityComparer.Default); + + _transientScopeRootTypeToScopeType = containerInfo + .ContainerType + .GetTypeMembers() + .Where(nts => nts.Name.StartsWith(Constants.CustomTransientScopeName)) + .SelectMany(nts => nts.GetAttributes() + .Where(ad => + SymbolEqualityComparer.Default.Equals(ad.AttributeClass, + wellKnownTypes.CustomScopeForRootTypesAttribute)) + .SelectMany(ad => ad + .ConstructorArguments + .SelectMany(tc => tc.Kind switch + { + TypedConstantKind.Type => new [] { tc.Value as INamedTypeSymbol }, + TypedConstantKind.Array => tc + .Values + .Where(subTc => subTc.Kind == TypedConstantKind.Type) + .Select(subTc => subTc.Value as INamedTypeSymbol), + _ => Array.Empty() + })) + .OfType() + .Select(rootType => (rootType, nts))) + .ToDictionary(t => t.rootType, t => t.nts); + + _scopeRootTypeToScopeType = containerInfo + .ContainerType + .GetTypeMembers() + .Where(nts => nts.Name.StartsWith(Constants.CustomScopeName)) + .SelectMany(nts => nts.GetAttributes() + .Where(ad => + SymbolEqualityComparer.Default.Equals(ad.AttributeClass, + wellKnownTypes.CustomScopeForRootTypesAttribute)) + .SelectMany(ad => ad + .ConstructorArguments + .SelectMany(tc => tc.Kind switch + { + TypedConstantKind.Type => new [] { tc.Value as INamedTypeSymbol }, + TypedConstantKind.Array => tc + .Values + .Where(subTc => subTc.Kind == TypedConstantKind.Type) + .Select(subTc => subTc.Value as INamedTypeSymbol), + _ => Array.Empty() + })) + .OfType() + .Select(rootType => (rootType, nts))) + .ToDictionary(t => t.rootType, t => t.nts); + } + + public IScopeResolutionBuilder GetScopeBuilder(INamedTypeSymbol scopeRootType) + { + if (_customScopeBuilders.TryGetValue(scopeRootType, out var builder)) + return builder; + + if (!_scopeRootTypeToScopeType.TryGetValue(scopeRootType, out var scopeType)) + return _defaultScopeBuilder.Value; + + var scopeTypesFromAttributes = _scopeTypesFromAttributesFactory(scopeType.GetAttributes()); + var ret = _scopeResolutionBuilderFactory( + scopeType.Name, + _containerResolutionBuilder, + _transientScopeInterfaceResolutionBuilder, + this, + _userProvidedScopeElementsFactory(scopeType), + _checkTypePropertiesFactory(_containerTypesFromAttributesList.Add(scopeTypesFromAttributes))); + _customScopeBuilders[scopeRootType] = ret; + return ret; + } + + public ITransientScopeResolutionBuilder GetTransientScopeBuilder(INamedTypeSymbol transientScopeRootType) + { + if (_customTransientScopeBuilders.TryGetValue(transientScopeRootType, out var builder)) + return builder; + + if (!_transientScopeRootTypeToScopeType.TryGetValue(transientScopeRootType, out var scopeType)) + return _defaultTransientScopeBuilder.Value; + + var scopeTypesFromAttributes = _scopeTypesFromAttributesFactory(scopeType.GetAttributes()); + var ret = _transientScopeResolutionBuilderFactory( + scopeType.Name, + _containerResolutionBuilder, + _transientScopeInterfaceResolutionBuilder, + this, + _userProvidedScopeElementsFactory(scopeType), + _checkTypePropertiesFactory(_containerTypesFromAttributesList.Add(scopeTypesFromAttributes))); + _customTransientScopeBuilders[transientScopeRootType] = ret; + _transientScopeInterfaceResolutionBuilder.AddImplementation(ret); + return ret; + } + + public bool HasWorkToDo => + _defaultScopeBuilder.IsValueCreated && _defaultScopeBuilder.Value.HasWorkToDo + || _defaultTransientScopeBuilder.IsValueCreated && _defaultTransientScopeBuilder.Value.HasWorkToDo + || _customScopeBuilders.Values.Any(sb => sb.HasWorkToDo) + || _customTransientScopeBuilders.Values.Any(tsb => tsb.HasWorkToDo); + + public void DoWork() + { + if (_defaultScopeBuilder.IsValueCreated) _defaultScopeBuilder.Value.DoWork(); + if (_defaultTransientScopeBuilder.IsValueCreated) _defaultTransientScopeBuilder.Value.DoWork(); + foreach (var customScopeBuilder in _customScopeBuilders.Values) + customScopeBuilder.DoWork(); + foreach (var customTransientScopeBuilder in _customTransientScopeBuilders.Values) + customTransientScopeBuilder.DoWork(); + } + + public (IReadOnlyList, IReadOnlyList) Build() + { + return ( + _customTransientScopeBuilders + .Values + .Prepend(_defaultTransientScopeBuilder.IsValueCreated ? _defaultTransientScopeBuilder.Value : null) + .OfType() + .Select(tsb => tsb.Build()) + .ToList(), + _customScopeBuilders + .Values + .Prepend(_defaultScopeBuilder.IsValueCreated ? _defaultScopeBuilder.Value : null) + .OfType() + .Select(sb => sb.Build()) + .ToList()); + } +} \ No newline at end of file diff --git a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs index 8d946b83..1044f5f3 100644 --- a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs @@ -22,8 +22,8 @@ ScopeRootResolution AddCreateResolveFunction( internal class ScopeResolutionBuilder : RangeResolutionBaseBuilder, IScopeResolutionBuilder { private readonly IContainerResolutionBuilder _containerResolutionBuilder; - private readonly ITransientScopeResolutionBuilder _transientScopeResolutionBuilder; private readonly ITransientScopeInterfaceResolutionBuilder _transientScopeInterfaceResolutionBuilder; + private readonly IScopeManager _scopeManager; private readonly List _rootResolutions = new (); private readonly string _containerReference; private readonly string _containerParameterReference; @@ -36,25 +36,26 @@ internal class ScopeResolutionBuilder : RangeResolutionBaseBuilder, IScopeResolu internal ScopeResolutionBuilder( // parameter + string name, IContainerResolutionBuilder containerResolutionBuilder, - ITransientScopeResolutionBuilder transientScopeResolutionBuilder, ITransientScopeInterfaceResolutionBuilder transientScopeInterfaceResolutionBuilder, + IScopeManager scopeManager, + IUserProvidedScopeElements userProvidedScopeElements, + ICheckTypeProperties checkTypeProperties, // dependencies WellKnownTypes wellKnownTypes, - IReferenceGeneratorFactory referenceGeneratorFactory, - ICheckTypeProperties checkTypeProperties, - IUserProvidedScopeElements userProvidedScopeElements) + IReferenceGeneratorFactory referenceGeneratorFactory) : base( - Constants.DefaultScopeName, + name, //Constants.DefaultScopeName, wellKnownTypes, referenceGeneratorFactory, checkTypeProperties, userProvidedScopeElements) { _containerResolutionBuilder = containerResolutionBuilder; - _transientScopeResolutionBuilder = transientScopeResolutionBuilder; _transientScopeInterfaceResolutionBuilder = transientScopeInterfaceResolutionBuilder; + _scopeManager = scopeManager; _containerReference = RootReferenceGenerator.Generate("_container"); _containerParameterReference = RootReferenceGenerator.Generate("container"); _transientScopeReference = RootReferenceGenerator.Generate("_transientScope"); @@ -72,25 +73,29 @@ protected override TransientScopeRootResolution CreateTransientScopeRootResoluti INamedTypeSymbol rootType, DisposableCollectionResolution disposableCollectionResolution, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) => - _transientScopeResolutionBuilder.AddCreateResolveFunction( - parameter, - rootType, - _containerReference, - disposableCollectionResolution, - currentParameters); + _scopeManager + .GetTransientScopeBuilder(rootType) + .AddCreateResolveFunction( + parameter, + rootType, + _containerReference, + disposableCollectionResolution, + currentParameters); protected override ScopeRootResolution CreateScopeRootResolution( IScopeRootParameter parameter, INamedTypeSymbol rootType, DisposableCollectionResolution disposableCollectionResolution, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) => - AddCreateResolveFunction( - parameter, - rootType, - _containerReference, - _transientScopeReference, - disposableCollectionResolution, - currentParameters); + _scopeManager + .GetScopeBuilder(rootType) + .AddCreateResolveFunction( + parameter, + rootType, + _containerReference, + _transientScopeReference, + disposableCollectionResolution, + currentParameters); public bool HasWorkToDo => _scopeRootFunctionResolutionsQueue.Any() || RangedInstanceResolutionsQueue.Any(); diff --git a/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs b/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs index f67fd841..8857f80c 100644 --- a/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs @@ -22,6 +22,7 @@ internal class TransientScopeResolutionBuilder : RangeResolutionBaseBuilder, ITr { private readonly IContainerResolutionBuilder _containerResolutionBuilder; private readonly ITransientScopeInterfaceResolutionBuilder _transientScopeInterfaceResolutionBuilder; + private readonly IScopeManager _scopeManager; private readonly List _rootResolutions = new (); private readonly string _containerReference; private readonly string _containerParameterReference; @@ -29,21 +30,21 @@ internal class TransientScopeResolutionBuilder : RangeResolutionBaseBuilder, ITr private readonly Dictionary _transientScopeRootFunctionResolutions = new (); private readonly HashSet<(ScopeRootFunction, string)> _transientScopeRootFunctionQueuedOverloads = new (); private readonly Queue<(ScopeRootFunction, IReadOnlyList, INamedTypeSymbol, IScopeRootParameter)> _transientScopeRootFunctionResolutionsQueue = new(); - - public IScopeResolutionBuilder? ScopeResolutionBuilder { get; set; } - + internal TransientScopeResolutionBuilder( // parameter + string name, IContainerResolutionBuilder containerResolutionBuilder, ITransientScopeInterfaceResolutionBuilder transientScopeInterfaceResolutionBuilder, + IScopeManager scopeManager, + IUserProvidedScopeElements userProvidedScopeElements, + ICheckTypeProperties checkTypeProperties, // dependencies WellKnownTypes wellKnownTypes, - IReferenceGeneratorFactory referenceGeneratorFactory, - ICheckTypeProperties checkTypeProperties, - IUserProvidedScopeElements userProvidedScopeElements) + IReferenceGeneratorFactory referenceGeneratorFactory) : base( - Constants.DefaultTransientScopeName, + name, wellKnownTypes, referenceGeneratorFactory, checkTypeProperties, @@ -51,6 +52,7 @@ internal TransientScopeResolutionBuilder( { _containerResolutionBuilder = containerResolutionBuilder; _transientScopeInterfaceResolutionBuilder = transientScopeInterfaceResolutionBuilder; + _scopeManager = scopeManager; _containerReference = RootReferenceGenerator.Generate("_container"); _containerParameterReference = RootReferenceGenerator.Generate("container"); } @@ -63,25 +65,29 @@ protected override RangedInstanceReferenceResolution CreateTransientScopeInstanc protected override TransientScopeRootResolution CreateTransientScopeRootResolution(IScopeRootParameter parameter, INamedTypeSymbol rootType, DisposableCollectionResolution disposableCollectionResolution, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) => - AddCreateResolveFunction( - parameter, - rootType, - _containerReference, - disposableCollectionResolution, - currentParameters); + _scopeManager + .GetTransientScopeBuilder(rootType) + .AddCreateResolveFunction( + parameter, + rootType, + _containerReference, + disposableCollectionResolution, + currentParameters); protected override ScopeRootResolution CreateScopeRootResolution( IScopeRootParameter parameter, INamedTypeSymbol rootType, DisposableCollectionResolution disposableCollectionResolution, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) => - ScopeResolutionBuilder!.AddCreateResolveFunction( - parameter, - rootType, - _containerReference, - "this", - disposableCollectionResolution, - currentParameters); + _scopeManager + .GetScopeBuilder(rootType) + .AddCreateResolveFunction( + parameter, + rootType, + _containerReference, + "this", + disposableCollectionResolution, + currentParameters); public bool HasWorkToDo => _transientScopeRootFunctionResolutionsQueue.Any() || RangedInstanceResolutionsQueue.Any(); diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index 4b669190..74bdab9e 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -160,8 +160,8 @@ internal record ContainerResolution( IReadOnlyList RangedInstances, TransientScopeInterfaceResolution TransientScopeInterface, string TransientScopeAdapterReference, - TransientScopeResolution DefaultTransientScope, - ScopeResolution DefaultScope) + IReadOnlyList TransientScopes, + IReadOnlyList Scopes) : RangeResolution(RootResolutions, DisposalHandling, RangedInstances, "this"); internal record DisposalHandling( diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index 0ed7ac2c..6c941b9f 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -39,12 +39,6 @@ IContainerResolutionBuilder ResolutionTreeFactory(IContainerInfo ci) (ITypesFromAttributes) attributeTypesFromAttributes, new TypesFromAttributes(ci.ContainerType.GetAttributes(), wellKnownTypes)); - var defaultTransientScopeType = ci.ContainerType.GetTypeMembers(Constants.DefaultTransientScopeName).FirstOrDefault(); - var defaultTransientScopeTypesFromAttributes = new ScopeTypesFromAttributes(defaultTransientScopeType?.GetAttributes() ?? ImmutableArray.Empty, wellKnownTypes); - - var defaultScopeType = ci.ContainerType.GetTypeMembers(Constants.DefaultScopeName).FirstOrDefault(); - var defaultScopeTypesFromAttributes = new ScopeTypesFromAttributes(defaultScopeType?.GetAttributes() ?? ImmutableArray.Empty, wellKnownTypes); - return new ContainerResolutionBuilder( ci, @@ -52,39 +46,56 @@ IContainerResolutionBuilder ResolutionTreeFactory(IContainerInfo ci) referenceGeneratorFactory, new CheckTypeProperties(new CurrentlyConsideredTypes(containerTypesFromAttributesList, context)), wellKnownTypes, + ScopeManagerFactory, + new UserProvidedScopeElements(ci.ContainerType)); + + IScopeManager ScopeManagerFactory( + IContainerResolutionBuilder containerResolutionBuilder, + ITransientScopeInterfaceResolutionBuilder transientScopeInterfaceResolutionBuilder) => new ScopeManager( + ci, + containerResolutionBuilder, + transientScopeInterfaceResolutionBuilder, + containerTypesFromAttributesList, TransientScopeResolutionBuilderFactory, ScopeResolutionBuilderFactory, - new UserProvidedScopeElements(ci.ContainerType)); + ad => new ScopeTypesFromAttributes(ad, wellKnownTypes), + tfa => new CheckTypeProperties(new CurrentlyConsideredTypes(tfa, context)), + st => new UserProvidedScopeElements(st), + new EmptyUserProvidedScopeElements(), + wellKnownTypes); - ITransientScopeResolutionBuilder TransientScopeResolutionBuilderFactory(IContainerResolutionBuilder containerBuilder, ITransientScopeInterfaceResolutionBuilder transientScopeInterfaceResolutionBuilder) => new TransientScopeResolutionBuilder( + ITransientScopeResolutionBuilder TransientScopeResolutionBuilderFactory( + string name, + IContainerResolutionBuilder containerBuilder, + ITransientScopeInterfaceResolutionBuilder transientScopeInterfaceResolutionBuilder, + IScopeManager scopeManager, + IUserProvidedScopeElements userProvidedScopeElements, + ICheckTypeProperties checkTypeProperties) => new TransientScopeResolutionBuilder( + name, containerBuilder, transientScopeInterfaceResolutionBuilder, + scopeManager, + userProvidedScopeElements, + checkTypeProperties, wellKnownTypes, - referenceGeneratorFactory, - new CheckTypeProperties( - new CurrentlyConsideredTypes( - containerTypesFromAttributesList.Add(defaultTransientScopeTypesFromAttributes), - context)), - defaultTransientScopeType is {} - ? new UserProvidedScopeElements(defaultTransientScopeType) - : new EmptyUserProvidedScopeElements()); - IScopeResolutionBuilder ScopeResolutionBuilderFactory(IContainerResolutionBuilder containerBuilder, ITransientScopeResolutionBuilder transientScopeResolutionBuilder, ITransientScopeInterfaceResolutionBuilder transientScopeInterfaceResolutionBuilder) => new ScopeResolutionBuilder( + referenceGeneratorFactory); + IScopeResolutionBuilder ScopeResolutionBuilderFactory( + string name, + IContainerResolutionBuilder containerBuilder, + ITransientScopeInterfaceResolutionBuilder transientScopeInterfaceResolutionBuilder, + IScopeManager scopeManager, + IUserProvidedScopeElements userProvidedScopeElements, + ICheckTypeProperties checkTypeProperties) => new ScopeResolutionBuilder( + name, containerBuilder, - transientScopeResolutionBuilder, transientScopeInterfaceResolutionBuilder, + scopeManager, + userProvidedScopeElements, + checkTypeProperties, wellKnownTypes, - referenceGeneratorFactory, - new CheckTypeProperties( - new CurrentlyConsideredTypes( - containerTypesFromAttributesList.Add(defaultScopeTypesFromAttributes), - context)), - defaultScopeType is {} - ? new UserProvidedScopeElements(defaultScopeType) - : new EmptyUserProvidedScopeElements()); - - + referenceGeneratorFactory); } IContainerInfo ContainerInfoFactory(INamedTypeSymbol type) => new ContainerInfo(type, wellKnownTypes); IReferenceGenerator ReferenceGeneratorFactory(int j) => new ReferenceGenerator(j); @@ -92,12 +103,12 @@ defaultScopeType is {} IContainerCodeBuilder ContainerCodeBuilderFactory( IContainerInfo containerInfo, ContainerResolution containerResolution, - ITransientScopeCodeBuilder transientScopeCodeBuilder, - IScopeCodeBuilder scopeCodeBuilder) => new ContainerCodeBuilder( + IReadOnlyList transientScopeCodeBuilders, + IReadOnlyList scopeCodeBuilders) => new ContainerCodeBuilder( containerInfo, containerResolution, - transientScopeCodeBuilder, - scopeCodeBuilder, + transientScopeCodeBuilders, + scopeCodeBuilders, wellKnownTypes); ITransientScopeCodeBuilder TransientScopeCodeBuilderFactory( diff --git a/Main/WellKnownTypes.cs b/Main/WellKnownTypes.cs index 58760e3a..adbfec6e 100644 --- a/Main/WellKnownTypes.cs +++ b/Main/WellKnownTypes.cs @@ -30,6 +30,7 @@ internal record WellKnownTypes( INamedTypeSymbol FilterCompositeAggregationAttribute, INamedTypeSymbol FilterDecoratorSequenceChoiceAttribute, INamedTypeSymbol FilterConstructorChoiceAttribute, + INamedTypeSymbol CustomScopeForRootTypesAttribute, INamedTypeSymbol Disposable, INamedTypeSymbol AsyncDisposable, INamedTypeSymbol Lazy1, @@ -146,6 +147,9 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK var filterConstructorChoiceAttribute = compilation .GetTypeByMetadataName(typeof(FilterConstructorChoiceAttribute).FullName ?? ""); + var customScopeForRootTypesAttribute = compilation + .GetTypeByMetadataName(typeof(CustomScopeForRootTypesAttribute).FullName ?? ""); + if (iContainer is null || spyAggregationAttribute is null || spyConstructorChoiceAggregationAttribute is null @@ -173,6 +177,7 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK || filterCompositeAggregationAttribute is null || filterDecoratorSequenceChoiceAttribute is null || filterConstructorChoiceAttribute is null + || customScopeForRootTypesAttribute is null || iDisposable is null || iAsyncDisposable is null || lazy1 is null @@ -221,6 +226,7 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK FilterCompositeAggregationAttribute: filterCompositeAggregationAttribute, FilterDecoratorSequenceChoiceAttribute: filterDecoratorSequenceChoiceAttribute, FilterConstructorChoiceAttribute: filterConstructorChoiceAttribute, + CustomScopeForRootTypesAttribute: customScopeForRootTypesAttribute, Disposable: iDisposable, AsyncDisposable: iAsyncDisposable, Lazy1: lazy1, diff --git a/Sample/Context.cs b/Sample/Context.cs index 4108dbc4..f398fb6b 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -1,42 +1,97 @@ -using System.Collections.Generic; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration; using MrMeeseeks.DIE.Sample; -namespace MrMeeseeks.DIE.Test.ScopeSpecificAttributesTestsWithImplementations; +namespace MrMeeseeks.DIE.Test.ScopeSpecificAttributesTestsWithDecorator; -internal interface IDependency {} +internal interface IInterface +{ + int CheckNumber { get; } +} -internal class DependencyContainer : IDependency {} +internal class Implementation : IInterface +{ + public int CheckNumber => 1; +} -internal class DependencyTransientScope : IDependency {} +internal class ContainerDecorator : IInterface, IDecorator +{ + public int CheckNumber => 69; + + internal ContainerDecorator(IInterface _) {} +} -internal class DependencyScope : IDependency {} +internal class ScopeDecorator : IInterface, IDecorator +{ + public int CheckNumber => 3; + + internal ScopeDecorator(IInterface _) {} +} -internal class TransientScope : ITransientScopeRoot +internal class TransientScopeDecorator : IInterface, IDecorator { - public TransientScope(IReadOnlyList dependencies) => Dependencies = dependencies; + public int CheckNumber => 23; + + internal TransientScopeDecorator(IInterface _) {} +} - public IReadOnlyList Dependencies { get; } +internal class TransientScopeSpecificDecorator : IInterface, IDecorator +{ + public int CheckNumber => 7; + + internal TransientScopeSpecificDecorator(IInterface _) {} } -internal class Scope : IScopeRoot +internal class TransientScopeRoot : ITransientScopeRoot { - public Scope(IReadOnlyList dependencies) => Dependencies = dependencies; + public IInterface Dep { get; } + + internal TransientScopeRoot(IInterface dep) + { + Dep = dep; + } +} - public IReadOnlyList Dependencies { get; } +internal class TransientScopeRootSpecific : ITransientScopeRoot +{ + public IInterface Dep { get; } + + internal TransientScopeRootSpecific(IInterface dep) + { + Dep = dep; + } +} + +internal class ScopeRoot : IScopeRoot +{ + public IInterface Dep { get; } + + internal ScopeRoot(IInterface dep) + { + Dep = dep; + } } -internal partial class Container : IContainer>, IContainer, IContainer + +[DecoratorSequenceChoice(typeof(IInterface), typeof(ContainerDecorator))] +internal partial class Container + : IContainer, + IContainer, + IContainer, + IContainer { - [FilterImplementationAggregation(typeof(DependencyContainer))] - [FilterImplementationAggregation(typeof(DependencyScope))] + [DecoratorSequenceChoice(typeof(IInterface), typeof(TransientScopeDecorator))] internal partial class DIE_DefaultTransientScope { + } + [DecoratorSequenceChoice(typeof(IInterface), typeof(TransientScopeSpecificDecorator))] + [CustomScopeForRootTypes(typeof(TransientScopeRootSpecific))] + internal partial class DIE_TransientScope_A + { + } - [FilterImplementationAggregation(typeof(DependencyContainer))] - [FilterImplementationAggregation(typeof(DependencyTransientScope))] + [DecoratorSequenceChoice(typeof(IInterface), typeof(ScopeDecorator))] internal partial class DIE_DefaultScope { diff --git a/Sample/Program.cs b/Sample/Program.cs index 10ab254a..e040e7a7 100644 --- a/Sample/Program.cs +++ b/Sample/Program.cs @@ -1,7 +1,7 @@ using System; using MrMeeseeks.DIE; -using MrMeeseeks.DIE.Test.ScopeSpecificAttributesTestsWithImplementations; +using MrMeeseeks.DIE.Test.ScopeSpecificAttributesTestsWithDecorator; Console.WriteLine("Hello, world!"); var container = new Container(); -Console.WriteLine(((IContainer) container).Resolve()); \ No newline at end of file +Console.WriteLine(((IContainer) container).Resolve()); \ No newline at end of file diff --git a/Test/ScopeSpecificAttributesTests.cs b/Test/ScopeSpecificAttributesTests.cs deleted file mode 100644 index f89ed648..00000000 --- a/Test/ScopeSpecificAttributesTests.cs +++ /dev/null @@ -1,107 +0,0 @@ -using MrMeeseeks.DIE.Configuration; -using Xunit; - -namespace MrMeeseeks.DIE.Test; - -internal interface IScopeSpecificAttributesInterface -{ - int Number { get; } -} - -internal class ScopeSpecificAttributesImplementation : IScopeSpecificAttributesInterface -{ - public int Number => 1; -} - -internal class ScopeSpecificAttributesContai : IScopeSpecificAttributesInterface, IDecorator -{ - public int Number => 69; - - internal ScopeSpecificAttributesContai(IScopeSpecificAttributesInterface _) {} -} - -internal class ScopeSpecificAttributesScope : IScopeSpecificAttributesInterface, IDecorator -{ - public int Number => 3; - - internal ScopeSpecificAttributesScope(IScopeSpecificAttributesInterface _) {} -} - -internal class ScopeSpecificAttributesTransientScope : IScopeSpecificAttributesInterface, IDecorator -{ - public int Number => 23; - - internal ScopeSpecificAttributesTransientScope(IScopeSpecificAttributesInterface _) {} -} - -internal class ScopeSpecificAttributesDep -{ - public int Number { get; } - - internal ScopeSpecificAttributesDep(IScopeSpecificAttributesInterface scopeSpecificAttributesInterface) - { - Number = scopeSpecificAttributesInterface.Number; - } -} - -internal class ScopeSpecificAttributesTransientScopeRoot : ITransientScopeRoot -{ - public ScopeSpecificAttributesDep Dep { get; } - - internal ScopeSpecificAttributesTransientScopeRoot(ScopeSpecificAttributesDep dep) - { - Dep = dep; - } -} - -internal class ScopeSpecificAttributesScopeRoot : IScopeRoot -{ - public ScopeSpecificAttributesDep Dep { get; } - - internal ScopeSpecificAttributesScopeRoot(ScopeSpecificAttributesDep dep) - { - Dep = dep; - } -} - - -[DecoratorSequenceChoice(typeof(IScopeSpecificAttributesInterface), typeof(ScopeSpecificAttributesContai))] -internal partial class ScopeSpecificAttributesContainer : IContainer, IContainer, IContainer -{ - [DecoratorSequenceChoice(typeof(IScopeSpecificAttributesInterface), typeof(ScopeSpecificAttributesTransientScope))] - internal partial class DIE_DefaultTransientScope - { - - } - - [DecoratorSequenceChoice(typeof(IScopeSpecificAttributesInterface), typeof(ScopeSpecificAttributesScope))] - internal partial class DIE_DefaultScope - { - - } -} - -public partial class ScopeSpecificAttributesTests -{ - [Fact] - public void Container() - { - using var container = new ScopeSpecificAttributesContainer(); - var instance = ((IContainer) container).Resolve(); - Assert.Equal(69, instance.Number); - } - [Fact] - public void TransientScope() - { - using var container = new ScopeSpecificAttributesContainer(); - var instance = ((IContainer) container).Resolve(); - Assert.Equal(23, instance.Dep.Number); - } - [Fact] - public void Scope() - { - using var container = new ScopeSpecificAttributesContainer(); - var instance = ((IContainer) container).Resolve(); - Assert.Equal(3, instance.Dep.Number); - } -} \ No newline at end of file diff --git a/Test/ScopeSpecificAttributesTestsWithDecorator.cs b/Test/ScopeSpecificAttributesTestsWithDecorator.cs new file mode 100644 index 00000000..4defe277 --- /dev/null +++ b/Test/ScopeSpecificAttributesTestsWithDecorator.cs @@ -0,0 +1,164 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.ScopeSpecificAttributesTestsWithDecorator; + +internal interface IInterface +{ + int CheckNumber { get; } +} + +internal class Implementation : IInterface +{ + public int CheckNumber => 1; +} + +internal class ContainerDecorator : IInterface, IDecorator +{ + public int CheckNumber => 69; + + internal ContainerDecorator(IInterface _) {} +} + +internal class ScopeDecorator : IInterface, IDecorator +{ + public int CheckNumber => 3; + + internal ScopeDecorator(IInterface _) {} +} + +internal class ScopeSpecificDecorator : IInterface, IDecorator +{ + public int CheckNumber => 13; + + internal ScopeSpecificDecorator(IInterface _) {} +} + +internal class TransientScopeDecorator : IInterface, IDecorator +{ + public int CheckNumber => 23; + + internal TransientScopeDecorator(IInterface _) {} +} + +internal class TransientScopeSpecificDecorator : IInterface, IDecorator +{ + public int CheckNumber => 7; + + internal TransientScopeSpecificDecorator(IInterface _) {} +} + +internal class TransientScopeRoot : ITransientScopeRoot +{ + public IInterface Dep { get; } + + internal TransientScopeRoot(IInterface dep) + { + Dep = dep; + } +} + +internal class TransientScopeRootSpecific : ITransientScopeRoot +{ + public IInterface Dep { get; } + + internal TransientScopeRootSpecific(IInterface dep) + { + Dep = dep; + } +} + +internal class ScopeRootSpecific : IScopeRoot +{ + public IInterface Dep { get; } + + internal ScopeRootSpecific (IInterface dep) + { + Dep = dep; + } +} + +internal class ScopeRoot : IScopeRoot +{ + public IInterface Dep { get; } + + internal ScopeRoot(IInterface dep) + { + Dep = dep; + } +} + + +[DecoratorSequenceChoice(typeof(IInterface), typeof(ContainerDecorator))] +internal partial class Container + : IContainer, + IContainer, + IContainer, + IContainer, + IContainer +{ + [DecoratorSequenceChoice(typeof(IInterface), typeof(TransientScopeDecorator))] + internal partial class DIE_DefaultTransientScope + { + + } + + [DecoratorSequenceChoice(typeof(IInterface), typeof(TransientScopeSpecificDecorator))] + [CustomScopeForRootTypes(typeof(TransientScopeRootSpecific))] + internal partial class DIE_TransientScope_A + { + + } + + [DecoratorSequenceChoice(typeof(IInterface), typeof(ScopeDecorator))] + internal partial class DIE_DefaultScope + { + + } + + [DecoratorSequenceChoice(typeof(IInterface), typeof(ScopeSpecificDecorator))] + [CustomScopeForRootTypes(typeof(ScopeRootSpecific))] + internal partial class DIE_Scope_A + { + + } +} + +public partial class ScopeSpecificAttributesTests +{ + [Fact] + public void Container() + { + using var container = new Container(); + var instance = ((IContainer) container).Resolve(); + Assert.Equal(69, instance.CheckNumber); + } + [Fact] + public void TransientScope() + { + using var container = new Container(); + var instance = ((IContainer) container).Resolve(); + Assert.Equal(23, instance.Dep.CheckNumber); + } + [Fact] + public void TransientScopeSpecific() + { + using var container = new Container(); + var instance = ((IContainer) container).Resolve(); + Assert.Equal(7, instance.Dep.CheckNumber); + } + [Fact] + public void Scope() + { + using var container = new Container(); + var instance = ((IContainer) container).Resolve(); + Assert.Equal(3, instance.Dep.CheckNumber); + } + [Fact] + public void ScopeSpecific() + { + using var container = new Container(); + var instance = ((IContainer) container).Resolve(); + Assert.Equal(13, instance.Dep.CheckNumber); + } +} \ No newline at end of file From 9426e998321b9cdf5f1935cfc81f635115092c1a Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sun, 6 Feb 2022 15:01:12 +0100 Subject: [PATCH 046/162] Implemented Type Initializers --- Main/CodeBuilding/RangeCodeBaseBuilder.cs | 22 ++++- Main/CodeBuilding/ScopeCodeBuilder.cs | 2 +- .../CodeBuilding/TransientScopeCodeBuilder.cs | 2 +- Main/Configuration/Attributes.cs | 16 +++ Main/Configuration/CheckTypeProperties.cs | 8 +- .../Configuration/CurrentlyConsideredTypes.cs | 92 ++++++++++++++---- Main/Configuration/TypesFromAttributes.cs | 44 ++++++++- .../RangeResolutionBaseBuilder.cs | 38 +++++++- Main/ResolutionTreeItem.cs | 30 +++++- Main/WellKnownTypes.cs | 21 +++- Sample/Container.cs | 5 +- Sample/Context.cs | 97 ++----------------- Sample/MarkerInterfaces.cs | 16 ++- Sample/Program.cs | 4 +- Test/AssemblyInfo.cs | 6 +- Test/FactoryTests.cs | 4 +- Test/MarkerInterfaces.cs | 16 ++- ...opeSpecificAttributesTestsWithDecorator.cs | 8 +- ...cAttributesTestsWithImplementationLists.cs | 4 +- ...cificAttributesTestsWithImplementations.cs | 4 +- Test/SyncTypeInitializationTest.cs | 26 +++++ Test/TaskTypeInitializationTests.cs | 31 ++++++ Test/ValueTaskTypeInitializationTests.cs | 31 ++++++ 23 files changed, 383 insertions(+), 144 deletions(-) create mode 100644 Test/SyncTypeInitializationTest.cs create mode 100644 Test/TaskTypeInitializationTests.cs create mode 100644 Test/ValueTaskTypeInitializationTests.cs diff --git a/Main/CodeBuilding/RangeCodeBaseBuilder.cs b/Main/CodeBuilding/RangeCodeBaseBuilder.cs index 18efb88e..52d3e857 100644 --- a/Main/CodeBuilding/RangeCodeBaseBuilder.cs +++ b/Main/CodeBuilding/RangeCodeBaseBuilder.cs @@ -132,12 +132,14 @@ private static StringBuilder GenerateFields( stringBuilder = GenerateFields(stringBuilder, resolutionBase); stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); break; - case ConstructorResolution(var reference, var typeFullName, _, var parameters, var initializedProperties): + case ConstructorResolution(var reference, var typeFullName, _, var parameters, var initializedProperties, var initialization): stringBuilder = parameters.Aggregate(stringBuilder, (builder, tuple) => GenerateFields(builder, tuple.Dependency)); stringBuilder = initializedProperties.Aggregate(stringBuilder, (builder, tuple) => GenerateFields(builder, tuple.Dependency)); stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); + if (initialization is TaskBaseTypeInitializationResolution taskInit) + stringBuilder = stringBuilder.AppendLine($"{taskInit.TaskTypeFullName} {taskInit.TaskReference};"); break; case SyntaxValueTupleResolution(var reference, var typeFullName, var items): stringBuilder = items.Aggregate(stringBuilder, GenerateFields); @@ -176,14 +178,14 @@ private StringBuilder GenerateResolutions( { switch (resolution) { - case TransientScopeRootResolution(var reference, var typeFullName, var transientScopeReference, var transientScopeTypeFullName, var containerInstanceScopeReference, var parameter, var (_, _, _, _, _), var (createFunctionReference, _)): + case TransientScopeRootResolution(var reference, var typeFullName, var transientScopeReference, var transientScopeTypeFullName, var containerInstanceScopeReference, var parameter, var (_, _, _, _, _, _), var (createFunctionReference, _)): stringBuilder = stringBuilder .AppendLine($"{transientScopeReference} = new {transientScopeTypeFullName}({containerInstanceScopeReference});") .AppendLine($"{_rangeResolution.ContainerReference}.{_containerResolution.DisposalHandling.DisposableCollection.Reference}.Add(({WellKnownTypes.Disposable.FullName()}) {transientScopeReference});") .AppendLine($"{reference} = ({typeFullName}) {transientScopeReference}.{createFunctionReference}({string.Join(", ", parameter.Select(p => p.Reference))});"); _isDisposalHandlingRequired = true; break; - case ScopeRootResolution(var reference, var typeFullName, var scopeReference, var scopeTypeFullName, var containerInstanceScopeReference, var transientInstanceScopeReference, var parameter, var (disposableCollectionReference, _, _, _, _), var (createFunctionReference, _)): + case ScopeRootResolution(var reference, var typeFullName, var scopeReference, var scopeTypeFullName, var containerInstanceScopeReference, var transientInstanceScopeReference, var parameter, var (disposableCollectionReference, _, _, _, _, _), var (createFunctionReference, _)): stringBuilder = stringBuilder .AppendLine($"{scopeReference} = new {scopeTypeFullName}({containerInstanceScopeReference}, {transientInstanceScopeReference});") .AppendLine($"{disposableCollectionReference}.Add(({WellKnownTypes.Disposable.FullName()}) {scopeReference});") @@ -201,7 +203,7 @@ private StringBuilder GenerateResolutions( case TransientScopeAsDisposableResolution(var reference, var typeFullName): stringBuilder = stringBuilder.AppendLine($"{reference} = ({typeFullName}) this;"); break; - case ConstructorResolution(var reference, var typeFullName, var disposableCollectionResolution, var parameters, var initializedProperties): + case ConstructorResolution(var reference, var typeFullName, var disposableCollectionResolution, var parameters, var initializedProperties, var initialization): stringBuilder = parameters.Aggregate(stringBuilder, (builder, tuple) => GenerateResolutions(builder, tuple.Dependency)); stringBuilder = initializedProperties.Aggregate(stringBuilder, @@ -219,6 +221,18 @@ private StringBuilder GenerateResolutions( $"{disposableCollectionResolution.Reference}.Add(({WellKnownTypes.Disposable.FullName()}) {reference});"); _isDisposalHandlingRequired = true; } + + if (initialization is {} init) + { + stringBuilder = init switch + { + SyncTypeInitializationResolution (var initInterfaceTypeName, var initMethodName) => + stringBuilder.AppendLine($"(({initInterfaceTypeName}) {reference}).{initMethodName}();"), + TaskBaseTypeInitializationResolution(var initInterfaceTypeName, var initMethodName, _, var taskReference) => + stringBuilder.AppendLine($"{taskReference} = (({initInterfaceTypeName}) {reference}).{initMethodName}();"), + _ => stringBuilder + }; + } break; case SyntaxValueTupleResolution(var reference, _, var items): stringBuilder = items.Aggregate(stringBuilder, GenerateResolutions); diff --git a/Main/CodeBuilding/ScopeCodeBuilder.cs b/Main/CodeBuilding/ScopeCodeBuilder.cs index 9869e5e5..9c77228f 100644 --- a/Main/CodeBuilding/ScopeCodeBuilder.cs +++ b/Main/CodeBuilding/ScopeCodeBuilder.cs @@ -18,7 +18,7 @@ public override StringBuilder Build(StringBuilder stringBuilder) stringBuilder = stringBuilder .AppendLine( - $"internal partial class {_scopeResolution.Name} : {WellKnownTypes.Disposable.FullName()}") + $"private partial class {_scopeResolution.Name} : {WellKnownTypes.Disposable.FullName()}") .AppendLine($"{{") .AppendLine($"private readonly {_containerInfo.FullName} {_scopeResolution.ContainerReference};") .AppendLine($"private readonly {_transientScopeInterfaceResolution.Name} {_scopeResolution.TransientScopeReference};") diff --git a/Main/CodeBuilding/TransientScopeCodeBuilder.cs b/Main/CodeBuilding/TransientScopeCodeBuilder.cs index 2ab14058..646d5905 100644 --- a/Main/CodeBuilding/TransientScopeCodeBuilder.cs +++ b/Main/CodeBuilding/TransientScopeCodeBuilder.cs @@ -18,7 +18,7 @@ public override StringBuilder Build(StringBuilder stringBuilder) stringBuilder = stringBuilder .AppendLine( - $"internal partial class {_transientScopeResolution.Name} : {_containerResolution.TransientScopeInterface.Name}, {WellKnownTypes.Disposable.FullName()}") + $"private partial class {_transientScopeResolution.Name} : {_containerResolution.TransientScopeInterface.Name}, {WellKnownTypes.Disposable.FullName()}") .AppendLine($"{{") .AppendLine($"private readonly {_containerInfo.FullName} {_transientScopeResolution.ContainerReference};") .AppendLine($"internal {_transientScopeResolution.Name}(") diff --git a/Main/Configuration/Attributes.cs b/Main/Configuration/Attributes.cs index 73e22fd7..c9ca59e8 100644 --- a/Main/Configuration/Attributes.cs +++ b/Main/Configuration/Attributes.cs @@ -169,4 +169,20 @@ public CustomScopeForRootTypesAttribute(params Type[] types) { } } + +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] +public class TypeInitializerAttribute : Attribute +{ + public TypeInitializerAttribute(Type type, string methodName) + { + } +} + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class FilterTypeInitializerAttribute : Attribute +{ + public FilterTypeInitializerAttribute(Type type) + { + } +} // ReSharper enable UnusedParameter.Local \ No newline at end of file diff --git a/Main/Configuration/CheckTypeProperties.cs b/Main/Configuration/CheckTypeProperties.cs index df1d3816..02207e41 100644 --- a/Main/Configuration/CheckTypeProperties.cs +++ b/Main/Configuration/CheckTypeProperties.cs @@ -20,7 +20,8 @@ internal interface ICheckTypeProperties bool ShouldBeDecorated(INamedTypeSymbol interfaceType); IReadOnlyList GetSequenceFor(INamedTypeSymbol interfaceType, INamedTypeSymbol implementationType); - IReadOnlyList MapToImplementations(ITypeSymbol typeSymbol); + IReadOnlyList MapToImplementations(ITypeSymbol typeSymbol); + (INamedTypeSymbol Type, IMethodSymbol Initializer)? GetInitializerFor(INamedTypeSymbol implementationType); } internal class CheckTypeProperties : ICheckTypeProperties @@ -82,4 +83,9 @@ public IReadOnlyList MapToImplementations(ITypeSymbol typeSymb _currentlyConsideredTypes.ImplementationMap.TryGetValue(typeSymbol, out var implementations) ? implementations : new List(); + + public (INamedTypeSymbol Type, IMethodSymbol Initializer)? GetInitializerFor(INamedTypeSymbol implementationType) => + _currentlyConsideredTypes.ImplementationToInitializer.TryGetValue(implementationType, out var tuple) + ? tuple + : null; } \ No newline at end of file diff --git a/Main/Configuration/CurrentlyConsideredTypes.cs b/Main/Configuration/CurrentlyConsideredTypes.cs index 8137b90e..197c4ae6 100644 --- a/Main/Configuration/CurrentlyConsideredTypes.cs +++ b/Main/Configuration/CurrentlyConsideredTypes.cs @@ -16,6 +16,7 @@ internal interface ICurrentlyConsideredTypes IReadOnlyDictionary> InterfaceSequenceChoices { get; } IReadOnlyDictionary> ImplementationSequenceChoices { get; } IReadOnlyDictionary> ImplementationMap { get; } + IReadOnlyDictionary ImplementationToInitializer { get; } } internal class CurrentlyConsideredTypes : ICurrentlyConsideredTypes @@ -24,9 +25,9 @@ public CurrentlyConsideredTypes( IReadOnlyList typesFromAttributes, GeneratorExecutionContext context) { - var tempAllImplementations = new List(); + var allImplementations = new List(); - tempAllImplementations.AddRange(context.Compilation.SyntaxTrees + allImplementations.AddRange(context.Compilation.SyntaxTrees .Select(st => (st, context.Compilation.GetSemanticModel(st))) .SelectMany(t => t.st .GetRoot() @@ -39,7 +40,7 @@ public CurrentlyConsideredTypes( foreach (var types in typesFromAttributes) { foreach (var filterType in types.FilterSpy.Concat(types.FilterImplementation)) - tempAllImplementations.Remove(filterType); + allImplementations.Remove(filterType); var spiedImplementations = types .Spy @@ -49,12 +50,10 @@ public CurrentlyConsideredTypes( .Select(ms => ms.ReturnType) .OfType()); - tempAllImplementations.AddRange(types.Implementation + allImplementations.AddRange(types.Implementation .Concat(spiedImplementations)); } - var allImplementations = tempAllImplementations; - TransientTypes = GetSetOfTypesWithProperties(t => t.Transient, t => t.FilterTransient); ContainerInstanceTypes = GetSetOfTypesWithProperties(t => t.ContainerInstance, t => t.FilterContainerInstance); TransientScopeInstanceTypes = GetSetOfTypesWithProperties(t => t.TransientScopeInstance, t => t.FilterTransientScopeInstance); @@ -138,6 +137,61 @@ public CurrentlyConsideredTypes( .GroupBy(t => t.Item1, t => t.Item2) .ToDictionary(g => g.Key, g => (IReadOnlyList) g.Distinct(SymbolEqualityComparer.Default).OfType().ToList()); + var initializers = new Dictionary(SymbolEqualityComparer.Default); + + foreach (var types in typesFromAttributes) + { + var filterInterfaceTypes = types + .FilterTypeInitializers + .Where(t => t.TypeKind is TypeKind.Interface) + .ToImmutableHashSet(SymbolEqualityComparer.Default); + + foreach (var filterConcreteType in allImplementations + .Where(i => AllDerivedTypes(i) + .Select(t => t.OriginalDefinition) + .Any(inter => filterInterfaceTypes.Contains(inter)))) + initializers.Remove(filterConcreteType); + + var filterConcreteTypes = types + .FilterTypeInitializers + .Where(t => t.TypeKind is TypeKind.Class or TypeKind.Struct) + .ToList(); + + foreach (var filterConcreteType in filterConcreteTypes) + initializers.Remove(filterConcreteType); + + var interfaceTypes = types + .TypeInitializers + .Where(ti => ti.Item1.TypeKind is TypeKind.Interface) + .ToList(); + + foreach (var (implementationType, interfaceType, initializerMethod) in allImplementations + .Select(i => + { + foreach (var (interfaceType, initializer) in interfaceTypes) + { + if (AllDerivedTypes(i).Select(d => d.OriginalDefinition).Contains(interfaceType, SymbolEqualityComparer.Default)) + { + return ((INamedTypeSymbol, INamedTypeSymbol, IMethodSymbol)?) (i, interfaceType, initializer); + } + } + + return null; + }) + .OfType<(INamedTypeSymbol, INamedTypeSymbol, IMethodSymbol)>()) + initializers[implementationType] = (interfaceType, initializerMethod); + + var concreteTypes = types + .TypeInitializers + .Where(ti => ti.Item1.TypeKind is TypeKind.Class or TypeKind.Struct) + .ToList(); + + foreach (var (implementation, initializer) in concreteTypes) + initializers[implementation] = (implementation, initializer); + } + + ImplementationToInitializer = initializers; + IImmutableSet GetSetOfTypesWithProperties( Func> propertyGivingTypesGetter, Func> filteredPropertyGivingTypesGetter) @@ -160,22 +214,21 @@ public CurrentlyConsideredTypes( } return ret; + } - - IEnumerable AllDerivedTypes(INamedTypeSymbol type) + IEnumerable AllDerivedTypes(INamedTypeSymbol type) + { + var concreteTypes = new List(); + var temp = type; + while (temp is {}) { - var concreteTypes = new List(); - var temp = type; - while (temp is {}) - { - concreteTypes.Add(temp); - temp = temp.BaseType; - } - return type - .AllInterfaces - .Append(type) - .Concat(concreteTypes); + concreteTypes.Add(temp); + temp = temp.BaseType; } + return type + .AllInterfaces + .Append(type) + .Concat(concreteTypes); } } @@ -191,4 +244,5 @@ IEnumerable AllDerivedTypes(INamedTypeSymbol type) public IReadOnlyDictionary> InterfaceSequenceChoices { get; } public IReadOnlyDictionary> ImplementationSequenceChoices { get; } public IReadOnlyDictionary> ImplementationMap { get; } + public IReadOnlyDictionary ImplementationToInitializer { get; } } \ No newline at end of file diff --git a/Main/Configuration/TypesFromAttributes.cs b/Main/Configuration/TypesFromAttributes.cs index 9ec3fcb3..df777fdb 100644 --- a/Main/Configuration/TypesFromAttributes.cs +++ b/Main/Configuration/TypesFromAttributes.cs @@ -14,6 +14,7 @@ internal interface ITypesFromAttributes IReadOnlyList Composite { get; } IReadOnlyList<(INamedTypeSymbol, IReadOnlyList)> DecoratorSequenceChoices { get; } IReadOnlyList<(INamedTypeSymbol, IMethodSymbol)> ConstructorChoices { get; } + IReadOnlyList<(INamedTypeSymbol, IMethodSymbol)> TypeInitializers { get; } IReadOnlyList FilterSpy { get; } IReadOnlyList FilterImplementation { get; } IReadOnlyList FilterTransient { get; } @@ -26,6 +27,7 @@ internal interface ITypesFromAttributes IReadOnlyList FilterComposite { get; } IReadOnlyList FilterDecoratorSequenceChoices { get; } IReadOnlyList FilterConstructorChoices { get; } + IReadOnlyList FilterTypeInitializers { get; } } internal class TypesFromAttributes : ScopeTypesFromAttributes @@ -106,11 +108,10 @@ internal ScopeTypesFromAttributes( FilterDecoratorSequenceChoices = (AttributeDictionary.TryGetValue(wellKnownTypes.FilterDecoratorSequenceChoiceAttribute, out var group1) ? group1 : Enumerable.Empty()) .Select(ad => { - if (ad.ConstructorArguments.Length < 2) + if (ad.ConstructorArguments.Length != 1) return null; - var decoratedType = ad.ConstructorArguments[0].Value; - return decoratedType as INamedTypeSymbol; + return ad.ConstructorArguments[0].Value as INamedTypeSymbol; }) .OfType() .ToList(); @@ -150,7 +151,40 @@ internal ScopeTypesFromAttributes( FilterConstructorChoices = (AttributeDictionary.TryGetValue(wellKnownTypes.FilterConstructorChoiceAttribute, out var group2) ? group2 : Enumerable.Empty()) .Select(ad => { - if (ad.ConstructorArguments.Length < 2) + if (ad.ConstructorArguments.Length != 1) + return null; + return ad.ConstructorArguments[0].Value as INamedTypeSymbol; + }) + .OfType() + .ToList(); + + TypeInitializers = (AttributeDictionary.TryGetValue(wellKnownTypes.TypeInitializerAttribute, out var group3) ? group3 : Enumerable.Empty()) + .Select(ad => + { + if (ad.ConstructorArguments.Length != 2 + || ad.ConstructorArguments[0].Value is not INamedTypeSymbol type + || ad.ConstructorArguments[1].Value is not string methodName) + return ((INamedTypeSymbol, IMethodSymbol)?) null; + + var initializationMethod = type + .GetMembers(methodName) + .OfType() + .FirstOrDefault(m => m.Parameters.Length == 0); + + if (initializationMethod is { }) + { + return (type, initializationMethod); + } + + return null; + }) + .OfType<(INamedTypeSymbol, IMethodSymbol)>() + .ToList(); + + FilterTypeInitializers = (AttributeDictionary.TryGetValue(wellKnownTypes.FilterTypeInitializerAttribute, out var group4) ? group4 : Enumerable.Empty()) + .Select(ad => + { + if (ad.ConstructorArguments.Length != 1) return null; return ad.ConstructorArguments[0].Value as INamedTypeSymbol; }) @@ -194,6 +228,7 @@ bool CheckValidType(TypedConstant typedConstant, out INamedTypeSymbol type) public IReadOnlyList Composite { get; } public IReadOnlyList<(INamedTypeSymbol, IReadOnlyList)> DecoratorSequenceChoices { get; } public IReadOnlyList<(INamedTypeSymbol, IMethodSymbol)> ConstructorChoices { get; } + public IReadOnlyList<(INamedTypeSymbol, IMethodSymbol)> TypeInitializers { get; } public IReadOnlyList FilterSpy { get; } public IReadOnlyList FilterImplementation { get; } public IReadOnlyList FilterTransient { get; } @@ -206,4 +241,5 @@ bool CheckValidType(TypedConstant typedConstant, out INamedTypeSymbol type) public IReadOnlyList FilterComposite { get; } public IReadOnlyList FilterDecoratorSequenceChoices { get; } public IReadOnlyList FilterConstructorChoices { get; } + public IReadOnlyList FilterTypeInitializers { get; } } \ No newline at end of file diff --git a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs index 2679ff68..4280b914 100644 --- a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs +++ b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs @@ -103,7 +103,8 @@ protected Resolvable SwitchType(SwitchTypeParameter parameter) .TypeArguments .Select((t, i) => ($"item{(i + 1)}", SwitchType(new SwitchTypeParameter(t, currentFuncParameters)))) .ToList(), - Array.Empty<(string Name, Resolvable Dependency)>()); + Array.Empty<(string Name, Resolvable Dependency)>(), + null); } if (type.FullName().StartsWith("(") && type.FullName().EndsWith(")") && type is INamedTypeSymbol syntaxValueTupleType) @@ -169,7 +170,8 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup dependency) ) }), - Array.Empty<(string Name, Resolvable Dependency)>()); + Array.Empty<(string Name, Resolvable Dependency)>(), + null); } if (type.OriginalDefinition.Equals(WellKnownTypes.Enumerable1, SymbolEqualityComparer.Default) @@ -476,7 +478,34 @@ protected Resolvable CreateConstructorResolution(ForConstructorParameter paramet var isTransientScopeRoot = CheckTypeProperties.ShouldBeScopeRoot(implementationType) == ScopeLevel.TransientScope; - + + ITypeInitializationResolution? typeInitializationResolution = null; + + if (CheckTypeProperties.GetInitializerFor(implementationType) is { } tuple) + { + var (initializationInterface, initializationMethod) = tuple; + var initializationTypeFullName = initializationInterface.FullName(); + var initializationMethodName = initializationMethod.Name; + typeInitializationResolution = initializationMethod.ReturnsVoid switch + { + true => new SyncTypeInitializationResolution(initializationTypeFullName, initializationMethodName), + false when initializationMethod.ReturnType.Equals(WellKnownTypes.Task, SymbolEqualityComparer.Default) => + new TaskTypeInitializationResolution( + initializationTypeFullName, + initializationMethodName, + WellKnownTypes.Task.FullName(), + RootReferenceGenerator.Generate(WellKnownTypes.Task)), + false when initializationMethod.ReturnType.Equals(WellKnownTypes.ValueTask, SymbolEqualityComparer.Default) => + new ValueTaskTypeInitializationResolution( + initializationTypeFullName, + initializationMethodName, + WellKnownTypes.ValueTask.FullName(), + RootReferenceGenerator.Generate(WellKnownTypes.ValueTask)), + _ => typeInitializationResolution + }; + } + + return new ConstructorResolution( RootReferenceGenerator.Generate(implementationType), implementationType.FullName(), @@ -494,7 +523,8 @@ protected Resolvable CreateConstructorResolution(ForConstructorParameter paramet .OfType() .Where(p => p.SetMethod?.IsInitOnly ?? false) .Select(p => ProcessChildType(p.Type, p.Name, implementationType, currentParameters)) - .ToList())); + .ToList()), + typeInitializationResolution); (string Name, Resolvable Dependency) ProcessChildType( ITypeSymbol typeSymbol, diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index 74bdab9e..50debc03 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -28,12 +28,37 @@ internal record InterfaceResolution( string TypeFullName, ResolutionTreeItem Dependency) : Resolvable(Reference, TypeFullName); +internal interface ITypeInitializationResolution {} + +internal record SyncTypeInitializationResolution( + string TypeFullName, + string MethodName) : ITypeInitializationResolution; + +internal record TaskBaseTypeInitializationResolution( + string TypeFullName, + string MethodName, + string TaskTypeFullName, + string TaskReference) : ITypeInitializationResolution; + +internal record TaskTypeInitializationResolution( + string TypeFullName, + string MethodName, + string TaskTypeFullName, + string TaskReference) : TaskBaseTypeInitializationResolution(TypeFullName, MethodName, TaskTypeFullName, TaskReference); + +internal record ValueTaskTypeInitializationResolution( + string TypeFullName, + string MethodName, + string TaskTypeFullName, + string TaskReference) : TaskBaseTypeInitializationResolution(TypeFullName, MethodName, TaskTypeFullName, TaskReference); + internal record ConstructorResolution( string Reference, string TypeFullName, DisposableCollectionResolution? DisposableCollectionResolution, IReadOnlyList<(string Name, Resolvable Dependency)> Parameter, - IReadOnlyList<(string Name, Resolvable Dependency)> InitializedProperties) : Resolvable(Reference, TypeFullName); + IReadOnlyList<(string Name, Resolvable Dependency)> InitializedProperties, + ITypeInitializationResolution? Initialization) : Resolvable(Reference, TypeFullName); internal record SyntaxValueTupleResolution( string Reference, @@ -121,7 +146,8 @@ internal record DisposableCollectionResolution( TypeFullName, null, Array.Empty<(string Name, Resolvable Dependency)>(), - Array.Empty<(string Name, Resolvable Dependency)>()); + Array.Empty<(string Name, Resolvable Dependency)>(), + null); internal abstract record RangeResolution( IReadOnlyList RootResolutions, diff --git a/Main/WellKnownTypes.cs b/Main/WellKnownTypes.cs index adbfec6e..e59a2252 100644 --- a/Main/WellKnownTypes.cs +++ b/Main/WellKnownTypes.cs @@ -1,4 +1,5 @@ -using MrMeeseeks.DIE.Configuration; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; namespace MrMeeseeks.DIE; @@ -17,6 +18,7 @@ internal record WellKnownTypes( INamedTypeSymbol CompositeAggregationAttribute, INamedTypeSymbol DecoratorSequenceChoiceAttribute, INamedTypeSymbol ConstructorChoiceAttribute, + INamedTypeSymbol TypeInitializerAttribute, INamedTypeSymbol FilterSpyAggregationAttribute, INamedTypeSymbol FilterSpyConstructorChoiceAggregationAttribute, INamedTypeSymbol FilterImplementationAggregationAttribute, @@ -30,12 +32,14 @@ internal record WellKnownTypes( INamedTypeSymbol FilterCompositeAggregationAttribute, INamedTypeSymbol FilterDecoratorSequenceChoiceAttribute, INamedTypeSymbol FilterConstructorChoiceAttribute, + INamedTypeSymbol FilterTypeInitializerAttribute, INamedTypeSymbol CustomScopeForRootTypesAttribute, INamedTypeSymbol Disposable, INamedTypeSymbol AsyncDisposable, INamedTypeSymbol Lazy1, INamedTypeSymbol ValueTask, INamedTypeSymbol ValueTask1, + INamedTypeSymbol Task, INamedTypeSymbol Task1, INamedTypeSymbol ObjectDisposedException, INamedTypeSymbol Enumerable1, @@ -55,6 +59,7 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK var lazy1 = compilation.GetTypeOrReport("System.Lazy`1"); var valueTask = compilation.GetTypeOrReport("System.Threading.Tasks.ValueTask"); var valueTask1 = compilation.GetTypeOrReport("System.Threading.Tasks.ValueTask`1"); + var task = compilation.GetTypeOrReport("System.Threading.Tasks.Task"); var task1 = compilation.GetTypeOrReport("System.Threading.Tasks.Task`1"); var objectDisposedException = compilation.GetTypeOrReport("System.ObjectDisposedException"); var iEnumerable1 = compilation.GetTypeOrReport("System.Collections.Generic.IEnumerable`1"); @@ -148,7 +153,13 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK .GetTypeByMetadataName(typeof(FilterConstructorChoiceAttribute).FullName ?? ""); var customScopeForRootTypesAttribute = compilation - .GetTypeByMetadataName(typeof(CustomScopeForRootTypesAttribute).FullName ?? ""); + .GetTypeByMetadataName(typeof(CustomScopeForRootTypesAttribute).FullName ?? "");; + + var typeInitializerAttribute = compilation + .GetTypeByMetadataName(typeof(TypeInitializerAttribute).FullName ?? "");; + + var filterTypeInitializerAttribute = compilation + .GetTypeByMetadataName(typeof(FilterTypeInitializerAttribute).FullName ?? ""); if (iContainer is null || spyAggregationAttribute is null @@ -164,6 +175,7 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK || compositeAggregationAttribute is null || decoratorSequenceChoiceAttribute is null || constructorChoiceAttribute is null + || typeInitializerAttribute is null || filterSpyAggregationAttribute is null || filterSpyConstructorChoiceAggregationAttribute is null || filterImplementationAggregationAttribute is null @@ -177,11 +189,13 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK || filterCompositeAggregationAttribute is null || filterDecoratorSequenceChoiceAttribute is null || filterConstructorChoiceAttribute is null + || filterTypeInitializerAttribute is null || customScopeForRootTypesAttribute is null || iDisposable is null || iAsyncDisposable is null || lazy1 is null || valueTask is null + || task is null || valueTask1 is null || task1 is null || objectDisposedException is null @@ -213,6 +227,7 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK CompositeAggregationAttribute: compositeAggregationAttribute, DecoratorSequenceChoiceAttribute: decoratorSequenceChoiceAttribute, ConstructorChoiceAttribute: constructorChoiceAttribute, + TypeInitializerAttribute: typeInitializerAttribute, FilterSpyAggregationAttribute: filterSpyAggregationAttribute, FilterSpyConstructorChoiceAggregationAttribute: filterSpyConstructorChoiceAggregationAttribute, FilterImplementationAggregationAttribute: filterImplementationAggregationAttribute, @@ -226,12 +241,14 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK FilterCompositeAggregationAttribute: filterCompositeAggregationAttribute, FilterDecoratorSequenceChoiceAttribute: filterDecoratorSequenceChoiceAttribute, FilterConstructorChoiceAttribute: filterConstructorChoiceAttribute, + FilterTypeInitializerAttribute: filterTypeInitializerAttribute, CustomScopeForRootTypesAttribute: customScopeForRootTypesAttribute, Disposable: iDisposable, AsyncDisposable: iAsyncDisposable, Lazy1: lazy1, ValueTask: valueTask, ValueTask1: valueTask1, + Task: task, Task1: task1, ObjectDisposedException: objectDisposedException, Enumerable1: iEnumerable1, diff --git a/Sample/Container.cs b/Sample/Container.cs index 7c7128b5..b5ebb3b9 100644 --- a/Sample/Container.cs +++ b/Sample/Container.cs @@ -8,4 +8,7 @@ [assembly:ScopeRootAggregation(typeof(IScopeRoot))] [assembly:TransientAggregation(typeof(ITransient))] [assembly:DecoratorAggregation(typeof(IDecorator<>))] -[assembly:CompositeAggregation(typeof(IComposite<>))] \ No newline at end of file +[assembly:CompositeAggregation(typeof(IComposite<>))] +[assembly:TypeInitializer(typeof(ITypeInitializer), nameof(ITypeInitializer.Initialize))] +[assembly:TypeInitializer(typeof(ITaskTypeInitializer), nameof(ITaskTypeInitializer.InitializeAsync))] +[assembly:TypeInitializer(typeof(IValueTaskTypeInitializer), nameof(IValueTaskTypeInitializer.InitializeAsync))] \ No newline at end of file diff --git a/Sample/Context.cs b/Sample/Context.cs index f398fb6b..ae6c5933 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -1,99 +1,18 @@ -using MrMeeseeks.DIE.Configuration; -using MrMeeseeks.DIE.Sample; +using System.Threading.Tasks; -namespace MrMeeseeks.DIE.Test.ScopeSpecificAttributesTestsWithDecorator; - -internal interface IInterface -{ - int CheckNumber { get; } -} - -internal class Implementation : IInterface -{ - public int CheckNumber => 1; -} - -internal class ContainerDecorator : IInterface, IDecorator -{ - public int CheckNumber => 69; - - internal ContainerDecorator(IInterface _) {} -} - -internal class ScopeDecorator : IInterface, IDecorator +namespace MrMeeseeks.DIE.Sample; +internal class Dependency : ITaskTypeInitializer { - public int CheckNumber => 3; + public bool IsInitialized { get; private set; } - internal ScopeDecorator(IInterface _) {} -} - -internal class TransientScopeDecorator : IInterface, IDecorator -{ - public int CheckNumber => 23; - - internal TransientScopeDecorator(IInterface _) {} -} - -internal class TransientScopeSpecificDecorator : IInterface, IDecorator -{ - public int CheckNumber => 7; - - internal TransientScopeSpecificDecorator(IInterface _) {} -} - -internal class TransientScopeRoot : ITransientScopeRoot -{ - public IInterface Dep { get; } - - internal TransientScopeRoot(IInterface dep) + Task ITaskTypeInitializer.InitializeAsync() { - Dep = dep; + IsInitialized = true; + return Task.CompletedTask; } } -internal class TransientScopeRootSpecific : ITransientScopeRoot -{ - public IInterface Dep { get; } - - internal TransientScopeRootSpecific(IInterface dep) - { - Dep = dep; - } -} - -internal class ScopeRoot : IScopeRoot -{ - public IInterface Dep { get; } - - internal ScopeRoot(IInterface dep) - { - Dep = dep; - } -} - - -[DecoratorSequenceChoice(typeof(IInterface), typeof(ContainerDecorator))] internal partial class Container - : IContainer, - IContainer, - IContainer, - IContainer + : IContainer { - [DecoratorSequenceChoice(typeof(IInterface), typeof(TransientScopeDecorator))] - internal partial class DIE_DefaultTransientScope - { - - } - [DecoratorSequenceChoice(typeof(IInterface), typeof(TransientScopeSpecificDecorator))] - [CustomScopeForRootTypes(typeof(TransientScopeRootSpecific))] - internal partial class DIE_TransientScope_A - { - - } - - [DecoratorSequenceChoice(typeof(IInterface), typeof(ScopeDecorator))] - internal partial class DIE_DefaultScope - { - - } } \ No newline at end of file diff --git a/Sample/MarkerInterfaces.cs b/Sample/MarkerInterfaces.cs index 558e0576..870e169d 100644 --- a/Sample/MarkerInterfaces.cs +++ b/Sample/MarkerInterfaces.cs @@ -1,3 +1,5 @@ +using System.Threading.Tasks; + namespace MrMeeseeks.DIE.Sample; public interface IContainerInstance { } @@ -7,4 +9,16 @@ public interface ITransientScopeRoot { } public interface IScopeRoot { } public interface ITransient { } public interface IDecorator { } -public interface IComposite { } \ No newline at end of file +public interface IComposite { } +public interface ITypeInitializer +{ + void Initialize(); +} +public interface ITaskTypeInitializer +{ + Task InitializeAsync(); +} +public interface IValueTaskTypeInitializer +{ + ValueTask InitializeAsync(); +} \ No newline at end of file diff --git a/Sample/Program.cs b/Sample/Program.cs index e040e7a7..101a171b 100644 --- a/Sample/Program.cs +++ b/Sample/Program.cs @@ -1,7 +1,7 @@ using System; using MrMeeseeks.DIE; -using MrMeeseeks.DIE.Test.ScopeSpecificAttributesTestsWithDecorator; +using MrMeeseeks.DIE.Sample; Console.WriteLine("Hello, world!"); var container = new Container(); -Console.WriteLine(((IContainer) container).Resolve()); \ No newline at end of file +Console.WriteLine(((IContainer) container).Resolve()); \ No newline at end of file diff --git a/Test/AssemblyInfo.cs b/Test/AssemblyInfo.cs index e09eda1f..dbd40887 100644 --- a/Test/AssemblyInfo.cs +++ b/Test/AssemblyInfo.cs @@ -1,4 +1,3 @@ -using MrMeeseeks.DIE; using MrMeeseeks.DIE.Configuration; using MrMeeseeks.DIE.Test; @@ -9,4 +8,7 @@ [assembly:ScopeRootAggregation(typeof(IScopeRoot))] [assembly:TransientAggregation(typeof(ITransient))] [assembly:DecoratorAggregation(typeof(IDecorator<>))] -[assembly:CompositeAggregation(typeof(IComposite<>))] \ No newline at end of file +[assembly:CompositeAggregation(typeof(IComposite<>))] +[assembly:TypeInitializer(typeof(ITypeInitializer), nameof(ITypeInitializer.Initialize))] +[assembly:TypeInitializer(typeof(ITaskTypeInitializer), nameof(ITaskTypeInitializer.InitializeAsync))] +[assembly:TypeInitializer(typeof(IValueTaskTypeInitializer), nameof(IValueTaskTypeInitializer.InitializeAsync))] \ No newline at end of file diff --git a/Test/FactoryTests.cs b/Test/FactoryTests.cs index 4f7771d5..f92757ce 100644 --- a/Test/FactoryTests.cs +++ b/Test/FactoryTests.cs @@ -30,12 +30,12 @@ internal partial class FactoryContainer : IContainer, IContainer DIE_Path = diePath; - internal partial class DIE_DefaultTransientScope + partial class DIE_DefaultTransientScope { private int DIE_Num => 69; } - internal partial class DIE_DefaultScope + partial class DIE_DefaultScope { private string DIE_Yeah => "Yeah"; } diff --git a/Test/MarkerInterfaces.cs b/Test/MarkerInterfaces.cs index f62270ec..bbcc48cd 100644 --- a/Test/MarkerInterfaces.cs +++ b/Test/MarkerInterfaces.cs @@ -1,3 +1,5 @@ +using System.Threading.Tasks; + namespace MrMeeseeks.DIE.Test; public interface IContainerInstance { } @@ -7,4 +9,16 @@ public interface ITransientScopeRoot { } public interface IScopeRoot { } public interface ITransient { } public interface IDecorator { } -public interface IComposite { } \ No newline at end of file +public interface IComposite { } +public interface ITypeInitializer +{ + void Initialize(); +} +public interface ITaskTypeInitializer +{ + Task InitializeAsync(); +} +public interface IValueTaskTypeInitializer +{ + ValueTask InitializeAsync(); +} \ No newline at end of file diff --git a/Test/ScopeSpecificAttributesTestsWithDecorator.cs b/Test/ScopeSpecificAttributesTestsWithDecorator.cs index 4defe277..50a5879b 100644 --- a/Test/ScopeSpecificAttributesTestsWithDecorator.cs +++ b/Test/ScopeSpecificAttributesTestsWithDecorator.cs @@ -98,27 +98,27 @@ internal partial class Container IContainer { [DecoratorSequenceChoice(typeof(IInterface), typeof(TransientScopeDecorator))] - internal partial class DIE_DefaultTransientScope + partial class DIE_DefaultTransientScope { } [DecoratorSequenceChoice(typeof(IInterface), typeof(TransientScopeSpecificDecorator))] [CustomScopeForRootTypes(typeof(TransientScopeRootSpecific))] - internal partial class DIE_TransientScope_A + partial class DIE_TransientScope_A { } [DecoratorSequenceChoice(typeof(IInterface), typeof(ScopeDecorator))] - internal partial class DIE_DefaultScope + partial class DIE_DefaultScope { } [DecoratorSequenceChoice(typeof(IInterface), typeof(ScopeSpecificDecorator))] [CustomScopeForRootTypes(typeof(ScopeRootSpecific))] - internal partial class DIE_Scope_A + partial class DIE_Scope_A { } diff --git a/Test/ScopeSpecificAttributesTestsWithImplementationLists.cs b/Test/ScopeSpecificAttributesTestsWithImplementationLists.cs index 38a7ac95..1f659a0e 100644 --- a/Test/ScopeSpecificAttributesTestsWithImplementationLists.cs +++ b/Test/ScopeSpecificAttributesTestsWithImplementationLists.cs @@ -30,14 +30,14 @@ internal partial class Container : IContainer>, ICont { [FilterImplementationAggregation(typeof(DependencyContainer))] [FilterImplementationAggregation(typeof(DependencyScope))] - internal partial class DIE_DefaultTransientScope + partial class DIE_DefaultTransientScope { } [FilterImplementationAggregation(typeof(DependencyContainer))] [FilterImplementationAggregation(typeof(DependencyTransientScope))] - internal partial class DIE_DefaultScope + partial class DIE_DefaultScope { } diff --git a/Test/ScopeSpecificAttributesTestsWithImplementations.cs b/Test/ScopeSpecificAttributesTestsWithImplementations.cs index d4817bb6..fda7edf3 100644 --- a/Test/ScopeSpecificAttributesTestsWithImplementations.cs +++ b/Test/ScopeSpecificAttributesTestsWithImplementations.cs @@ -31,14 +31,14 @@ internal partial class Container : IContainer, IContainer IsInitialized = true; +} + +internal partial class Container + : IContainer +{ +} + +public partial class Tests +{ + [Fact] + public void Test() + { + using var container = new Container(); + var instance = ((IContainer) container).Resolve(); + Assert.True(instance.IsInitialized); + } +} \ No newline at end of file diff --git a/Test/TaskTypeInitializationTests.cs b/Test/TaskTypeInitializationTests.cs new file mode 100644 index 00000000..f8100410 --- /dev/null +++ b/Test/TaskTypeInitializationTests.cs @@ -0,0 +1,31 @@ +using System; +using System.Threading.Tasks; +using Xunit; + +namespace MrMeeseeks.DIE.Test.TaskTypeInitializationTests; + +internal class Dependency : ITaskTypeInitializer +{ + public bool IsInitialized { get; private set; } + + async Task ITaskTypeInitializer.InitializeAsync() + { + await Task.Delay(TimeSpan.FromMilliseconds(500)).ConfigureAwait(false); + IsInitialized = true; + } +} + +internal partial class Container : IContainer +{ +} + +public partial class Tests +{ + [Fact] + public void Test() + { + using var container = new Container(); + var instance = ((IContainer) container).Resolve(); + Assert.True(instance.IsInitialized); + } +} \ No newline at end of file diff --git a/Test/ValueTaskTypeInitializationTests.cs b/Test/ValueTaskTypeInitializationTests.cs new file mode 100644 index 00000000..ed40f8b2 --- /dev/null +++ b/Test/ValueTaskTypeInitializationTests.cs @@ -0,0 +1,31 @@ +using System; +using System.Threading.Tasks; +using Xunit; + +namespace MrMeeseeks.DIE.Test.ValueTaskTypeInitializationTests; + +internal class Dependency : IValueTaskTypeInitializer +{ + public bool IsInitialized { get; private set; } + + async ValueTask IValueTaskTypeInitializer.InitializeAsync() + { + await Task.Delay(TimeSpan.FromMilliseconds(500)).ConfigureAwait(false); + IsInitialized = true; + } +} + +internal partial class Container : IContainer +{ +} + +public partial class Tests +{ + [Fact] + public void Test() + { + using var container = new Container(); + var instance = ((IContainer) container).Resolve(); + Assert.True(instance.IsInitialized); + } +} \ No newline at end of file From f17e29d9c4ffeb1c3b0d7140e8e0b91088655a8b Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sun, 13 Feb 2022 19:15:48 +0100 Subject: [PATCH 047/162] Implemented async support with restriction to wrapping dependencies into Tasks or ValueTasks --- Main/CodeBuilding/RangeCodeBaseBuilder.cs | 100 ++- .../ContainerResolutionBuilder.cs | 26 +- .../FunctionResolutionBuilder.cs | 767 ++++++++++++++++++ .../RangeResolutionBaseBuilder.cs | 581 ++----------- Main/ResolutionBuilding/ResolutionDtos.cs | 12 +- .../ScopeResolutionBuilder.cs | 30 +- .../TransientScopeResolutionBuilder.cs | 28 +- Main/ResolutionTreeItem.cs | 42 +- Main/SourceGenerator.cs | 12 +- Main/WellKnownTypes.cs | 203 ++--- Sample/Context.cs | 47 +- Sample/Program.cs | 16 +- Sample/Sample.csproj | 2 +- .../WrappedDependency/DecorationChaining.cs | 64 ++ Test/Async/WrappedDependency/Func.cs | 32 + Test/Async/WrappedDependency/Lazy.cs | 32 + Test/Async/WrappedDependency/SyncToTask.cs | 29 + .../WrappedDependency/SyncToValueTask.cs | 29 + .../Async/WrappedDependency/TaskCollection.cs | 65 ++ .../WrappedDependency/TaskComposition.cs | 84 ++ .../WrappedDependency/TaskToTask.cs} | 10 +- .../WrappedDependency/TaskToValueTask.cs | 31 + .../WrappedDependency/ValueTaskCollection.cs | 64 ++ .../WrappedDependency/ValueTaskComposition.cs | 84 ++ .../WrappedDependency/ValueTaskToTask.cs} | 10 +- .../WrappedDependency/ValueTaskToValueTask.cs | 31 + 26 files changed, 1738 insertions(+), 693 deletions(-) create mode 100644 Main/ResolutionBuilding/FunctionResolutionBuilder.cs create mode 100644 Test/Async/WrappedDependency/DecorationChaining.cs create mode 100644 Test/Async/WrappedDependency/Func.cs create mode 100644 Test/Async/WrappedDependency/Lazy.cs create mode 100644 Test/Async/WrappedDependency/SyncToTask.cs create mode 100644 Test/Async/WrappedDependency/SyncToValueTask.cs create mode 100644 Test/Async/WrappedDependency/TaskCollection.cs create mode 100644 Test/Async/WrappedDependency/TaskComposition.cs rename Test/{TaskTypeInitializationTests.cs => Async/WrappedDependency/TaskToTask.cs} (62%) create mode 100644 Test/Async/WrappedDependency/TaskToValueTask.cs create mode 100644 Test/Async/WrappedDependency/ValueTaskCollection.cs create mode 100644 Test/Async/WrappedDependency/ValueTaskComposition.cs rename Test/{ValueTaskTypeInitializationTests.cs => Async/WrappedDependency/ValueTaskToTask.cs} (62%) create mode 100644 Test/Async/WrappedDependency/ValueTaskToValueTask.cs diff --git a/Main/CodeBuilding/RangeCodeBaseBuilder.cs b/Main/CodeBuilding/RangeCodeBaseBuilder.cs index 52d3e857..42ccd7e2 100644 --- a/Main/CodeBuilding/RangeCodeBaseBuilder.cs +++ b/Main/CodeBuilding/RangeCodeBaseBuilder.cs @@ -115,6 +115,36 @@ private static StringBuilder GenerateFields( { switch (resolution) { + case TaskFromTaskResolution(var wrappedResolvable, _, var taskReference, var taskFullName): + stringBuilder = GenerateFields(stringBuilder, wrappedResolvable); + stringBuilder = stringBuilder + .AppendLine($"{taskFullName} {taskReference};"); + break; + case TaskFromValueTaskResolution(var wrappedResolvable, _, var taskReference, var taskFullName): + stringBuilder = GenerateFields(stringBuilder, wrappedResolvable); + stringBuilder = stringBuilder + .AppendLine($"{taskFullName} {taskReference};"); + break; + case TaskFromSyncResolution(var wrappedResolvable, var taskReference, var taskFullName): + stringBuilder = GenerateFields(stringBuilder, wrappedResolvable); + stringBuilder = stringBuilder + .AppendLine($"{taskFullName} {taskReference};"); + break; + case ValueTaskFromTaskResolution(var wrappedResolvable, _, var valueTaskReference, var valueTaskFullName): + stringBuilder = GenerateFields(stringBuilder, wrappedResolvable); + stringBuilder = stringBuilder + .AppendLine($"{valueTaskFullName} {valueTaskReference};"); + break; + case ValueTaskFromValueTaskResolution(var wrappedResolvable, _, var valueTaskReference, var valueTaskFullName): + stringBuilder = GenerateFields(stringBuilder, wrappedResolvable); + stringBuilder = stringBuilder + .AppendLine($"{valueTaskFullName} {valueTaskReference};"); + break; + case ValueTaskFromSyncResolution(var wrappedResolvable, var valueTaskReference, var valueTaskFullName): + stringBuilder = GenerateFields(stringBuilder, wrappedResolvable); + stringBuilder = stringBuilder + .AppendLine($"{valueTaskFullName} {valueTaskReference};"); + break; case TransientScopeRootResolution(var reference, var typeFullName, var transientScopeReference, var transientScopeTypeFullName, _, _, _, _): stringBuilder = stringBuilder .AppendLine($"{transientScopeTypeFullName} {transientScopeReference};") @@ -138,7 +168,7 @@ private static StringBuilder GenerateFields( stringBuilder = initializedProperties.Aggregate(stringBuilder, (builder, tuple) => GenerateFields(builder, tuple.Dependency)); stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); - if (initialization is TaskBaseTypeInitializationResolution taskInit) + if (initialization is TaskBaseTypeInitializationResolution { Await: false } taskInit) stringBuilder = stringBuilder.AppendLine($"{taskInit.TaskTypeFullName} {taskInit.TaskReference};"); break; case SyntaxValueTupleResolution(var reference, var typeFullName, var items): @@ -178,6 +208,70 @@ private StringBuilder GenerateResolutions( { switch (resolution) { + case TaskFromTaskResolution(var wrappedResolvable, var initialization, var taskReference, _): + stringBuilder = GenerateResolutions(stringBuilder, wrappedResolvable); + stringBuilder = stringBuilder + .AppendLine($"{taskReference} = {initialization.TaskReference}.ContinueWith(t =>") + .AppendLine("{") + .AppendLine("if (t.IsCompletedSuccessfully)") + .AppendLine($"return {wrappedResolvable.Reference};") + .AppendLine("if (t.IsFaulted && t.Exception is { })") + .AppendLine("throw t.Exception;") + .AppendLine("if (t.IsCanceled)") + .AppendLine($"throw new {WellKnownTypes.TaskCanceledException.FullName()}(t);") + .AppendLine($"throw new {WellKnownTypes.Exception.FullName()}(\"Something unexpected.\");") + .AppendLine("});"); + break; + case TaskFromValueTaskResolution(var wrappedResolvable, var initialization, var taskReference, _): + stringBuilder = GenerateResolutions(stringBuilder, wrappedResolvable); + stringBuilder = stringBuilder + .AppendLine($"{taskReference} = {initialization.TaskReference}.AsTask().ContinueWith(t =>") + .AppendLine("{") + .AppendLine("if (t.IsCompletedSuccessfully)") + .AppendLine($"return {wrappedResolvable.Reference};") + .AppendLine("if (t.IsFaulted && t.Exception is { })") + .AppendLine("throw t.Exception;") + .AppendLine("if (t.IsCanceled)") + .AppendLine($"throw new {WellKnownTypes.TaskCanceledException.FullName()}(t);") + .AppendLine($"throw new {WellKnownTypes.Exception.FullName()}(\"Something unexpected.\");") + .AppendLine("});"); + break; + case TaskFromSyncResolution(var wrappedResolvable, var taskReference, _): + stringBuilder = GenerateResolutions(stringBuilder, wrappedResolvable); + stringBuilder = stringBuilder.AppendLine($"{taskReference} = {WellKnownTypes.Task.FullName()}.FromResult({wrappedResolvable.Reference});"); + break; + case ValueTaskFromTaskResolution(var wrappedResolvable, var initialization, var valueTaskReference, var valueTaskFullName): + stringBuilder = GenerateResolutions(stringBuilder, wrappedResolvable); + stringBuilder = stringBuilder + .AppendLine($"{valueTaskReference} = new {valueTaskFullName}({initialization.TaskReference}.ContinueWith(t =>") + .AppendLine("{") + .AppendLine("if (t.IsCompletedSuccessfully)") + .AppendLine($"return {wrappedResolvable.Reference};") + .AppendLine("if (t.IsFaulted && t.Exception is { })") + .AppendLine("throw t.Exception;") + .AppendLine("if (t.IsCanceled)") + .AppendLine($"throw new {WellKnownTypes.TaskCanceledException.FullName()}(t);") + .AppendLine($"throw new {WellKnownTypes.Exception.FullName()}(\"Something unexpected.\");") + .AppendLine("}));"); + break; + case ValueTaskFromValueTaskResolution(var wrappedResolvable, var initialization, var valueTaskReference, var valueTaskFullName): + stringBuilder = GenerateResolutions(stringBuilder, wrappedResolvable); + stringBuilder = stringBuilder + .AppendLine($"{valueTaskReference} = new {valueTaskFullName}({initialization.TaskReference}.AsTask().ContinueWith(t =>") + .AppendLine("{") + .AppendLine("if (t.IsCompletedSuccessfully)") + .AppendLine($"return {wrappedResolvable.Reference};") + .AppendLine("if (t.IsFaulted && t.Exception is { })") + .AppendLine("throw t.Exception;") + .AppendLine("if (t.IsCanceled)") + .AppendLine($"throw new {WellKnownTypes.TaskCanceledException.FullName()}(t);") + .AppendLine($"throw new {WellKnownTypes.Exception.FullName()}(\"Something unexpected.\");") + .AppendLine("}));"); + break; + case ValueTaskFromSyncResolution(var wrappedResolvable, var valueTaskReference, _): + stringBuilder = GenerateResolutions(stringBuilder, wrappedResolvable); + stringBuilder = stringBuilder.AppendLine($"{valueTaskReference} = {WellKnownTypes.ValueTask.FullName()}.FromResult({wrappedResolvable.Reference});"); + break; case TransientScopeRootResolution(var reference, var typeFullName, var transientScopeReference, var transientScopeTypeFullName, var containerInstanceScopeReference, var parameter, var (_, _, _, _, _, _), var (createFunctionReference, _)): stringBuilder = stringBuilder .AppendLine($"{transientScopeReference} = new {transientScopeTypeFullName}({containerInstanceScopeReference});") @@ -228,7 +322,9 @@ private StringBuilder GenerateResolutions( { SyncTypeInitializationResolution (var initInterfaceTypeName, var initMethodName) => stringBuilder.AppendLine($"(({initInterfaceTypeName}) {reference}).{initMethodName}();"), - TaskBaseTypeInitializationResolution(var initInterfaceTypeName, var initMethodName, _, var taskReference) => + TaskBaseTypeInitializationResolution { Await: true, TypeFullName: {} initInterfaceTypeName, MethodName: {} initMethodName} => + stringBuilder.AppendLine($"await (({initInterfaceTypeName}) {reference}).{initMethodName}();"), + TaskBaseTypeInitializationResolution { Await: false, TypeFullName: {} initInterfaceTypeName, MethodName: {} initMethodName, TaskReference: {} taskReference} => stringBuilder.AppendLine($"{taskReference} = (({initInterfaceTypeName}) {reference}).{initMethodName}();"), _ => stringBuilder }; diff --git a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs index 52f3b286..74577a2f 100644 --- a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs @@ -2,7 +2,7 @@ namespace MrMeeseeks.DIE.ResolutionBuilding; -internal interface IContainerResolutionBuilder +internal interface IContainerResolutionBuilder : IRangeResolutionBaseBuilder { void AddCreateResolveFunctions(IReadOnlyList rootTypes); @@ -17,6 +17,7 @@ internal class ContainerResolutionBuilder : RangeResolutionBaseBuilder, IContain { private readonly IContainerInfo _containerInfo; private readonly ITransientScopeInterfaceResolutionBuilder _transientScopeInterfaceResolutionBuilder; + private readonly Func _functionResolutionBuilderFactory; private readonly List _rootResolutions = new (); private readonly string _transientScopeAdapterReference; @@ -31,17 +32,20 @@ internal ContainerResolutionBuilder( IReferenceGeneratorFactory referenceGeneratorFactory, ICheckTypeProperties checkTypeProperties, WellKnownTypes wellKnownTypes, - Func scopeManagerFactory, - IUserProvidedScopeElements userProvidedScopeElements) + Func scopeManagerFactory, + Func functionResolutionBuilderFactory, + IUserProvidedScopeElements userProvidedScopeElement) : base( containerInfo.Name, - wellKnownTypes, - referenceGeneratorFactory, checkTypeProperties, - userProvidedScopeElements) + userProvidedScopeElement, + wellKnownTypes, + referenceGeneratorFactory, + functionResolutionBuilderFactory) { _containerInfo = containerInfo; _transientScopeInterfaceResolutionBuilder = transientScopeInterfaceResolutionBuilder; + _functionResolutionBuilderFactory = functionResolutionBuilderFactory; _scopeManager = scopeManagerFactory(this, transientScopeInterfaceResolutionBuilder); transientScopeInterfaceResolutionBuilder.AddImplementation(this); @@ -55,7 +59,7 @@ public void AddCreateResolveFunctions(IReadOnlyList rootTypes) nameof(IContainer.Resolve), typeSymbol.FullName(), "", - SwitchType(new SwitchTypeParameter( + _functionResolutionBuilderFactory(this).ResolveFunction(new SwitchTypeParameter( typeSymbol, Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>())), Array.Empty(), @@ -70,13 +74,13 @@ public RangedInstanceReferenceResolution CreateContainerInstanceReferenceResolut "Container", containerReference); - protected override RangedInstanceReferenceResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter) => + public override RangedInstanceReferenceResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter) => CreateContainerInstanceReferenceResolution(parameter, "this"); - protected override RangedInstanceReferenceResolution CreateTransientScopeInstanceReferenceResolution(ForConstructorParameter parameter) => + public override RangedInstanceReferenceResolution CreateTransientScopeInstanceReferenceResolution(ForConstructorParameter parameter) => _transientScopeInterfaceResolutionBuilder.CreateTransientScopeInstanceReferenceResolution(parameter, "this"); - protected override TransientScopeRootResolution CreateTransientScopeRootResolution(IScopeRootParameter parameter, INamedTypeSymbol rootType, + public override TransientScopeRootResolution CreateTransientScopeRootResolution(IScopeRootParameter parameter, INamedTypeSymbol rootType, DisposableCollectionResolution disposableCollectionResolution, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) => _scopeManager .GetTransientScopeBuilder(rootType) @@ -87,7 +91,7 @@ protected override TransientScopeRootResolution CreateTransientScopeRootResoluti disposableCollectionResolution, currentParameters); - protected override ScopeRootResolution CreateScopeRootResolution( + public override ScopeRootResolution CreateScopeRootResolution( IScopeRootParameter parameter, INamedTypeSymbol rootType, DisposableCollectionResolution disposableCollectionResolution, diff --git a/Main/ResolutionBuilding/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/FunctionResolutionBuilder.cs new file mode 100644 index 00000000..54997297 --- /dev/null +++ b/Main/ResolutionBuilding/FunctionResolutionBuilder.cs @@ -0,0 +1,767 @@ +using MrMeeseeks.DIE.Configuration; + +namespace MrMeeseeks.DIE.ResolutionBuilding; + +internal interface IFunctionResolutionBuilder +{ + Resolvable ResolveFunction(SwitchTypeParameter parameter); + Resolvable RangedFunction(ForConstructorParameter parameter); + Resolvable ScopeRootFunction(CreateInterfaceParameter parameter); + Resolvable ScopeRootFunction(SwitchImplementationParameter parameter); + Resolvable ScopeRootFunction(SwitchInterfaceAfterScopeRootParameter parameter); +} + +internal class FunctionResolutionBuilder : IFunctionResolutionBuilder +{ + private readonly IRangeResolutionBaseBuilder _rangeResolutionBaseBuilder; + private readonly WellKnownTypes _wellKnownTypes; + private readonly ICheckTypeProperties _checkTypeProperties; + + private readonly IReferenceGenerator _rootReferenceGenerator; + + private readonly DisposableCollectionResolution _disposableCollectionResolution; + private readonly IUserProvidedScopeElements _userProvidedScopeElements; + + internal FunctionResolutionBuilder( + // parameters + IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, + + // dependencies + WellKnownTypes wellKnownTypes, + IReferenceGeneratorFactory referenceGeneratorFactory) + { + _rangeResolutionBaseBuilder = rangeResolutionBaseBuilder; + _wellKnownTypes = wellKnownTypes; + _checkTypeProperties = rangeResolutionBaseBuilder.CheckTypeProperties; + _userProvidedScopeElements = rangeResolutionBaseBuilder.UserProvidedScopeElements; + + _rootReferenceGenerator = referenceGeneratorFactory.Create(); + _disposableCollectionResolution = _rangeResolutionBaseBuilder.DisposableCollectionResolution; + } + + private (Resolvable, ConstructorResolution?) SwitchType(SwitchTypeParameter parameter) + { + var (type, currentFuncParameters) = parameter; + if (currentFuncParameters.FirstOrDefault(t => SymbolEqualityComparer.Default.Equals(t.Type.OriginalDefinition, type.OriginalDefinition)) is { Type: not null, Resolution: not null } funcParameter) + return (funcParameter.Resolution, null); + + if (_userProvidedScopeElements.GetInstanceFor(type) is { } instance) + return ( + new FieldResolution( + _rootReferenceGenerator.Generate(instance.Type), + instance.Type.FullName(), + instance.Name), + null); + + if (_userProvidedScopeElements.GetPropertyFor(type) is { } property) + return ( + new FieldResolution( + _rootReferenceGenerator.Generate(property.Type), + property.Type.FullName(), + property.Name), + null); + + if (_userProvidedScopeElements.GetFactoryFor(type) is { } factory) + return ( + new FactoryResolution( + _rootReferenceGenerator.Generate(factory.ReturnType), + factory.ReturnType.FullName(), + factory.Name, + factory + .Parameters + .Select(p => (p.Name, SwitchType(new SwitchTypeParameter(p.Type, currentFuncParameters)).Item1)) + .ToList()), + null); + + if (type.OriginalDefinition.Equals(_wellKnownTypes.Task1, SymbolEqualityComparer.Default) + && type is INamedTypeSymbol task) + return SwitchTask(new SwitchTaskParameter(SwitchType(new SwitchTypeParameter(task.TypeArguments[0], currentFuncParameters)))); + + if (type.OriginalDefinition.Equals(_wellKnownTypes.ValueTask1, SymbolEqualityComparer.Default) + && type is INamedTypeSymbol valueTask) + return SwitchValueTask(new SwitchValueTaskParameter(SwitchType(new SwitchTypeParameter(valueTask.TypeArguments[0], currentFuncParameters)))); + + if (type.FullName().StartsWith("global::System.ValueTuple<") && type is INamedTypeSymbol valueTupleType) + { + var constructorResolution = new ConstructorResolution( + _rootReferenceGenerator.Generate(valueTupleType), + valueTupleType.FullName(), + ImplementsIDisposable(valueTupleType, _wellKnownTypes, _disposableCollectionResolution, _checkTypeProperties), + valueTupleType + .TypeArguments + .Select((t, i) => ($"item{(i + 1)}", SwitchType(new SwitchTypeParameter(t, currentFuncParameters)).Item1)) + .ToList(), + Array.Empty<(string Name, Resolvable Dependency)>(), + null); + return (constructorResolution, constructorResolution); + } + + if (type.FullName().StartsWith("(") && type.FullName().EndsWith(")") && type is INamedTypeSymbol syntaxValueTupleType) + { + var itemTypes = GetTypeArguments(syntaxValueTupleType).ToList(); + + return (new SyntaxValueTupleResolution( + _rootReferenceGenerator.Generate("syntaxValueTuple"), + syntaxValueTupleType.FullName(), + itemTypes + .Select(t => SwitchType(new SwitchTypeParameter(t, currentFuncParameters)).Item1) + .ToList()), + null); + + IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTupleType) + { + foreach (var typeArgument in currentSyntaxValueTupleType.TypeArguments) + { + if (typeArgument.FullName().StartsWith("(") && typeArgument.FullName().EndsWith(")") && + typeArgument is INamedTypeSymbol nextSyntaxValueTupleType) + { + foreach (var typeSymbol in GetTypeArguments(nextSyntaxValueTupleType)) + { + yield return typeSymbol; + } + } + else + { + yield return typeArgument; + } + } + } + } + + if (type.OriginalDefinition.Equals(_wellKnownTypes.Lazy1, SymbolEqualityComparer.Default) + && type is INamedTypeSymbol namedTypeSymbol) + { + if (namedTypeSymbol.TypeArguments.SingleOrDefault() is not INamedTypeSymbol genericType) + { + return ( + new ErrorTreeItem(namedTypeSymbol.TypeArguments.Length switch + { + 0 => $"[{namedTypeSymbol.FullName()}] Lazy: No type argument", + > 1 => $"[{namedTypeSymbol.FullName()}] Lazy: more than one type argument", + _ => $"[{namedTypeSymbol.FullName()}] Lazy: {namedTypeSymbol.TypeArguments[0].FullName()} is not a named type symbol" + }), + null); + } + + var dependency = SwitchType(new SwitchTypeParameter( + genericType, + Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>())); + var constructorInjection = new ConstructorResolution( + _rootReferenceGenerator.Generate(namedTypeSymbol), + namedTypeSymbol.FullName(), + ImplementsIDisposable(namedTypeSymbol, _wellKnownTypes, _disposableCollectionResolution, _checkTypeProperties), + new ReadOnlyCollection<(string Name, Resolvable Dependency)>( + new List<(string Name, Resolvable Dependency)> + { + ( + "valueFactory", + new FuncResolution( + _rootReferenceGenerator.Generate("func"), + $"global::System.Func<{genericType.FullName()}>", + Array.Empty(), + dependency.Item1) + ) + }), + Array.Empty<(string Name, Resolvable Dependency)>(), + null); + return (constructorInjection, constructorInjection); + } + + if (type.OriginalDefinition.Equals(_wellKnownTypes.Enumerable1, SymbolEqualityComparer.Default) + || type.OriginalDefinition.Equals(_wellKnownTypes.ReadOnlyCollection1, SymbolEqualityComparer.Default) + || type.OriginalDefinition.Equals(_wellKnownTypes.ReadOnlyList1, SymbolEqualityComparer.Default)) + { + if (type is not INamedTypeSymbol collectionType) + { + return ( + new ErrorTreeItem($"[{type.FullName()}] Collection: Collection is not a named type symbol"), + null); + } + if (collectionType.TypeArguments.SingleOrDefault() is not INamedTypeSymbol wrappedType) + { + return ( + new ErrorTreeItem(collectionType.TypeArguments.Length switch + { + 0 => $"[{type.FullName()}] Collection: No item type argument", + > 1 => $"[{type.FullName()}] Collection: More than one item type argument", + _ => $"[{type.FullName()}] Collection: {collectionType.TypeArguments[0].FullName()} is not a named type symbol" + }), + null); + } + ITypeSymbol wrappedItemTypeSymbol = wrappedType; + ITypeSymbol unwrappedItemTypeSymbol = wrappedType; + TaskType? taskType = null; + + if (wrappedType.OriginalDefinition.Equals(_wellKnownTypes.Task1, SymbolEqualityComparer.Default) + && type is INamedTypeSymbol enumerableTask) + { + wrappedItemTypeSymbol = enumerableTask.TypeArguments[0]; + taskType = TaskType.Task; + } + + if (wrappedType.OriginalDefinition.Equals(_wellKnownTypes.ValueTask1, SymbolEqualityComparer.Default) + && type is INamedTypeSymbol enumerableValueTask) + { + wrappedItemTypeSymbol = enumerableValueTask.TypeArguments[0]; + taskType = TaskType.ValueTask; + } + + if (wrappedItemTypeSymbol is not INamedTypeSymbol wrappedItemType) + { + return ( + new ErrorTreeItem($"[{type.FullName()}] Collection: Collection's inner type is not a named type symbol"), + null); + } + + if (taskType is { }) + unwrappedItemTypeSymbol = wrappedItemType.TypeArguments[0]; + + if (unwrappedItemTypeSymbol is not INamedTypeSymbol unwrappedItemType) + { + return ( + new ErrorTreeItem($"[{type.FullName()}] Collection: Collection's inner type is not a named type symbol"), + null); + } + + var itemTypeIsInterface = unwrappedItemType.TypeKind == TypeKind.Interface; + var items = _checkTypeProperties + .MapToImplementations(unwrappedItemType) + .Select(i => + { + var itemResolution = itemTypeIsInterface + ? SwitchInterfaceForSpecificImplementation( + new SwitchInterfaceForSpecificImplementationParameter(unwrappedItemType, i, currentFuncParameters)) + : SwitchClass(new SwitchClassParameter(i, currentFuncParameters)); + return (taskType switch + { + TaskType.Task => SwitchTask(new SwitchTaskParameter(itemResolution)), + TaskType.ValueTask => SwitchValueTask(new SwitchValueTaskParameter(itemResolution)), + _ => itemResolution + }).Item1; + }) + .ToList(); + + return ( + new CollectionResolution( + _rootReferenceGenerator.Generate(type), + type.FullName(), + wrappedItemType.FullName(), + items), + null); + } + + if (type.TypeKind == TypeKind.Interface) + return SwitchInterface(new SwitchInterfaceParameter(type, currentFuncParameters)); + + if (type.TypeKind is TypeKind.Class or TypeKind.Struct) + return SwitchClass(new SwitchClassParameter(type, currentFuncParameters)); + + if (type.TypeKind == TypeKind.Delegate + && type.FullName().StartsWith("global::System.Func<") + && type is INamedTypeSymbol namedTypeSymbol0) + { + var returnType = namedTypeSymbol0.TypeArguments.Last(); + var parameterTypes = namedTypeSymbol0 + .TypeArguments + .Take(namedTypeSymbol0.TypeArguments.Length - 1) + .Select(ts => (Type: ts, Resolution: new ParameterResolution(_rootReferenceGenerator.Generate(ts), ts.FullName()))) + .ToArray(); + + var dependency = SwitchType(new SwitchTypeParameter( + returnType, + parameterTypes)); + return ( + new FuncResolution( + _rootReferenceGenerator.Generate(type), + type.FullName(), + parameterTypes.Select(t => t.Resolution).ToArray(), + dependency.Item1), + null); + } + + return ( + new ErrorTreeItem($"[{type.FullName()}] Couldn't process in resolution tree creation."), + null); + } + + private (Resolvable, ConstructorResolution?) SwitchTask(SwitchTaskParameter parameter) + { + var resolution = parameter.InnerResolution; + var boundTaskTypeFullName = _wellKnownTypes + .Task1 + .ConstructUnboundGenericType() + .FullName() + .Replace("<>", $"<{resolution.Item1.TypeFullName}>"); + var wrappedTaskReference = _rootReferenceGenerator.Generate(_wellKnownTypes.Task); + if (resolution.Item2 is { } constructorResolution) + { + if (constructorResolution.Initialization is TaskBaseTypeInitializationResolution taskBaseResolution) + taskBaseResolution.Await = false; + var taskResolution = constructorResolution.Initialization switch + { + TaskTypeInitializationResolution taskTypeInitialization => new TaskFromTaskResolution( + resolution.Item1, + taskTypeInitialization, + wrappedTaskReference, + boundTaskTypeFullName), + ValueTaskTypeInitializationResolution taskTypeInitialization => new TaskFromValueTaskResolution( + resolution.Item1, + taskTypeInitialization, + wrappedTaskReference, + boundTaskTypeFullName), + _ => (Resolvable) new TaskFromSyncResolution(resolution.Item1, wrappedTaskReference, boundTaskTypeFullName) + }; + return (taskResolution, resolution.Item2); + } + return (new TaskFromSyncResolution(resolution.Item1, wrappedTaskReference, boundTaskTypeFullName), resolution.Item2); + } + + private (Resolvable, ConstructorResolution?) SwitchValueTask(SwitchValueTaskParameter parameter) + { + var resolution = parameter.InnerResolution; + var boundValueTaskTypeFullName = _wellKnownTypes + .ValueTask1 + .ConstructUnboundGenericType() + .FullName() + .Replace("<>", $"<{resolution.Item1.TypeFullName}>"); + var wrappedValueTaskReference = _rootReferenceGenerator.Generate(_wellKnownTypes.ValueTask); + if (resolution.Item2 is { } constructorResolution) + { + if (constructorResolution.Initialization is TaskBaseTypeInitializationResolution taskBaseResolution) + taskBaseResolution.Await = false; + var taskResolution = constructorResolution.Initialization switch + { + TaskTypeInitializationResolution taskTypeInitialization => new ValueTaskFromTaskResolution( + resolution.Item1, + taskTypeInitialization, + wrappedValueTaskReference, + boundValueTaskTypeFullName), + ValueTaskTypeInitializationResolution taskTypeInitialization => new ValueTaskFromValueTaskResolution( + resolution.Item1, + taskTypeInitialization, + wrappedValueTaskReference, + boundValueTaskTypeFullName), + _ => (Resolvable) new ValueTaskFromSyncResolution(resolution.Item1, wrappedValueTaskReference, boundValueTaskTypeFullName) + }; + return (taskResolution, resolution.Item2); + } + return (new TaskFromSyncResolution(resolution.Item1, wrappedValueTaskReference, boundValueTaskTypeFullName), resolution.Item2); + } + + private (Resolvable, ConstructorResolution?) SwitchInterface(SwitchInterfaceParameter parameter) + { + var (typeSymbol, currentParameters) = parameter; + var interfaceType = (INamedTypeSymbol) typeSymbol; + var implementations = _checkTypeProperties + .MapToImplementations(typeSymbol); + var shouldBeScopeRoot = implementations.Max(i => _checkTypeProperties.ShouldBeScopeRoot(i)); + + var nextParameter = new SwitchInterfaceAfterScopeRootParameter( + interfaceType, + implementations, + currentParameters); + + return shouldBeScopeRoot switch + { + ScopeLevel.TransientScope => (_rangeResolutionBaseBuilder.CreateTransientScopeRootResolution( + nextParameter, + interfaceType, + _disposableCollectionResolution, + currentParameters), null), // todo async handling + ScopeLevel.Scope => (_rangeResolutionBaseBuilder.CreateScopeRootResolution( + nextParameter, + interfaceType, + _disposableCollectionResolution, + currentParameters), null), // todo async handling + _ => SwitchInterfaceAfterScopeRoot(nextParameter) + }; + } + + private (Resolvable, ConstructorResolution?) SwitchInterfaceAfterScopeRoot( + SwitchInterfaceAfterScopeRootParameter parameter) + { + var (interfaceType, implementations, currentParameters) = parameter; + if (_checkTypeProperties.ShouldBeComposite(interfaceType)) + { + var compositeImplementationType = _checkTypeProperties.GetCompositeFor(interfaceType); + var interfaceResolutions = implementations.Select(i => CreateInterface(new CreateInterfaceParameter( + interfaceType, + i, + currentParameters))).ToList(); + var composition = new CompositionInterfaceExtension( + interfaceType, + implementations.ToList(), + compositeImplementationType, + interfaceResolutions.Select(ir => ir.Item1).ToList()); + return CreateInterface(new CreateInterfaceParameterAsComposition( + interfaceType, + compositeImplementationType, + currentParameters, + composition)); + } + if (implementations.SingleOrDefault() is not { } implementationType) + { + return ( + new ErrorTreeItem(implementations.Count switch + { + 0 => $"[{interfaceType.FullName()}] Interface: No implementation found", + > 1 => $"[{interfaceType.FullName()}] Interface: more than one implementation found", + _ => + $"[{interfaceType.FullName()}] Interface: Found single implementation {implementations[0].FullName()} is not a named type symbol" + }), + null); + } + + return CreateInterface(new CreateInterfaceParameter( + interfaceType, + implementationType, + currentParameters)); + } + + private (Resolvable, ConstructorResolution?) SwitchInterfaceForSpecificImplementation( + SwitchInterfaceForSpecificImplementationParameter parameter) + { + var (interfaceType, implementationType, currentParameters) = parameter; + + var nextParameter = new CreateInterfaceParameter( + interfaceType, + implementationType, + currentParameters); + + return _checkTypeProperties.ShouldBeScopeRoot(implementationType) switch + { + ScopeLevel.TransientScope => (_rangeResolutionBaseBuilder.CreateTransientScopeRootResolution( + nextParameter, + interfaceType, + _disposableCollectionResolution, + currentParameters), null), // todo async handling + ScopeLevel.Scope => (_rangeResolutionBaseBuilder.CreateScopeRootResolution( + nextParameter, + interfaceType, + _disposableCollectionResolution, + currentParameters), null), // todo async handling + _ => CreateInterface(nextParameter) + }; + } + + private (InterfaceResolution, ConstructorResolution?) CreateInterface(CreateInterfaceParameter parameter) + { + var (interfaceType, implementationType, currentParameters) = parameter; + var shouldBeDecorated = _checkTypeProperties.ShouldBeDecorated(interfaceType); + + var nextParameter = parameter switch + { + CreateInterfaceParameterAsComposition asComposition => new SwitchImplementationParameterWithComposition( + asComposition.Composition.CompositeType, + currentParameters, + asComposition.Composition), + _ => new SwitchImplementationParameter( + implementationType, + currentParameters) + }; + + var currentInterfaceResolution = new InterfaceResolution( + _rootReferenceGenerator.Generate(interfaceType), + interfaceType.FullName(), + SwitchImplementation(nextParameter).Item1); + + if (shouldBeDecorated) + { + var decorators = new Queue(_checkTypeProperties.GetSequenceFor(interfaceType, implementationType)); + while (decorators.Any()) + { + var decorator = decorators.Dequeue(); + var decoration = new DecorationInterfaceExtension( + interfaceType, + implementationType, + decorator, + currentInterfaceResolution); + var decoratorResolution = SwitchImplementation(new SwitchImplementationParameterWithDecoration( + decorator, + currentParameters, + decoration)).Item1; + currentInterfaceResolution = new InterfaceResolution( + _rootReferenceGenerator.Generate(interfaceType), + interfaceType.FullName(), + decoratorResolution); + } + } + + return (currentInterfaceResolution, currentInterfaceResolution.Dependency as ConstructorResolution); + } + + private (Resolvable, ConstructorResolution?) SwitchClass(SwitchClassParameter parameter) + { + var (typeSymbol, currentParameters) = parameter; + var implementations = _checkTypeProperties + .MapToImplementations(typeSymbol); + var implementationType = implementations.SingleOrDefault(); + if (implementationType is not { }) + { + return ( + new ErrorTreeItem(implementations.Count switch + { + 0 => $"[{typeSymbol.FullName()}] Class: No implementation found", + > 1 => $"[{typeSymbol.FullName()}] Class: more than one implementation found", + _ => $"[{typeSymbol.FullName()}] Class: Found single implementation{implementations[0].FullName()} is not a named type symbol" + }), + null); + } + + var nextParameter = new SwitchImplementationParameter( + implementationType, + currentParameters); + + return _checkTypeProperties.ShouldBeScopeRoot(implementationType) switch + { + ScopeLevel.TransientScope => (_rangeResolutionBaseBuilder.CreateTransientScopeRootResolution( + nextParameter, + implementationType, + _disposableCollectionResolution, + currentParameters), null), // todo async handling + ScopeLevel.Scope => (_rangeResolutionBaseBuilder.CreateScopeRootResolution( + nextParameter, + implementationType, + _disposableCollectionResolution, + currentParameters), null), // todo async handling + _ => SwitchImplementation(nextParameter) + }; + } + + private (Resolvable, ConstructorResolution?) SwitchImplementation(SwitchImplementationParameter parameter) + { + var (implementationType, currentParameters) = parameter; + var scopeLevel = parameter switch + { + SwitchImplementationParameterWithComposition withComposition => + withComposition.Composition.ImplementationTypes.Select(i => _checkTypeProperties.GetScopeLevelFor(i)) + .Min(), + SwitchImplementationParameterWithDecoration withDecoration => _checkTypeProperties.GetScopeLevelFor( + withDecoration.Decoration.ImplementationType), + _ => _checkTypeProperties.GetScopeLevelFor(parameter.ImplementationType) + }; + var nextParameter = parameter switch + { + SwitchImplementationParameterWithComposition withComposition => new ForConstructorParameterWithComposition( + withComposition.Composition.CompositeType, + currentParameters, + withComposition.Composition), + SwitchImplementationParameterWithDecoration withDecoration => new ForConstructorParameterWithDecoration( + withDecoration.Decoration.DecoratorType, + currentParameters, + withDecoration.Decoration), + _ => new ForConstructorParameter(implementationType, currentParameters) + }; + return scopeLevel switch + { + ScopeLevel.Container => (_rangeResolutionBaseBuilder.CreateContainerInstanceReferenceResolution(nextParameter), null), // todo async handling + ScopeLevel.TransientScope => (_rangeResolutionBaseBuilder.CreateTransientScopeInstanceReferenceResolution(nextParameter), null), // todo async handling + ScopeLevel.Scope => (_rangeResolutionBaseBuilder.CreateScopeInstanceReferenceResolution(nextParameter), null), // todo async handling + _ => CreateConstructorResolution(nextParameter) + }; + } + + private (Resolvable, ConstructorResolution?) CreateConstructorResolution(ForConstructorParameter parameter) + { + var (implementationType, currentParameters) = parameter; + + if (_checkTypeProperties.GetConstructorChoiceFor(implementationType) is not { } constructor) + { + return ( + new ErrorTreeItem(implementationType.Constructors.Length switch + { + 0 => $"[{implementationType.FullName()}] Class.Constructor: No constructor found for implementation {implementationType.FullName()}", + > 1 => $"[{implementationType.FullName()}] Class.Constructor: More than one constructor found for implementation {implementationType.FullName()}", + _ => $"[{implementationType.FullName()}] Class.Constructor: {implementationType.Constructors[0].Name} is not a method symbol" + }), + null); + } + + var checkForDecoration = false; + DecorationInterfaceExtension? decoration = null; + + if (parameter is ForConstructorParameterWithDecoration withDecoration) + { + checkForDecoration = true; + decoration = withDecoration.Decoration; + } + + var checkForComposition = false; + CompositionInterfaceExtension? composition = null; + + if (parameter is ForConstructorParameterWithComposition withComposition) + { + checkForComposition = true; + composition = withComposition.Composition; + } + + var isTransientScopeRoot = + _checkTypeProperties.ShouldBeScopeRoot(implementationType) == ScopeLevel.TransientScope; + + ITypeInitializationResolution? typeInitializationResolution = null; + + if (_checkTypeProperties.GetInitializerFor(implementationType) is { } tuple) + { + var (initializationInterface, initializationMethod) = tuple; + var initializationTypeFullName = initializationInterface.FullName(); + var initializationMethodName = initializationMethod.Name; + typeInitializationResolution = initializationMethod.ReturnsVoid switch + { + true => new SyncTypeInitializationResolution(initializationTypeFullName, initializationMethodName), + false when initializationMethod.ReturnType.Equals(_wellKnownTypes.Task, SymbolEqualityComparer.Default) => + new TaskTypeInitializationResolution( + initializationTypeFullName, + initializationMethodName, + _wellKnownTypes.Task.FullName(), + _rootReferenceGenerator.Generate(_wellKnownTypes.Task)), + false when initializationMethod.ReturnType.Equals(_wellKnownTypes.ValueTask, SymbolEqualityComparer.Default) => + new ValueTaskTypeInitializationResolution( + initializationTypeFullName, + initializationMethodName, + _wellKnownTypes.ValueTask.FullName(), + _rootReferenceGenerator.Generate(_wellKnownTypes.ValueTask)), + _ => typeInitializationResolution + }; + } + + + var resolution = new ConstructorResolution( + _rootReferenceGenerator.Generate(implementationType), + implementationType.FullName(), + ImplementsIDisposable( + implementationType, + _wellKnownTypes, + _disposableCollectionResolution, + _checkTypeProperties), + new ReadOnlyCollection<(string Name, Resolvable Dependency)>(constructor + .Parameters + .Select(p => ProcessChildType(p.Type, p.Name, implementationType, currentParameters)) + .ToList()), + new ReadOnlyCollection<(string Name, Resolvable Dependency)>(implementationType + .GetMembers() + .OfType() + .Where(p => p.SetMethod?.IsInitOnly ?? false) + .Select(p => ProcessChildType(p.Type, p.Name, implementationType, currentParameters)) + .ToList()), + typeInitializationResolution); + + return (resolution, resolution); + + (string Name, Resolvable Dependency) ProcessChildType( + ITypeSymbol typeSymbol, + string parameterName, + INamedTypeSymbol impType, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currParameter) + { + if (checkForDecoration && decoration is {}) + { + if (typeSymbol.Equals(decoration.InterfaceType, SymbolEqualityComparer.Default)) + return (parameterName, decoration.CurrentInterfaceResolution); + + if (typeSymbol.Equals(_wellKnownTypes.Task1.Construct(decoration.InterfaceType), SymbolEqualityComparer.Default) + && decoration.CurrentInterfaceResolution.Dependency is ConstructorResolution constrRes0) + return (parameterName, SwitchTask(new SwitchTaskParameter((decoration.CurrentInterfaceResolution, constrRes0))).Item1); + + if (typeSymbol.Equals(_wellKnownTypes.ValueTask1.Construct(decoration.InterfaceType), SymbolEqualityComparer.Default) + && decoration.CurrentInterfaceResolution.Dependency is ConstructorResolution constrRes1) + return (parameterName, SwitchValueTask(new SwitchValueTaskParameter((decoration.CurrentInterfaceResolution, constrRes1))).Item1); + } + + if (checkForComposition && composition is {}) + { + if (typeSymbol.Equals(_wellKnownTypes.Enumerable1.Construct(composition.InterfaceType), SymbolEqualityComparer.Default) + || typeSymbol.Equals(_wellKnownTypes.ReadOnlyCollection1.Construct(composition.InterfaceType), SymbolEqualityComparer.Default) + || typeSymbol.Equals(_wellKnownTypes.ReadOnlyList1.Construct(composition.InterfaceType), SymbolEqualityComparer.Default)) + return (parameterName, new CollectionResolution( + _rootReferenceGenerator.Generate(typeSymbol), + typeSymbol.FullName(), + composition.InterfaceType.FullName(), + composition.InterfaceResolutionComposition)); + + if (typeSymbol.Equals(_wellKnownTypes.Enumerable1.Construct(_wellKnownTypes.Task1.Construct(composition.InterfaceType)), SymbolEqualityComparer.Default) + || typeSymbol.Equals(_wellKnownTypes.ReadOnlyCollection1.Construct(_wellKnownTypes.Task1.Construct(composition.InterfaceType)), SymbolEqualityComparer.Default) + || typeSymbol.Equals(_wellKnownTypes.ReadOnlyList1.Construct(_wellKnownTypes.Task1.Construct(composition.InterfaceType)), SymbolEqualityComparer.Default)) + return (parameterName, new CollectionResolution( + _rootReferenceGenerator.Generate(typeSymbol), + typeSymbol.FullName(), + _wellKnownTypes.Task1.Construct(composition.InterfaceType).FullName(), + composition.InterfaceResolutionComposition + .Select(ir => + { + if (ir.Dependency is ConstructorResolution constRes) + return SwitchTask(new SwitchTaskParameter((ir, constRes))).Item1; + return null; + }) + .OfType() + .ToList())); + + if (typeSymbol.Equals(_wellKnownTypes.Enumerable1.Construct(_wellKnownTypes.ValueTask1.Construct(composition.InterfaceType)), SymbolEqualityComparer.Default) + || typeSymbol.Equals(_wellKnownTypes.ReadOnlyCollection1.Construct(_wellKnownTypes.ValueTask1.Construct(composition.InterfaceType)), SymbolEqualityComparer.Default) + || typeSymbol.Equals(_wellKnownTypes.ReadOnlyList1.Construct(_wellKnownTypes.ValueTask1.Construct(composition.InterfaceType)), SymbolEqualityComparer.Default)) + return (parameterName, new CollectionResolution( + _rootReferenceGenerator.Generate(typeSymbol), + typeSymbol.FullName(), + _wellKnownTypes.ValueTask1.Construct(composition.InterfaceType).FullName(), + composition.InterfaceResolutionComposition + .Select(ir => + { + if (ir.Dependency is ConstructorResolution constRes) + return SwitchValueTask(new SwitchValueTaskParameter((ir, constRes))).Item1; + return null; + }) + .OfType() + .ToList())); + } + + if (isTransientScopeRoot + && typeSymbol.Equals(_wellKnownTypes.Disposable, SymbolEqualityComparer.Default)) + return (parameterName, new TransientScopeAsDisposableResolution( + _rootReferenceGenerator.Generate(_wellKnownTypes.Disposable), + _wellKnownTypes.Disposable.FullName())); + if (typeSymbol is not INamedTypeSymbol parameterType) + return ("", + new ErrorTreeItem( + $"[{impType.FullName()}] Class.Constructor.Parameter: Parameter type {typeSymbol.FullName()} is not a named type symbol")); + + return ( + parameterName, + SwitchType(new SwitchTypeParameter( + parameterType, + currParameter)).Item1); + } + } + + private static DisposableCollectionResolution? ImplementsIDisposable( + INamedTypeSymbol type, + WellKnownTypes wellKnownTypes, + DisposableCollectionResolution disposableCollectionResolution, + ICheckTypeProperties checkDisposalManagement) => + type.AllInterfaces.Contains(wellKnownTypes.Disposable) && checkDisposalManagement.ShouldBeManaged(type) + ? disposableCollectionResolution + : null; + + public Resolvable ResolveFunction(SwitchTypeParameter parameter) + { + return SwitchType(parameter).Item1; + } + + public Resolvable RangedFunction(ForConstructorParameter parameter) + { + return CreateConstructorResolution(parameter).Item1; + } + + public Resolvable ScopeRootFunction(CreateInterfaceParameter parameter) + { + return CreateInterface(parameter).Item1; + } + + public Resolvable ScopeRootFunction(SwitchImplementationParameter parameter) + { + return SwitchImplementation(parameter).Item1; + } + + public Resolvable ScopeRootFunction(SwitchInterfaceAfterScopeRootParameter parameter) + { + return SwitchInterfaceAfterScopeRoot(parameter).Item1; + } +} \ No newline at end of file diff --git a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs index 4280b914..c8976084 100644 --- a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs +++ b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs @@ -2,11 +2,42 @@ namespace MrMeeseeks.DIE.ResolutionBuilding; -internal abstract class RangeResolutionBaseBuilder +internal interface IRangeResolutionBaseBuilder { + ICheckTypeProperties CheckTypeProperties { get; } + IUserProvidedScopeElements UserProvidedScopeElements { get; } + DisposableCollectionResolution DisposableCollectionResolution { get; } + RangedInstanceReferenceResolution CreateContainerInstanceReferenceResolution( + ForConstructorParameter parameter); + + RangedInstanceReferenceResolution CreateTransientScopeInstanceReferenceResolution( + ForConstructorParameter parameter); + + RangedInstanceReferenceResolution CreateScopeInstanceReferenceResolution( + ForConstructorParameter parameter); + + TransientScopeRootResolution CreateTransientScopeRootResolution( + IScopeRootParameter parameter, + INamedTypeSymbol rootType, + DisposableCollectionResolution disposableCollectionResolution, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters); + + ScopeRootResolution CreateScopeRootResolution( + IScopeRootParameter parameter, + INamedTypeSymbol rootType, + DisposableCollectionResolution disposableCollectionResolution, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters); +} + +internal abstract class RangeResolutionBaseBuilder : IRangeResolutionBaseBuilder +{ + public ICheckTypeProperties CheckTypeProperties { get; } + public IUserProvidedScopeElements UserProvidedScopeElements { get; } + public DisposableCollectionResolution DisposableCollectionResolution { get; } + protected readonly WellKnownTypes WellKnownTypes; - protected readonly ICheckTypeProperties CheckTypeProperties; + private readonly Func _functionResolutionBuilderFactory; protected readonly IReferenceGenerator RootReferenceGenerator; protected readonly IDictionary RangedInstanceReferenceResolutions = @@ -15,24 +46,24 @@ internal abstract class RangeResolutionBaseBuilder protected readonly Queue RangedInstanceResolutionsQueue = new(); protected readonly List<(RangedInstanceFunction, RangedInstanceFunctionOverload)> RangedInstances = new (); - protected readonly DisposableCollectionResolution DisposableCollectionResolution; - protected readonly IUserProvidedScopeElements UserProvidedScopeElements; protected readonly DisposalHandling DisposalHandling; protected readonly string Name; protected RangeResolutionBaseBuilder( // parameters string name, + ICheckTypeProperties checkTypeProperties, + IUserProvidedScopeElements userProvidedScopeElements, // dependencies WellKnownTypes wellKnownTypes, IReferenceGeneratorFactory referenceGeneratorFactory, - ICheckTypeProperties checkTypeProperties, - IUserProvidedScopeElements userProvidedScopeElements) + Func functionResolutionBuilderFactory) { - WellKnownTypes = wellKnownTypes; CheckTypeProperties = checkTypeProperties; UserProvidedScopeElements = userProvidedScopeElements; + WellKnownTypes = wellKnownTypes; + _functionResolutionBuilderFactory = functionResolutionBuilderFactory; RootReferenceGenerator = referenceGeneratorFactory.Create(); DisposableCollectionResolution = new DisposableCollectionResolution( @@ -49,527 +80,28 @@ protected RangeResolutionBaseBuilder( RootReferenceGenerator.Generate("disposable")); } - protected abstract RangedInstanceReferenceResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter); + public abstract RangedInstanceReferenceResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter); - protected abstract RangedInstanceReferenceResolution CreateTransientScopeInstanceReferenceResolution(ForConstructorParameter parameter); + public abstract RangedInstanceReferenceResolution CreateTransientScopeInstanceReferenceResolution(ForConstructorParameter parameter); + + public RangedInstanceReferenceResolution CreateScopeInstanceReferenceResolution( + ForConstructorParameter parameter) => + CreateRangedInstanceReferenceResolution( + parameter, + "Scope", + "this"); - protected abstract TransientScopeRootResolution CreateTransientScopeRootResolution( + public abstract TransientScopeRootResolution CreateTransientScopeRootResolution( IScopeRootParameter parameter, INamedTypeSymbol rootType, DisposableCollectionResolution disposableCollectionResolution, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters); - protected abstract ScopeRootResolution CreateScopeRootResolution( + public abstract ScopeRootResolution CreateScopeRootResolution( IScopeRootParameter parameter, INamedTypeSymbol rootType, DisposableCollectionResolution disposableCollectionResolution, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters); - - protected Resolvable SwitchType(SwitchTypeParameter parameter) - { - var (type, currentFuncParameters) = parameter; - if (currentFuncParameters.FirstOrDefault(t => SymbolEqualityComparer.Default.Equals(t.Type.OriginalDefinition, type.OriginalDefinition)) is { Type: not null, Resolution: not null } funcParameter) - return funcParameter.Resolution; - - if (UserProvidedScopeElements.GetInstanceFor(type) is { } instance) - return new FieldResolution( - RootReferenceGenerator.Generate(instance.Type), - instance.Type.FullName(), - instance.Name); - - if (UserProvidedScopeElements.GetPropertyFor(type) is { } property) - return new FieldResolution( - RootReferenceGenerator.Generate(property.Type), - property.Type.FullName(), - property.Name); - - if (UserProvidedScopeElements.GetFactoryFor(type) is { } factory) - return new FactoryResolution( - RootReferenceGenerator.Generate(factory.ReturnType), - factory.ReturnType.FullName(), - factory.Name, - factory - .Parameters - .Select(p => (p.Name, SwitchType(new SwitchTypeParameter(p.Type, currentFuncParameters)))) - .ToList()); - - if (type.FullName().StartsWith("global::System.ValueTuple<") && type is INamedTypeSymbol valueTupleType) - { - return new ConstructorResolution( - RootReferenceGenerator.Generate(valueTupleType), - valueTupleType.FullName(), - ImplementsIDisposable(valueTupleType, WellKnownTypes, DisposableCollectionResolution, CheckTypeProperties), - valueTupleType - .TypeArguments - .Select((t, i) => ($"item{(i + 1)}", SwitchType(new SwitchTypeParameter(t, currentFuncParameters)))) - .ToList(), - Array.Empty<(string Name, Resolvable Dependency)>(), - null); - } - - if (type.FullName().StartsWith("(") && type.FullName().EndsWith(")") && type is INamedTypeSymbol syntaxValueTupleType) - { - var itemTypes = GetTypeArguments(syntaxValueTupleType).ToList(); - - return new SyntaxValueTupleResolution( - RootReferenceGenerator.Generate("syntaxValueTuple"), - syntaxValueTupleType.FullName(), - itemTypes - .Select(t => SwitchType(new SwitchTypeParameter(t, currentFuncParameters))) - .ToList()); - - IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTupleType) - { - foreach (var typeArgument in currentSyntaxValueTupleType.TypeArguments) - { - if (typeArgument.FullName().StartsWith("(") && typeArgument.FullName().EndsWith(")") && - typeArgument is INamedTypeSymbol nextSyntaxValueTupleType) - { - foreach (var typeSymbol in GetTypeArguments(nextSyntaxValueTupleType)) - { - yield return typeSymbol; - } - } - else - { - yield return typeArgument; - } - } - } - } - - if (type.OriginalDefinition.Equals(WellKnownTypes.Lazy1, SymbolEqualityComparer.Default) - && type is INamedTypeSymbol namedTypeSymbol) - { - if (namedTypeSymbol.TypeArguments.SingleOrDefault() is not INamedTypeSymbol genericType) - { - return new ErrorTreeItem(namedTypeSymbol.TypeArguments.Length switch - { - 0 => $"[{namedTypeSymbol.FullName()}] Lazy: No type argument", - > 1 => $"[{namedTypeSymbol.FullName()}] Lazy: more than one type argument", - _ => $"[{namedTypeSymbol.FullName()}] Lazy: {namedTypeSymbol.TypeArguments[0].FullName()} is not a named type symbol" - }); - } - - var dependency = SwitchType(new SwitchTypeParameter( - genericType, - Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>())); - return new ConstructorResolution( - RootReferenceGenerator.Generate(namedTypeSymbol), - namedTypeSymbol.FullName(), - ImplementsIDisposable(namedTypeSymbol, WellKnownTypes, DisposableCollectionResolution, CheckTypeProperties), - new ReadOnlyCollection<(string Name, Resolvable Dependency)>( - new List<(string Name, Resolvable Dependency)> - { - ( - "valueFactory", - new FuncResolution( - RootReferenceGenerator.Generate("func"), - $"global::System.Func<{genericType.FullName()}>", - Array.Empty(), - dependency) - ) - }), - Array.Empty<(string Name, Resolvable Dependency)>(), - null); - } - - if (type.OriginalDefinition.Equals(WellKnownTypes.Enumerable1, SymbolEqualityComparer.Default) - || type.OriginalDefinition.Equals(WellKnownTypes.ReadOnlyCollection1, SymbolEqualityComparer.Default) - || type.OriginalDefinition.Equals(WellKnownTypes.ReadOnlyList1, SymbolEqualityComparer.Default)) - { - if (type is not INamedTypeSymbol collectionType) - { - return new ErrorTreeItem($"[{type.FullName()}] Collection: Collection is not a named type symbol"); - } - if (collectionType.TypeArguments.SingleOrDefault() is not INamedTypeSymbol itemType) - { - return new ErrorTreeItem(collectionType.TypeArguments.Length switch - { - 0 => $"[{type.FullName()}] Collection: No item type argument", - > 1 => $"[{type.FullName()}] Collection: More than one item type argument", - _ => $"[{type.FullName()}] Collection: {collectionType.TypeArguments[0].FullName()} is not a named type symbol" - }); - } - var itemFullName = itemType.FullName(); - var itemTypeIsInterface = itemType.TypeKind == TypeKind.Interface; - var items = CheckTypeProperties - .MapToImplementations(itemType) - .Select(i => itemTypeIsInterface - ? SwitchInterfaceForSpecificImplementation(new SwitchInterfaceForSpecificImplementationParameter(itemType, i, currentFuncParameters)) - : SwitchClass(new SwitchClassParameter(i, currentFuncParameters))) - .ToList(); - - return new CollectionResolution( - RootReferenceGenerator.Generate(type), - type.FullName(), - itemFullName, - items); - } - - if (type.TypeKind == TypeKind.Interface) - return SwitchInterface(new SwitchInterfaceParameter(type, currentFuncParameters)); - - if (type.TypeKind is TypeKind.Class or TypeKind.Struct) - return SwitchClass(new SwitchClassParameter(type, currentFuncParameters)); - - if (type.TypeKind == TypeKind.Delegate - && type.FullName().StartsWith("global::System.Func<") - && type is INamedTypeSymbol namedTypeSymbol0) - { - var returnType = namedTypeSymbol0.TypeArguments.Last(); - var parameterTypes = namedTypeSymbol0 - .TypeArguments - .Take(namedTypeSymbol0.TypeArguments.Length - 1) - .Select(ts => (Type: ts, Resolution: new ParameterResolution(RootReferenceGenerator.Generate(ts), ts.FullName()))) - .ToArray(); - - var dependency = SwitchType(new SwitchTypeParameter( - returnType, - parameterTypes)); - return new FuncResolution( - RootReferenceGenerator.Generate(type), - type.FullName(), - parameterTypes.Select(t => t.Resolution).ToArray(), - dependency); - } - - return new ErrorTreeItem($"[{type.FullName()}] Couldn't process in resolution tree creation."); - } - - private Resolvable SwitchInterface(SwitchInterfaceParameter parameter) - { - var (typeSymbol, currentParameters) = parameter; - var interfaceType = (INamedTypeSymbol) typeSymbol; - var implementations = CheckTypeProperties - .MapToImplementations(typeSymbol); - var shouldBeScopeRoot = implementations.Max(i => CheckTypeProperties.ShouldBeScopeRoot(i)); - - var nextParameter = new SwitchInterfaceAfterScopeRootParameter( - interfaceType, - implementations, - currentParameters); - - return shouldBeScopeRoot switch - { - ScopeLevel.TransientScope => CreateTransientScopeRootResolution( - nextParameter, - interfaceType, - DisposableCollectionResolution, - currentParameters), - ScopeLevel.Scope => CreateScopeRootResolution( - nextParameter, - interfaceType, - DisposableCollectionResolution, - currentParameters), - _ => SwitchInterfaceAfterScopeRoot(nextParameter) - }; - } - - protected Resolvable SwitchInterfaceAfterScopeRoot( - SwitchInterfaceAfterScopeRootParameter parameter) - { - var (interfaceType, implementations, currentParameters) = parameter; - if (CheckTypeProperties.ShouldBeComposite(interfaceType)) - { - var compositeImplementationType = CheckTypeProperties.GetCompositeFor(interfaceType); - var interfaceResolutions = implementations.Select(i => CreateInterface(new CreateInterfaceParameter( - interfaceType, - i, - currentParameters))).ToList(); - var composition = new CompositionInterfaceExtension( - interfaceType, - implementations.ToList(), - compositeImplementationType, - interfaceResolutions); - return CreateInterface(new CreateInterfaceParameterAsComposition( - interfaceType, - compositeImplementationType, - currentParameters, - composition)); - } - if (implementations.SingleOrDefault() is not { } implementationType) - { - return new ErrorTreeItem(implementations.Count switch - { - 0 => $"[{interfaceType.FullName()}] Interface: No implementation found", - > 1 => $"[{interfaceType.FullName()}] Interface: more than one implementation found", - _ => - $"[{interfaceType.FullName()}] Interface: Found single implementation {implementations[0].FullName()} is not a named type symbol" - }); - } - - return CreateInterface(new CreateInterfaceParameter( - interfaceType, - implementationType, - currentParameters)); - } - - private Resolvable SwitchInterfaceForSpecificImplementation( - SwitchInterfaceForSpecificImplementationParameter parameter) - { - var (interfaceType, implementationType, currentParameters) = parameter; - - var nextParameter = new CreateInterfaceParameter( - interfaceType, - implementationType, - currentParameters); - - return CheckTypeProperties.ShouldBeScopeRoot(implementationType) switch - { - ScopeLevel.TransientScope => CreateTransientScopeRootResolution( - nextParameter, - interfaceType, - DisposableCollectionResolution, - currentParameters), - ScopeLevel.Scope => CreateScopeRootResolution( - nextParameter, - interfaceType, - DisposableCollectionResolution, - currentParameters), - _ => CreateInterface(nextParameter) - }; - } - - internal InterfaceResolution CreateInterface(CreateInterfaceParameter parameter) - { - var (interfaceType, implementationType, currentParameters) = parameter; - var shouldBeDecorated = CheckTypeProperties.ShouldBeDecorated(interfaceType); - - var nextParameter = parameter switch - { - CreateInterfaceParameterAsComposition asComposition => new SwitchImplementationParameterWithComposition( - asComposition.Composition.CompositeType, - currentParameters, - asComposition.Composition), - _ => new SwitchImplementationParameter( - implementationType, - currentParameters) - }; - - var currentInterfaceResolution = new InterfaceResolution( - RootReferenceGenerator.Generate(interfaceType), - interfaceType.FullName(), - SwitchImplementation(nextParameter)); - - if (shouldBeDecorated) - { - var decorators = new Queue(CheckTypeProperties.GetSequenceFor(interfaceType, implementationType)); - while (decorators.Any()) - { - var decorator = decorators.Dequeue(); - var decoration = new DecorationInterfaceExtension(interfaceType, implementationType, decorator, - currentInterfaceResolution); - var decoratorResolution = SwitchImplementation(new SwitchImplementationParameterWithDecoration( - decorator, - currentParameters, - decoration)); - currentInterfaceResolution = new InterfaceResolution( - RootReferenceGenerator.Generate(interfaceType), - interfaceType.FullName(), - decoratorResolution); - } - } - - return currentInterfaceResolution; - } - - protected Resolvable SwitchClass(SwitchClassParameter parameter) - { - var (typeSymbol, currentParameters) = parameter; - var implementations = CheckTypeProperties - .MapToImplementations(typeSymbol); - var implementationType = implementations.SingleOrDefault(); - if (implementationType is not { }) - { - return new ErrorTreeItem(implementations.Count switch - { - 0 => $"[{typeSymbol.FullName()}] Class: No implementation found", - > 1 => $"[{typeSymbol.FullName()}] Class: more than one implementation found", - _ => - $"[{typeSymbol.FullName()}] Class: Found single implementation{implementations[0].FullName()} is not a named type symbol" - }); - } - - var nextParameter = new SwitchImplementationParameter( - implementationType, - currentParameters); - - return CheckTypeProperties.ShouldBeScopeRoot(implementationType) switch - { - ScopeLevel.TransientScope => CreateTransientScopeRootResolution( - nextParameter, - implementationType, - DisposableCollectionResolution, - currentParameters), - ScopeLevel.Scope => CreateScopeRootResolution( - nextParameter, - implementationType, - DisposableCollectionResolution, - currentParameters), - _ => SwitchImplementation(nextParameter) - }; - } - - protected Resolvable SwitchImplementation(SwitchImplementationParameter parameter) - { - var (implementationType, currentParameters) = parameter; - var scopeLevel = parameter switch - { - SwitchImplementationParameterWithComposition withComposition => - withComposition.Composition.ImplementationTypes.Select(i => CheckTypeProperties.GetScopeLevelFor(i)) - .Min(), - SwitchImplementationParameterWithDecoration withDecoration => CheckTypeProperties.GetScopeLevelFor( - withDecoration.Decoration.ImplementationType), - _ => CheckTypeProperties.GetScopeLevelFor(parameter.ImplementationType) - }; - var nextParameter = parameter switch - { - SwitchImplementationParameterWithComposition withComposition => new ForConstructorParameterWithComposition( - withComposition.Composition.CompositeType, - currentParameters, - withComposition.Composition), - SwitchImplementationParameterWithDecoration withDecoration => new ForConstructorParameterWithDecoration( - withDecoration.Decoration.DecoratorType, - currentParameters, - withDecoration.Decoration), - _ => new ForConstructorParameter(implementationType, currentParameters) - }; - return scopeLevel switch - { - ScopeLevel.Container => CreateContainerInstanceReferenceResolution(nextParameter), - ScopeLevel.TransientScope => CreateTransientScopeInstanceReferenceResolution(nextParameter), - ScopeLevel.Scope => CreateScopeInstanceReferenceResolution(nextParameter), - _ => CreateConstructorResolution(nextParameter) - }; - } - - protected Resolvable CreateConstructorResolution(ForConstructorParameter parameter) - { - var (implementationType, currentParameters) = parameter; - - if (CheckTypeProperties.GetConstructorChoiceFor(implementationType) is not { } constructor) - { - return new ErrorTreeItem(implementationType.Constructors.Length switch - { - 0 => $"[{implementationType.FullName()}] Class.Constructor: No constructor found for implementation {implementationType.FullName()}", - > 1 => $"[{implementationType.FullName()}] Class.Constructor: More than one constructor found for implementation {implementationType.FullName()}", - _ => $"[{implementationType.FullName()}] Class.Constructor: {implementationType.Constructors[0].Name} is not a method symbol" - }); - } - - var checkForDecoration = false; - DecorationInterfaceExtension? decoration = null; - - if (parameter is ForConstructorParameterWithDecoration withDecoration) - { - checkForDecoration = true; - decoration = withDecoration.Decoration; - } - - var checkForComposition = false; - CompositionInterfaceExtension? composition = null; - - if (parameter is ForConstructorParameterWithComposition withComposition) - { - checkForComposition = true; - composition = withComposition.Composition; - } - - var isTransientScopeRoot = - CheckTypeProperties.ShouldBeScopeRoot(implementationType) == ScopeLevel.TransientScope; - - ITypeInitializationResolution? typeInitializationResolution = null; - - if (CheckTypeProperties.GetInitializerFor(implementationType) is { } tuple) - { - var (initializationInterface, initializationMethod) = tuple; - var initializationTypeFullName = initializationInterface.FullName(); - var initializationMethodName = initializationMethod.Name; - typeInitializationResolution = initializationMethod.ReturnsVoid switch - { - true => new SyncTypeInitializationResolution(initializationTypeFullName, initializationMethodName), - false when initializationMethod.ReturnType.Equals(WellKnownTypes.Task, SymbolEqualityComparer.Default) => - new TaskTypeInitializationResolution( - initializationTypeFullName, - initializationMethodName, - WellKnownTypes.Task.FullName(), - RootReferenceGenerator.Generate(WellKnownTypes.Task)), - false when initializationMethod.ReturnType.Equals(WellKnownTypes.ValueTask, SymbolEqualityComparer.Default) => - new ValueTaskTypeInitializationResolution( - initializationTypeFullName, - initializationMethodName, - WellKnownTypes.ValueTask.FullName(), - RootReferenceGenerator.Generate(WellKnownTypes.ValueTask)), - _ => typeInitializationResolution - }; - } - - - return new ConstructorResolution( - RootReferenceGenerator.Generate(implementationType), - implementationType.FullName(), - ImplementsIDisposable( - implementationType, - WellKnownTypes, - DisposableCollectionResolution, - CheckTypeProperties), - new ReadOnlyCollection<(string Name, Resolvable Dependency)>(constructor - .Parameters - .Select(p => ProcessChildType(p.Type, p.Name, implementationType, currentParameters)) - .ToList()), - new ReadOnlyCollection<(string Name, Resolvable Dependency)>(implementationType - .GetMembers() - .OfType() - .Where(p => p.SetMethod?.IsInitOnly ?? false) - .Select(p => ProcessChildType(p.Type, p.Name, implementationType, currentParameters)) - .ToList()), - typeInitializationResolution); - - (string Name, Resolvable Dependency) ProcessChildType( - ITypeSymbol typeSymbol, - string parameterName, - INamedTypeSymbol impType, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currParameter) - { - if (checkForDecoration && typeSymbol.Equals(decoration?.InterfaceType, SymbolEqualityComparer.Default)) - return (parameterName, decoration.CurrentInterfaceResolution); - if (checkForComposition - && composition is {} - && (typeSymbol.Equals(WellKnownTypes.Enumerable1.Construct(composition.InterfaceType), SymbolEqualityComparer.Default) - || typeSymbol.Equals(WellKnownTypes.ReadOnlyCollection1.Construct(composition.InterfaceType), SymbolEqualityComparer.Default) - || typeSymbol.Equals(WellKnownTypes.ReadOnlyList1.Construct(composition.InterfaceType), SymbolEqualityComparer.Default))) - return (parameterName, new CollectionResolution( - RootReferenceGenerator.Generate(typeSymbol), - typeSymbol.FullName(), - composition.InterfaceType.FullName(), - composition.InterfaceResolutionComposition)); - - if (isTransientScopeRoot - && typeSymbol.Equals(WellKnownTypes.Disposable, SymbolEqualityComparer.Default)) - return (parameterName, new TransientScopeAsDisposableResolution( - RootReferenceGenerator.Generate(WellKnownTypes.Disposable), - WellKnownTypes.Disposable.FullName())); - if (typeSymbol is not INamedTypeSymbol parameterType) - return ("", - new ErrorTreeItem( - $"[{impType.FullName()}] Class.Constructor.Parameter: Parameter type {typeSymbol.FullName()} is not a named type symbol")); - - return ( - parameterName, - SwitchType(new SwitchTypeParameter( - parameterType, - currParameter))); - } - } - - - private RangedInstanceReferenceResolution CreateScopeInstanceReferenceResolution( - ForConstructorParameter parameter) => - CreateRangedInstanceReferenceResolution( - parameter, - "Scope", - "this"); protected RangedInstanceReferenceResolution CreateRangedInstanceReferenceResolution( ForConstructorParameter parameter, @@ -621,11 +153,11 @@ protected void DoRangedInstancesWork() var (scopeInstanceFunction, parameter, type, interfaceExtension) = RangedInstanceResolutionsQueue.Dequeue(); var resolvable = interfaceExtension switch { - DecorationInterfaceExtension decoration => CreateConstructorResolution(new ForConstructorParameterWithDecoration( + DecorationInterfaceExtension decoration => _functionResolutionBuilderFactory(this).RangedFunction(new ForConstructorParameterWithDecoration( decoration.DecoratorType, parameter, decoration)), - CompositionInterfaceExtension composition => CreateConstructorResolution(new ForConstructorParameterWithComposition( + CompositionInterfaceExtension composition => _functionResolutionBuilderFactory(this).RangedFunction(new ForConstructorParameterWithComposition( composition.CompositeType, parameter, composition)), - _ => CreateConstructorResolution(new ForConstructorParameter(type, parameter)) + _ => _functionResolutionBuilderFactory(this).RangedFunction(new ForConstructorParameter(type, parameter)) }; RangedInstances.Add(( scopeInstanceFunction, @@ -634,13 +166,4 @@ protected void DoRangedInstancesWork() parameter.Select(t => t.Item2).ToList()))); } } - - private static DisposableCollectionResolution? ImplementsIDisposable( - INamedTypeSymbol type, - WellKnownTypes wellKnownTypes, - DisposableCollectionResolution disposableCollectionResolution, - ICheckTypeProperties checkDisposalManagement) => - type.AllInterfaces.Contains(wellKnownTypes.Disposable) && checkDisposalManagement.ShouldBeManaged(type) - ? disposableCollectionResolution - : null; } \ No newline at end of file diff --git a/Main/ResolutionBuilding/ResolutionDtos.cs b/Main/ResolutionBuilding/ResolutionDtos.cs index 48340ca4..dd5a3eaa 100644 --- a/Main/ResolutionBuilding/ResolutionDtos.cs +++ b/Main/ResolutionBuilding/ResolutionDtos.cs @@ -144,4 +144,14 @@ internal record RangedInstanceResolutionsQueueItem( RangedInstanceFunction Function, IReadOnlyList<(ITypeSymbol, ParameterResolution)> Parameters, INamedTypeSymbol ImplementationType, - InterfaceExtension? InterfaceExtension); \ No newline at end of file + InterfaceExtension? InterfaceExtension); + +internal record SwitchTaskParameter((Resolvable, ConstructorResolution?) InnerResolution) : Parameter; + +internal record SwitchValueTaskParameter((Resolvable, ConstructorResolution?) InnerResolution) : Parameter; + +internal enum TaskType +{ + Task, + ValueTask +} \ No newline at end of file diff --git a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs index 1044f5f3..74a788b7 100644 --- a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs @@ -2,7 +2,7 @@ namespace MrMeeseeks.DIE.ResolutionBuilding; -internal interface IScopeResolutionBuilder +internal interface IScopeResolutionBuilder : IRangeResolutionBaseBuilder { bool HasWorkToDo { get; } @@ -24,6 +24,7 @@ internal class ScopeResolutionBuilder : RangeResolutionBaseBuilder, IScopeResolu private readonly IContainerResolutionBuilder _containerResolutionBuilder; private readonly ITransientScopeInterfaceResolutionBuilder _transientScopeInterfaceResolutionBuilder; private readonly IScopeManager _scopeManager; + private readonly Func _functionResolutionBuilderFactory; private readonly List _rootResolutions = new (); private readonly string _containerReference; private readonly string _containerParameterReference; @@ -45,30 +46,33 @@ internal ScopeResolutionBuilder( // dependencies WellKnownTypes wellKnownTypes, - IReferenceGeneratorFactory referenceGeneratorFactory) + IReferenceGeneratorFactory referenceGeneratorFactory, + Func functionResolutionBuilderFactory) : base( - name, //Constants.DefaultScopeName, + name, + checkTypeProperties, + userProvidedScopeElements, wellKnownTypes, - referenceGeneratorFactory, - checkTypeProperties, - userProvidedScopeElements) + referenceGeneratorFactory, + functionResolutionBuilderFactory) { _containerResolutionBuilder = containerResolutionBuilder; _transientScopeInterfaceResolutionBuilder = transientScopeInterfaceResolutionBuilder; _scopeManager = scopeManager; + _functionResolutionBuilderFactory = functionResolutionBuilderFactory; _containerReference = RootReferenceGenerator.Generate("_container"); _containerParameterReference = RootReferenceGenerator.Generate("container"); _transientScopeReference = RootReferenceGenerator.Generate("_transientScope"); _transientScopeParameterReference = RootReferenceGenerator.Generate("transientScope"); } - protected override RangedInstanceReferenceResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter) => + public override RangedInstanceReferenceResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter) => _containerResolutionBuilder.CreateContainerInstanceReferenceResolution(parameter, _containerReference); - protected override RangedInstanceReferenceResolution CreateTransientScopeInstanceReferenceResolution(ForConstructorParameter parameter) => + public override RangedInstanceReferenceResolution CreateTransientScopeInstanceReferenceResolution(ForConstructorParameter parameter) => _transientScopeInterfaceResolutionBuilder.CreateTransientScopeInstanceReferenceResolution(parameter, _transientScopeReference); - protected override TransientScopeRootResolution CreateTransientScopeRootResolution( + public override TransientScopeRootResolution CreateTransientScopeRootResolution( IScopeRootParameter parameter, INamedTypeSymbol rootType, DisposableCollectionResolution disposableCollectionResolution, @@ -82,7 +86,7 @@ protected override TransientScopeRootResolution CreateTransientScopeRootResoluti disposableCollectionResolution, currentParameters); - protected override ScopeRootResolution CreateScopeRootResolution( + public override ScopeRootResolution CreateScopeRootResolution( IScopeRootParameter parameter, INamedTypeSymbol rootType, DisposableCollectionResolution disposableCollectionResolution, @@ -150,9 +154,9 @@ public void DoWork() var resolvable = functionParameter switch { - CreateInterfaceParameter createInterfaceParameter => CreateInterface(createInterfaceParameter), - SwitchImplementationParameter switchImplementationParameter => SwitchImplementation(switchImplementationParameter), - SwitchInterfaceAfterScopeRootParameter switchInterfaceAfterScopeRootParameter => SwitchInterfaceAfterScopeRoot(switchInterfaceAfterScopeRootParameter), + CreateInterfaceParameter createInterfaceParameter => _functionResolutionBuilderFactory(this).ScopeRootFunction(createInterfaceParameter), + SwitchImplementationParameter switchImplementationParameter => _functionResolutionBuilderFactory(this).ScopeRootFunction(switchImplementationParameter), + SwitchInterfaceAfterScopeRootParameter switchInterfaceAfterScopeRootParameter => _functionResolutionBuilderFactory(this).ScopeRootFunction(switchInterfaceAfterScopeRootParameter), _ => throw new ArgumentOutOfRangeException(nameof(functionParameter)) }; diff --git a/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs b/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs index 8857f80c..b697458d 100644 --- a/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs @@ -2,7 +2,7 @@ namespace MrMeeseeks.DIE.ResolutionBuilding; -internal interface ITransientScopeResolutionBuilder : ITransientScopeImplementationResolutionBuilder +internal interface ITransientScopeResolutionBuilder : ITransientScopeImplementationResolutionBuilder, IRangeResolutionBaseBuilder { bool HasWorkToDo { get; } @@ -23,6 +23,7 @@ internal class TransientScopeResolutionBuilder : RangeResolutionBaseBuilder, ITr private readonly IContainerResolutionBuilder _containerResolutionBuilder; private readonly ITransientScopeInterfaceResolutionBuilder _transientScopeInterfaceResolutionBuilder; private readonly IScopeManager _scopeManager; + private readonly Func _functionResolutionBuilderFactory; private readonly List _rootResolutions = new (); private readonly string _containerReference; private readonly string _containerParameterReference; @@ -42,28 +43,31 @@ internal TransientScopeResolutionBuilder( // dependencies WellKnownTypes wellKnownTypes, - IReferenceGeneratorFactory referenceGeneratorFactory) + IReferenceGeneratorFactory referenceGeneratorFactory, + Func functionResolutionBuilderFactory) : base( name, + checkTypeProperties, + userProvidedScopeElements, wellKnownTypes, - referenceGeneratorFactory, - checkTypeProperties, - userProvidedScopeElements) + referenceGeneratorFactory, + functionResolutionBuilderFactory) { _containerResolutionBuilder = containerResolutionBuilder; _transientScopeInterfaceResolutionBuilder = transientScopeInterfaceResolutionBuilder; _scopeManager = scopeManager; + _functionResolutionBuilderFactory = functionResolutionBuilderFactory; _containerReference = RootReferenceGenerator.Generate("_container"); _containerParameterReference = RootReferenceGenerator.Generate("container"); } - protected override RangedInstanceReferenceResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter) => + public override RangedInstanceReferenceResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter) => _containerResolutionBuilder.CreateContainerInstanceReferenceResolution(parameter, _containerReference); - protected override RangedInstanceReferenceResolution CreateTransientScopeInstanceReferenceResolution(ForConstructorParameter parameter) => + public override RangedInstanceReferenceResolution CreateTransientScopeInstanceReferenceResolution(ForConstructorParameter parameter) => _transientScopeInterfaceResolutionBuilder.CreateTransientScopeInstanceReferenceResolution(parameter, "this"); - protected override TransientScopeRootResolution CreateTransientScopeRootResolution(IScopeRootParameter parameter, INamedTypeSymbol rootType, + public override TransientScopeRootResolution CreateTransientScopeRootResolution(IScopeRootParameter parameter, INamedTypeSymbol rootType, DisposableCollectionResolution disposableCollectionResolution, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) => _scopeManager .GetTransientScopeBuilder(rootType) @@ -74,7 +78,7 @@ protected override TransientScopeRootResolution CreateTransientScopeRootResoluti disposableCollectionResolution, currentParameters); - protected override ScopeRootResolution CreateScopeRootResolution( + public override ScopeRootResolution CreateScopeRootResolution( IScopeRootParameter parameter, INamedTypeSymbol rootType, DisposableCollectionResolution disposableCollectionResolution, @@ -140,9 +144,9 @@ public void DoWork() var resolvable = functionParameter switch { - CreateInterfaceParameter createInterfaceParameter => CreateInterface(createInterfaceParameter), - SwitchImplementationParameter switchImplementationParameter => SwitchImplementation(switchImplementationParameter), - SwitchInterfaceAfterScopeRootParameter switchInterfaceAfterScopeRootParameter => SwitchInterfaceAfterScopeRoot(switchInterfaceAfterScopeRootParameter), + CreateInterfaceParameter createInterfaceParameter => _functionResolutionBuilderFactory(this).ScopeRootFunction(createInterfaceParameter), + SwitchImplementationParameter switchImplementationParameter => _functionResolutionBuilderFactory(this).ScopeRootFunction(switchImplementationParameter), + SwitchInterfaceAfterScopeRootParameter switchInterfaceAfterScopeRootParameter => _functionResolutionBuilderFactory(this).ScopeRootFunction(switchInterfaceAfterScopeRootParameter), _ => throw new ArgumentOutOfRangeException(nameof(functionParameter)) }; diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index 50debc03..33d963d8 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -38,7 +38,10 @@ internal record TaskBaseTypeInitializationResolution( string TypeFullName, string MethodName, string TaskTypeFullName, - string TaskReference) : ITypeInitializationResolution; + string TaskReference) : ITypeInitializationResolution +{ + internal bool Await { get; set; } = true; +} internal record TaskTypeInitializationResolution( string TypeFullName, @@ -201,4 +204,39 @@ internal record DisposalHandling( internal record FieldResolution( string Reference, string TypeFullName, - string FieldName) : Resolvable(Reference, TypeFullName); \ No newline at end of file + string FieldName) : Resolvable(Reference, TypeFullName); + +internal abstract record TaskBaseResolution( + Resolvable WrappedResolvable, + string TaskReference, + string TaskFullName) : Resolvable(TaskReference, TaskFullName); + +internal record TaskFromTaskResolution( + Resolvable WrappedResolvable, + TaskTypeInitializationResolution Initialization, + string TaskReference, + string TaskFullName) : TaskBaseResolution(WrappedResolvable, TaskReference, TaskFullName); +internal record TaskFromValueTaskResolution( + Resolvable WrappedResolvable, + ValueTaskTypeInitializationResolution Initialization, + string TaskReference, + string TaskFullName) : TaskBaseResolution(WrappedResolvable, TaskReference, TaskFullName); +internal record TaskFromSyncResolution( + Resolvable WrappedResolvable, + string TaskReference, + string TaskFullName) : TaskBaseResolution(WrappedResolvable, TaskReference, TaskFullName); + +internal record ValueTaskFromTaskResolution( + Resolvable WrappedResolvable, + TaskTypeInitializationResolution Initialization, + string ValueTaskReference, + string ValueTaskFullName) : TaskBaseResolution(WrappedResolvable, ValueTaskReference, ValueTaskFullName); +internal record ValueTaskFromValueTaskResolution( + Resolvable WrappedResolvable, + ValueTaskTypeInitializationResolution Initialization, + string ValueTaskReference, + string ValueTaskFullName) : TaskBaseResolution(WrappedResolvable, ValueTaskReference, ValueTaskFullName); +internal record ValueTaskFromSyncResolution( + Resolvable WrappedResolvable, + string ValueTaskReference, + string ValueTaskFullName) : TaskBaseResolution(WrappedResolvable, ValueTaskReference, ValueTaskFullName); \ No newline at end of file diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index 6c941b9f..f94157a2 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -47,6 +47,7 @@ IContainerResolutionBuilder ResolutionTreeFactory(IContainerInfo ci) new CheckTypeProperties(new CurrentlyConsideredTypes(containerTypesFromAttributesList, context)), wellKnownTypes, ScopeManagerFactory, + FunctionResolutionBuilderFactory, new UserProvidedScopeElements(ci.ContainerType)); IScopeManager ScopeManagerFactory( @@ -79,7 +80,8 @@ ITransientScopeResolutionBuilder TransientScopeResolutionBuilderFactory( checkTypeProperties, wellKnownTypes, - referenceGeneratorFactory); + referenceGeneratorFactory, + FunctionResolutionBuilderFactory); IScopeResolutionBuilder ScopeResolutionBuilderFactory( string name, IContainerResolutionBuilder containerBuilder, @@ -95,6 +97,14 @@ IScopeResolutionBuilder ScopeResolutionBuilderFactory( checkTypeProperties, wellKnownTypes, + referenceGeneratorFactory, + FunctionResolutionBuilderFactory); + + IFunctionResolutionBuilder FunctionResolutionBuilderFactory( + IRangeResolutionBaseBuilder rangeResolutionBaseBuilder) => new FunctionResolutionBuilder( + rangeResolutionBaseBuilder, + + wellKnownTypes, referenceGeneratorFactory); } IContainerInfo ContainerInfoFactory(INamedTypeSymbol type) => new ContainerInfo(type, wellKnownTypes); diff --git a/Main/WellKnownTypes.cs b/Main/WellKnownTypes.cs index e59a2252..9441e64e 100644 --- a/Main/WellKnownTypes.cs +++ b/Main/WellKnownTypes.cs @@ -1,5 +1,4 @@ -using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration; namespace MrMeeseeks.DIE; @@ -49,6 +48,7 @@ internal record WellKnownTypes( INamedTypeSymbol Action, INamedTypeSymbol Func, INamedTypeSymbol Exception, + INamedTypeSymbol TaskCanceledException, INamedTypeSymbol SemaphoreSlim) { internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellKnownTypes) @@ -72,6 +72,7 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK var action = compilation.GetTypeOrReport("System.Action"); var func = compilation.GetTypeOrReport("System.Func`3"); var exception = compilation.GetTypeOrReport("System.Exception"); + var taskCanceledException = compilation.GetTypeOrReport("System.Threading.Tasks.TaskCanceledException"); var semaphoreSlim = compilation.GetTypeOrReport("System.Threading.SemaphoreSlim"); var spyAggregationAttribute = compilation @@ -161,105 +162,107 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK var filterTypeInitializerAttribute = compilation .GetTypeByMetadataName(typeof(FilterTypeInitializerAttribute).FullName ?? ""); - if (iContainer is null - || spyAggregationAttribute is null - || spyConstructorChoiceAggregationAttribute is null - || implementationAggregationAttribute is null - || transientAggregationAttribute is null - || containerInstanceAggregationAttribute is null - || transientScopeInstanceAggregationAttribute is null - || scopeInstanceAggregationAttribute is null - || transientScopeRootAggregationAttribute is null - || scopeRootAggregationAttribute is null - || decoratorAggregationAttribute is null - || compositeAggregationAttribute is null - || decoratorSequenceChoiceAttribute is null - || constructorChoiceAttribute is null - || typeInitializerAttribute is null - || filterSpyAggregationAttribute is null - || filterSpyConstructorChoiceAggregationAttribute is null - || filterImplementationAggregationAttribute is null - || filterTransientAggregationAttribute is null - || filterContainerInstanceAggregationAttribute is null - || filterTransientScopeInstanceAggregationAttribute is null - || filterScopeInstanceAggregationAttribute is null - || filterTransientScopeRootAggregationAttribute is null - || filterScopeRootAggregationAttribute is null - || filterDecoratorAggregationAttribute is null - || filterCompositeAggregationAttribute is null - || filterDecoratorSequenceChoiceAttribute is null - || filterConstructorChoiceAttribute is null - || filterTypeInitializerAttribute is null - || customScopeForRootTypesAttribute is null - || iDisposable is null - || iAsyncDisposable is null - || lazy1 is null - || valueTask is null - || task is null - || valueTask1 is null - || task1 is null - || objectDisposedException is null - || iEnumerable1 is null - || iReadOnlyCollection1 is null - || iReadOnlyList1 is null - || concurrentBagOfDisposable is null - || action is null - || func is null - || exception is null - || semaphoreSlim is null) + if (iContainer is not null + && spyAggregationAttribute is not null + && spyConstructorChoiceAggregationAttribute is not null + && implementationAggregationAttribute is not null + && transientAggregationAttribute is not null + && containerInstanceAggregationAttribute is not null + && transientScopeInstanceAggregationAttribute is not null + && scopeInstanceAggregationAttribute is not null + && transientScopeRootAggregationAttribute is not null + && scopeRootAggregationAttribute is not null + && decoratorAggregationAttribute is not null + && compositeAggregationAttribute is not null + && decoratorSequenceChoiceAttribute is not null + && constructorChoiceAttribute is not null + && typeInitializerAttribute is not null + && filterSpyAggregationAttribute is not null + && filterSpyConstructorChoiceAggregationAttribute is not null + && filterImplementationAggregationAttribute is not null + && filterTransientAggregationAttribute is not null + && filterContainerInstanceAggregationAttribute is not null + && filterTransientScopeInstanceAggregationAttribute is not null + && filterScopeInstanceAggregationAttribute is not null + && filterTransientScopeRootAggregationAttribute is not null + && filterScopeRootAggregationAttribute is not null + && filterDecoratorAggregationAttribute is not null + && filterCompositeAggregationAttribute is not null + && filterDecoratorSequenceChoiceAttribute is not null + && filterConstructorChoiceAttribute is not null + && filterTypeInitializerAttribute is not null + && customScopeForRootTypesAttribute is not null + && iDisposable is not null + && iAsyncDisposable is not null + && lazy1 is not null + && valueTask is not null + && task is not null + && valueTask1 is not null + && task1 is not null + && taskCanceledException is not null + && objectDisposedException is not null + && iEnumerable1 is not null + && iReadOnlyCollection1 is not null + && iReadOnlyList1 is not null + && concurrentBagOfDisposable is not null + && action is not null + && func is not null + && exception is not null + && semaphoreSlim is not null) { - wellKnownTypes = null!; - return false; - } - wellKnownTypes = new WellKnownTypes( - Container: iContainer, - SpyAggregationAttribute: spyAggregationAttribute, - SpyConstructorChoiceAggregationAttribute: spyConstructorChoiceAggregationAttribute, - ImplementationAggregationAttribute: implementationAggregationAttribute, - TransientAggregationAttribute: transientAggregationAttribute, - ContainerInstanceAggregationAttribute: containerInstanceAggregationAttribute, - TransientScopeInstanceAggregationAttribute: transientScopeInstanceAggregationAttribute, - ScopeInstanceAggregationAttribute: scopeInstanceAggregationAttribute, - TransientScopeRootAggregationAttribute: transientScopeRootAggregationAttribute, - ScopeRootAggregationAttribute: scopeRootAggregationAttribute, - DecoratorAggregationAttribute: decoratorAggregationAttribute, - CompositeAggregationAttribute: compositeAggregationAttribute, - DecoratorSequenceChoiceAttribute: decoratorSequenceChoiceAttribute, - ConstructorChoiceAttribute: constructorChoiceAttribute, - TypeInitializerAttribute: typeInitializerAttribute, - FilterSpyAggregationAttribute: filterSpyAggregationAttribute, - FilterSpyConstructorChoiceAggregationAttribute: filterSpyConstructorChoiceAggregationAttribute, - FilterImplementationAggregationAttribute: filterImplementationAggregationAttribute, - FilterTransientAggregationAttribute: filterTransientAggregationAttribute, - FilterContainerInstanceAggregationAttribute: filterContainerInstanceAggregationAttribute, - FilterTransientScopeInstanceAggregationAttribute: filterTransientScopeInstanceAggregationAttribute, - FilterScopeInstanceAggregationAttribute: filterScopeInstanceAggregationAttribute, - FilterTransientScopeRootAggregationAttribute: filterTransientScopeRootAggregationAttribute, - FilterScopeRootAggregationAttribute: filterScopeRootAggregationAttribute, - FilterDecoratorAggregationAttribute: filterDecoratorAggregationAttribute, - FilterCompositeAggregationAttribute: filterCompositeAggregationAttribute, - FilterDecoratorSequenceChoiceAttribute: filterDecoratorSequenceChoiceAttribute, - FilterConstructorChoiceAttribute: filterConstructorChoiceAttribute, - FilterTypeInitializerAttribute: filterTypeInitializerAttribute, - CustomScopeForRootTypesAttribute: customScopeForRootTypesAttribute, - Disposable: iDisposable, - AsyncDisposable: iAsyncDisposable, - Lazy1: lazy1, - ValueTask: valueTask, - ValueTask1: valueTask1, - Task: task, - Task1: task1, - ObjectDisposedException: objectDisposedException, - Enumerable1: iEnumerable1, - ReadOnlyCollection1: iReadOnlyCollection1, - ReadOnlyList1: iReadOnlyList1, - ConcurrentBagOfDisposable: concurrentBagOfDisposable, - Action: action, - Func: func, - Exception: exception, - SemaphoreSlim: semaphoreSlim); - - return true; + wellKnownTypes = new WellKnownTypes( + Container: iContainer, + SpyAggregationAttribute: spyAggregationAttribute, + SpyConstructorChoiceAggregationAttribute: spyConstructorChoiceAggregationAttribute, + ImplementationAggregationAttribute: implementationAggregationAttribute, + TransientAggregationAttribute: transientAggregationAttribute, + ContainerInstanceAggregationAttribute: containerInstanceAggregationAttribute, + TransientScopeInstanceAggregationAttribute: transientScopeInstanceAggregationAttribute, + ScopeInstanceAggregationAttribute: scopeInstanceAggregationAttribute, + TransientScopeRootAggregationAttribute: transientScopeRootAggregationAttribute, + ScopeRootAggregationAttribute: scopeRootAggregationAttribute, + DecoratorAggregationAttribute: decoratorAggregationAttribute, + CompositeAggregationAttribute: compositeAggregationAttribute, + DecoratorSequenceChoiceAttribute: decoratorSequenceChoiceAttribute, + ConstructorChoiceAttribute: constructorChoiceAttribute, + TypeInitializerAttribute: typeInitializerAttribute, + FilterSpyAggregationAttribute: filterSpyAggregationAttribute, + FilterSpyConstructorChoiceAggregationAttribute: filterSpyConstructorChoiceAggregationAttribute, + FilterImplementationAggregationAttribute: filterImplementationAggregationAttribute, + FilterTransientAggregationAttribute: filterTransientAggregationAttribute, + FilterContainerInstanceAggregationAttribute: filterContainerInstanceAggregationAttribute, + FilterTransientScopeInstanceAggregationAttribute: filterTransientScopeInstanceAggregationAttribute, + FilterScopeInstanceAggregationAttribute: filterScopeInstanceAggregationAttribute, + FilterTransientScopeRootAggregationAttribute: filterTransientScopeRootAggregationAttribute, + FilterScopeRootAggregationAttribute: filterScopeRootAggregationAttribute, + FilterDecoratorAggregationAttribute: filterDecoratorAggregationAttribute, + FilterCompositeAggregationAttribute: filterCompositeAggregationAttribute, + FilterDecoratorSequenceChoiceAttribute: filterDecoratorSequenceChoiceAttribute, + FilterConstructorChoiceAttribute: filterConstructorChoiceAttribute, + FilterTypeInitializerAttribute: filterTypeInitializerAttribute, + CustomScopeForRootTypesAttribute: customScopeForRootTypesAttribute, + Disposable: iDisposable, + AsyncDisposable: iAsyncDisposable, + Lazy1: lazy1, + ValueTask: valueTask, + ValueTask1: valueTask1, + Task: task, + Task1: task1, + ObjectDisposedException: objectDisposedException, + Enumerable1: iEnumerable1, + ReadOnlyCollection1: iReadOnlyCollection1, + ReadOnlyList1: iReadOnlyList1, + ConcurrentBagOfDisposable: concurrentBagOfDisposable, + Action: action, + Func: func, + Exception: exception, + TaskCanceledException: taskCanceledException, + SemaphoreSlim: semaphoreSlim); + return true; + } + + wellKnownTypes = null!; + return false; } } \ No newline at end of file diff --git a/Sample/Context.cs b/Sample/Context.cs index ae6c5933..6927e3f7 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -1,18 +1,51 @@ -using System.Threading.Tasks; +using System.Collections.Generic; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Sample; -namespace MrMeeseeks.DIE.Sample; -internal class Dependency : ITaskTypeInitializer +namespace MrMeeseeks.DIE.Test.Async.TaskCollection; + +internal interface IInterface +{ + bool IsInitialized { get; } +} + +internal class DependencyA : ITaskTypeInitializer, IInterface +{ + public bool IsInitialized { get; private set; } + + async Task ITaskTypeInitializer.InitializeAsync() + { + await Task.Delay(500).ConfigureAwait(false); + IsInitialized = true; + } +} + +internal class DependencyB : IValueTaskTypeInitializer, IInterface { public bool IsInitialized { get; private set; } - Task ITaskTypeInitializer.InitializeAsync() + async ValueTask IValueTaskTypeInitializer.InitializeAsync() { + await Task.Delay(500).ConfigureAwait(false); IsInitialized = true; - return Task.CompletedTask; } } -internal partial class Container - : IContainer +internal class DependencyC : ITypeInitializer, IInterface +{ + public bool IsInitialized { get; private set; } + + void ITypeInitializer.Initialize() + { + IsInitialized = true; + } +} + +internal class DependencyD : IInterface +{ + public bool IsInitialized => true; +} + +internal partial class Container : IContainer>> { } \ No newline at end of file diff --git a/Sample/Program.cs b/Sample/Program.cs index 101a171b..6d63b683 100644 --- a/Sample/Program.cs +++ b/Sample/Program.cs @@ -1,7 +1,15 @@ using System; +using System.Collections.Generic; +using System.Threading.Tasks; using MrMeeseeks.DIE; -using MrMeeseeks.DIE.Sample; +using MrMeeseeks.DIE.Test.Async.TaskCollection; -Console.WriteLine("Hello, world!"); -var container = new Container(); -Console.WriteLine(((IContainer) container).Resolve()); \ No newline at end of file +internal class Program +{ + private static void Main() + { + Console.WriteLine("Hello, world!"); + var container = new Container(); + Console.WriteLine(((IContainer>>) container).Resolve()); + } +} \ No newline at end of file diff --git a/Sample/Sample.csproj b/Sample/Sample.csproj index 2f5c9bad..b70bf202 100644 --- a/Sample/Sample.csproj +++ b/Sample/Sample.csproj @@ -2,7 +2,7 @@ Exe - net6.0 + net5.0 MrMeeseeks.DIE.Sample true diff --git a/Test/Async/WrappedDependency/DecorationChaining.cs b/Test/Async/WrappedDependency/DecorationChaining.cs new file mode 100644 index 00000000..02027672 --- /dev/null +++ b/Test/Async/WrappedDependency/DecorationChaining.cs @@ -0,0 +1,64 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Async.WrappedDependency.DecorationChaining; + +internal interface IInterface +{ + bool IsInitialized { get; } +} + +internal class Dependency : ITaskTypeInitializer, IInterface +{ + public bool IsInitialized { get; private set; } + + async Task ITaskTypeInitializer.InitializeAsync() + { + await Task.Delay(500).ConfigureAwait(false); + IsInitialized = true; + } +} + +internal class DecoratorA : ITypeInitializer, IInterface, IDecorator +{ + private readonly Task _task; + public bool IsInitialized { get; private set; } + + internal DecoratorA(Task task) => _task = task; + + void ITypeInitializer.Initialize() + { + _task.Wait(); + IsInitialized = true; + } +} + +internal class DecoratorB : IValueTaskTypeInitializer, IInterface, IDecorator +{ + public bool IsInitialized { get; private set; } + + internal DecoratorB(IInterface _) {} + + async ValueTask IValueTaskTypeInitializer.InitializeAsync() + { + await Task.Delay(500).ConfigureAwait(false); + IsInitialized = true; + } +} + +[DecoratorSequenceChoice(typeof(IInterface), typeof(DecoratorA), typeof(DecoratorB))] +internal partial class Container : IContainer> +{ +} + +public class Tests +{ + [Fact] + public async Task Test() + { + using var container = new Container(); + var instance = await ((IContainer>) container).Resolve().ConfigureAwait(false); + Assert.True(instance.IsInitialized); + } +} \ No newline at end of file diff --git a/Test/Async/WrappedDependency/Func.cs b/Test/Async/WrappedDependency/Func.cs new file mode 100644 index 00000000..b4e1b6fc --- /dev/null +++ b/Test/Async/WrappedDependency/Func.cs @@ -0,0 +1,32 @@ +using System; +using System.Threading.Tasks; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Async.WrappedDependency.Func; + + +internal class Dependency : ITaskTypeInitializer +{ + public bool IsInitialized { get; private set; } + + async Task ITaskTypeInitializer.InitializeAsync() + { + await Task.Delay(500).ConfigureAwait(false); + IsInitialized = true; + } +} + +internal partial class Container : IContainer>> +{ +} + +public class Tests +{ + [Fact] + public async Task Test() + { + using var container = new Container(); + var instance = ((IContainer>>) container).Resolve(); + Assert.True((await instance().ConfigureAwait(false)).IsInitialized); + } +} \ No newline at end of file diff --git a/Test/Async/WrappedDependency/Lazy.cs b/Test/Async/WrappedDependency/Lazy.cs new file mode 100644 index 00000000..2dbf0844 --- /dev/null +++ b/Test/Async/WrappedDependency/Lazy.cs @@ -0,0 +1,32 @@ +using System; +using System.Threading.Tasks; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Async.WrappedDependency.Lazy; + + +internal class Dependency : ITaskTypeInitializer +{ + public bool IsInitialized { get; private set; } + + async Task ITaskTypeInitializer.InitializeAsync() + { + await Task.Delay(500).ConfigureAwait(false); + IsInitialized = true; + } +} + +internal partial class Container : IContainer>> +{ +} + +public class Tests +{ + [Fact] + public async Task Test() + { + using var container = new Container(); + var instance = ((IContainer>>) container).Resolve(); + Assert.True((await instance.Value.ConfigureAwait(false)).IsInitialized); + } +} \ No newline at end of file diff --git a/Test/Async/WrappedDependency/SyncToTask.cs b/Test/Async/WrappedDependency/SyncToTask.cs new file mode 100644 index 00000000..63f2bb76 --- /dev/null +++ b/Test/Async/WrappedDependency/SyncToTask.cs @@ -0,0 +1,29 @@ +using System.Threading.Tasks; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Async.WrappedDependency.SyncToTask; + +internal class Dependency : ITypeInitializer +{ + public bool IsInitialized { get; private set; } + + void ITypeInitializer.Initialize() + { + IsInitialized = true; + } +} + +internal partial class Container : IContainer> +{ +} + +public class Tests +{ + [Fact] + public async Task Test() + { + using var container = new Container(); + var instance = await ((IContainer>) container).Resolve().ConfigureAwait(false); + Assert.True(instance.IsInitialized); + } +} \ No newline at end of file diff --git a/Test/Async/WrappedDependency/SyncToValueTask.cs b/Test/Async/WrappedDependency/SyncToValueTask.cs new file mode 100644 index 00000000..78abf4b0 --- /dev/null +++ b/Test/Async/WrappedDependency/SyncToValueTask.cs @@ -0,0 +1,29 @@ +using System.Threading.Tasks; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Async.WrappedDependency.SyncToValueTask; + +internal class Dependency : ITypeInitializer +{ + public bool IsInitialized { get; private set; } + + void ITypeInitializer.Initialize() + { + IsInitialized = true; + } +} + +internal partial class Container : IContainer> +{ +} + +public class Tests +{ + [Fact] + public async Task Test() + { + using var container = new Container(); + var instance = await ((IContainer>) container).Resolve().ConfigureAwait(false); + Assert.True(instance.IsInitialized); + } +} \ No newline at end of file diff --git a/Test/Async/WrappedDependency/TaskCollection.cs b/Test/Async/WrappedDependency/TaskCollection.cs new file mode 100644 index 00000000..c17f69c7 --- /dev/null +++ b/Test/Async/WrappedDependency/TaskCollection.cs @@ -0,0 +1,65 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Async.WrappedDependency.TaskCollection; + +internal interface IInterface +{ + bool IsInitialized { get; } +} + +internal class DependencyA : ITaskTypeInitializer, IInterface +{ + public bool IsInitialized { get; private set; } + + async Task ITaskTypeInitializer.InitializeAsync() + { + await Task.Delay(500).ConfigureAwait(false); + IsInitialized = true; + } +} + +internal class DependencyB : IValueTaskTypeInitializer, IInterface +{ + public bool IsInitialized { get; private set; } + + async ValueTask IValueTaskTypeInitializer.InitializeAsync() + { + await Task.Delay(500).ConfigureAwait(false); + IsInitialized = true; + } +} + +internal class DependencyC : ITypeInitializer, IInterface +{ + public bool IsInitialized { get; private set; } + + void ITypeInitializer.Initialize() + { + IsInitialized = true; + } +} + +internal class DependencyD : IInterface +{ + public bool IsInitialized => true; +} + +internal partial class Container : IContainer>> +{ +} + +public class Tests +{ + [Fact] + public async Task Test() + { + using var container = new Container(); + var instance = ((IContainer>>) container).Resolve(); + Assert.Equal(4, instance.Count); + await Task.WhenAll(instance).ConfigureAwait(false); + foreach (var task in instance) + Assert.True((await task.ConfigureAwait(false)).IsInitialized); + } +} \ No newline at end of file diff --git a/Test/Async/WrappedDependency/TaskComposition.cs b/Test/Async/WrappedDependency/TaskComposition.cs new file mode 100644 index 00000000..214a453b --- /dev/null +++ b/Test/Async/WrappedDependency/TaskComposition.cs @@ -0,0 +1,84 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Async.WrappedDependency.TaskComposition; + +internal interface IInterface +{ + bool IsInitialized { get; } +} + +internal class DependencyA : ITaskTypeInitializer, IInterface +{ + public bool IsInitialized { get; private set; } + + async Task ITaskTypeInitializer.InitializeAsync() + { + await Task.Delay(500).ConfigureAwait(false); + IsInitialized = true; + } +} + +internal class DependencyB : IValueTaskTypeInitializer, IInterface +{ + public bool IsInitialized { get; private set; } + + async ValueTask IValueTaskTypeInitializer.InitializeAsync() + { + await Task.Delay(500).ConfigureAwait(false); + IsInitialized = true; + } +} + +internal class DependencyC : ITypeInitializer, IInterface +{ + public bool IsInitialized { get; private set; } + + void ITypeInitializer.Initialize() + { + IsInitialized = true; + } +} + +internal class DependencyD : IInterface +{ + public bool IsInitialized => true; +} + +internal class Composite : ITaskTypeInitializer, IInterface, IComposite +{ + private readonly IReadOnlyList> _composition; + + internal Composite( + IReadOnlyList> composition) => + _composition = composition; + + public async Task InitializeAsync() + { + await Task.WhenAll(_composition).ConfigureAwait(false); + await Task.Delay(500).ConfigureAwait(false); + IsInitialized = true; + } + + public bool IsInitialized { get; private set; } + + public int Count => _composition.Count; +} + +internal partial class Container : IContainer> +{ +} + +public class Tests +{ + [Fact] + public async Task Test() + { + using var container = new Container(); + var instance = await ((IContainer>) container).Resolve().ConfigureAwait(false); + Assert.IsType(instance); + Assert.Equal(4, ((Composite) instance).Count); + Assert.True(instance.IsInitialized); + } +} \ No newline at end of file diff --git a/Test/TaskTypeInitializationTests.cs b/Test/Async/WrappedDependency/TaskToTask.cs similarity index 62% rename from Test/TaskTypeInitializationTests.cs rename to Test/Async/WrappedDependency/TaskToTask.cs index f8100410..caefacaa 100644 --- a/Test/TaskTypeInitializationTests.cs +++ b/Test/Async/WrappedDependency/TaskToTask.cs @@ -2,7 +2,7 @@ using System.Threading.Tasks; using Xunit; -namespace MrMeeseeks.DIE.Test.TaskTypeInitializationTests; +namespace MrMeeseeks.DIE.Test.Async.WrappedDependency.TaskToTask; internal class Dependency : ITaskTypeInitializer { @@ -15,17 +15,17 @@ async Task ITaskTypeInitializer.InitializeAsync() } } -internal partial class Container : IContainer +internal partial class Container : IContainer> { } -public partial class Tests +public class Tests { [Fact] - public void Test() + public async Task Test() { using var container = new Container(); - var instance = ((IContainer) container).Resolve(); + var instance = await ((IContainer>) container).Resolve().ConfigureAwait(false); Assert.True(instance.IsInitialized); } } \ No newline at end of file diff --git a/Test/Async/WrappedDependency/TaskToValueTask.cs b/Test/Async/WrappedDependency/TaskToValueTask.cs new file mode 100644 index 00000000..76797de2 --- /dev/null +++ b/Test/Async/WrappedDependency/TaskToValueTask.cs @@ -0,0 +1,31 @@ +using System; +using System.Threading.Tasks; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Async.WrappedDependency.TaskToValueTask; + +internal class Dependency : ITaskTypeInitializer +{ + public bool IsInitialized { get; private set; } + + async Task ITaskTypeInitializer.InitializeAsync() + { + await Task.Delay(TimeSpan.FromMilliseconds(500)).ConfigureAwait(false); + IsInitialized = true; + } +} + +internal partial class Container : IContainer> +{ +} + +public class Tests +{ + [Fact] + public async Task Test() + { + using var container = new Container(); + var instance = await ((IContainer>) container).Resolve().ConfigureAwait(false); + Assert.True(instance.IsInitialized); + } +} \ No newline at end of file diff --git a/Test/Async/WrappedDependency/ValueTaskCollection.cs b/Test/Async/WrappedDependency/ValueTaskCollection.cs new file mode 100644 index 00000000..886d6492 --- /dev/null +++ b/Test/Async/WrappedDependency/ValueTaskCollection.cs @@ -0,0 +1,64 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Async.WrappedDependency.ValueTaskCollection; + +internal interface IInterface +{ + bool IsInitialized { get; } +} + +internal class DependencyA : ITaskTypeInitializer, IInterface +{ + public bool IsInitialized { get; private set; } + + async Task ITaskTypeInitializer.InitializeAsync() + { + await Task.Delay(500).ConfigureAwait(false); + IsInitialized = true; + } +} + +internal class DependencyB : IValueTaskTypeInitializer, IInterface +{ + public bool IsInitialized { get; private set; } + + async ValueTask IValueTaskTypeInitializer.InitializeAsync() + { + await Task.Delay(500).ConfigureAwait(false); + IsInitialized = true; + } +} + +internal class DependencyC : ITypeInitializer, IInterface +{ + public bool IsInitialized { get; private set; } + + void ITypeInitializer.Initialize() + { + IsInitialized = true; + } +} + +internal class DependencyD : IInterface +{ + public bool IsInitialized => true; +} + +internal partial class Container : IContainer>> +{ +} + +public class Tests +{ + [Fact] + public async Task Test() + { + using var container = new Container(); + var instance = ((IContainer>>) container).Resolve(); + Assert.Equal(4, instance.Count); + foreach (var task in instance) + Assert.True((await task.ConfigureAwait(false)).IsInitialized); + } +} \ No newline at end of file diff --git a/Test/Async/WrappedDependency/ValueTaskComposition.cs b/Test/Async/WrappedDependency/ValueTaskComposition.cs new file mode 100644 index 00000000..5400afe9 --- /dev/null +++ b/Test/Async/WrappedDependency/ValueTaskComposition.cs @@ -0,0 +1,84 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Async.WrappedDependency.ValueTaskComposition; + +internal interface IInterface +{ + bool IsInitialized { get; } +} + +internal class DependencyA : ITaskTypeInitializer, IInterface +{ + public bool IsInitialized { get; private set; } + + async Task ITaskTypeInitializer.InitializeAsync() + { + await Task.Delay(500).ConfigureAwait(false); + IsInitialized = true; + } +} + +internal class DependencyB : IValueTaskTypeInitializer, IInterface +{ + public bool IsInitialized { get; private set; } + + async ValueTask IValueTaskTypeInitializer.InitializeAsync() + { + await Task.Delay(500).ConfigureAwait(false); + IsInitialized = true; + } +} + +internal class DependencyC : ITypeInitializer, IInterface +{ + public bool IsInitialized { get; private set; } + + void ITypeInitializer.Initialize() + { + IsInitialized = true; + } +} + +internal class DependencyD : IInterface +{ + public bool IsInitialized => true; +} + +internal class Composite : ITaskTypeInitializer, IInterface, IComposite +{ + private readonly IReadOnlyList> _composition; + + internal Composite( + IReadOnlyList> composition) => + _composition = composition; + + public async Task InitializeAsync() + { + await Task.WhenAll(_composition).ConfigureAwait(false); + await Task.Delay(500).ConfigureAwait(false); + IsInitialized = true; + } + + public bool IsInitialized { get; private set; } + + public int Count => _composition.Count; +} + +internal partial class Container : IContainer> +{ +} + +public class Tests +{ + [Fact] + public async Task Test() + { + using var container = new Container(); + var instance = await ((IContainer>) container).Resolve().ConfigureAwait(false); + Assert.IsType(instance); + Assert.Equal(4, ((Composite) instance).Count); + Assert.True(instance.IsInitialized); + } +} \ No newline at end of file diff --git a/Test/ValueTaskTypeInitializationTests.cs b/Test/Async/WrappedDependency/ValueTaskToTask.cs similarity index 62% rename from Test/ValueTaskTypeInitializationTests.cs rename to Test/Async/WrappedDependency/ValueTaskToTask.cs index ed40f8b2..68a8af87 100644 --- a/Test/ValueTaskTypeInitializationTests.cs +++ b/Test/Async/WrappedDependency/ValueTaskToTask.cs @@ -2,7 +2,7 @@ using System.Threading.Tasks; using Xunit; -namespace MrMeeseeks.DIE.Test.ValueTaskTypeInitializationTests; +namespace MrMeeseeks.DIE.Test.Async.WrappedDependency.ValueTaskToTask; internal class Dependency : IValueTaskTypeInitializer { @@ -15,17 +15,17 @@ async ValueTask IValueTaskTypeInitializer.InitializeAsync() } } -internal partial class Container : IContainer +internal partial class Container : IContainer> { } -public partial class Tests +public class Tests { [Fact] - public void Test() + public async Task Test() { using var container = new Container(); - var instance = ((IContainer) container).Resolve(); + var instance = await ((IContainer>) container).Resolve().ConfigureAwait(false); Assert.True(instance.IsInitialized); } } \ No newline at end of file diff --git a/Test/Async/WrappedDependency/ValueTaskToValueTask.cs b/Test/Async/WrappedDependency/ValueTaskToValueTask.cs new file mode 100644 index 00000000..d8a26afe --- /dev/null +++ b/Test/Async/WrappedDependency/ValueTaskToValueTask.cs @@ -0,0 +1,31 @@ +using System; +using System.Threading.Tasks; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Async.WrappedDependency.ValueTaskToValueTask; + +internal class Dependency : IValueTaskTypeInitializer +{ + public bool IsInitialized { get; private set; } + + async ValueTask IValueTaskTypeInitializer.InitializeAsync() + { + await Task.Delay(TimeSpan.FromMilliseconds(500)).ConfigureAwait(false); + IsInitialized = true; + } +} + +internal partial class Container : IContainer> +{ +} + +public class Tests +{ + [Fact] + public async Task Test() + { + using var container = new Container(); + var instance = await ((IContainer>) container).Resolve().ConfigureAwait(false); + Assert.True(instance.IsInitialized); + } +} \ No newline at end of file From 0e64f03577faf84e22759d1f9342a1308a2064be Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Fri, 18 Feb 2022 22:35:50 +0100 Subject: [PATCH 048/162] Switching from container interface to container attribute --- Main/CodeBuilding/RangeCodeBaseBuilder.cs | 2 +- Main/Configuration/Attributes.cs | 8 ++++ Main/ContainerInfo.cs | 20 ++++---- Main/ExecuteImpl.cs | 2 +- Main/IContainer.cs | 6 --- .../ContainerResolutionBuilder.cs | 6 +-- .../ScopeResolutionBuilder.cs | 1 - .../TransientScopeResolutionBuilder.cs | 1 - Main/ResolutionTreeItem.cs | 1 - Main/WellKnownTypes.cs | 16 ++++--- Sample/Context.cs | 4 +- Sample/Program.cs | 5 +- .../WrappedDependency/DecorationChaining.cs | 5 +- Test/Async/WrappedDependency/Func.cs | 6 ++- Test/Async/WrappedDependency/Lazy.cs | 7 ++- Test/Async/WrappedDependency/SyncToTask.cs | 6 ++- .../WrappedDependency/SyncToValueTask.cs | 7 ++- .../Async/WrappedDependency/TaskCollection.cs | 6 ++- .../WrappedDependency/TaskComposition.cs | 6 ++- Test/Async/WrappedDependency/TaskToTask.cs | 6 ++- .../WrappedDependency/TaskToValueTask.cs | 6 ++- .../WrappedDependency/ValueTaskCollection.cs | 6 ++- .../WrappedDependency/ValueTaskComposition.cs | 6 ++- .../WrappedDependency/ValueTaskToTask.cs | 6 ++- .../WrappedDependency/ValueTaskToValueTask.cs | 6 ++- Test/CompositeTests.cs | 46 ++++++++++--------- Test/ConstructorChoiceTests.cs | 8 ++-- Test/ConstructorTests.cs | 8 ++-- Test/DecoratorTests.cs | 29 +++++++----- Test/FactoryTests.cs | 10 ++-- Test/ImplementationAggregationTests.cs | 5 +- Test/InstanceTests.cs | 6 ++- Test/PropertyTests.cs | 7 ++- ...opeSpecificAttributesTestsWithDecorator.cs | 18 +++----- ...cAttributesTestsWithImplementationLists.cs | 9 ++-- ...cificAttributesTestsWithImplementations.cs | 9 ++-- Test/SyncTypeInitializationTest.cs | 5 +- Test/TransientScopeInstanceTests.cs | 40 ++++++---------- Test/ValueTupleTests.cs | 21 +++++---- 39 files changed, 204 insertions(+), 168 deletions(-) delete mode 100644 Main/IContainer.cs diff --git a/Main/CodeBuilding/RangeCodeBaseBuilder.cs b/Main/CodeBuilding/RangeCodeBaseBuilder.cs index 42ccd7e2..e2c0ec0b 100644 --- a/Main/CodeBuilding/RangeCodeBaseBuilder.cs +++ b/Main/CodeBuilding/RangeCodeBaseBuilder.cs @@ -92,7 +92,7 @@ private StringBuilder GenerateResolutionFunction( { var parameter = string.Join(",", resolution.Parameter.Select(r => $"{r.TypeFullName} {r.Reference}")); stringBuilder = stringBuilder - .AppendLine($"{resolution.AccessModifier} {resolution.TypeFullName} {resolution.ExplicitImplementationFullName}{(string.IsNullOrWhiteSpace(resolution.ExplicitImplementationFullName) ? "" : ".")}{resolution.Reference}({parameter})") + .AppendLine($"{resolution.AccessModifier} {resolution.TypeFullName} {resolution.Reference}({parameter})") .AppendLine($"{{") .AppendLine($"if (this.{resolution.DisposalHandling.DisposedPropertyReference}) throw new {WellKnownTypes.ObjectDisposedException}(nameof({resolution.RangeName}));"); diff --git a/Main/Configuration/Attributes.cs b/Main/Configuration/Attributes.cs index c9ca59e8..6dc78f7f 100644 --- a/Main/Configuration/Attributes.cs +++ b/Main/Configuration/Attributes.cs @@ -185,4 +185,12 @@ public FilterTypeInitializerAttribute(Type type) { } } + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class MultiContainerAttribute : Attribute +{ + public MultiContainerAttribute(params Type[] types) + { + } +} // ReSharper enable UnusedParameter.Local \ No newline at end of file diff --git a/Main/ContainerInfo.cs b/Main/ContainerInfo.cs index a436212d..9e8e1e86 100644 --- a/Main/ContainerInfo.cs +++ b/Main/ContainerInfo.cs @@ -25,17 +25,15 @@ internal ContainerInfo( ContainerType = containerClass; ResolutionRootTypes = containerClass - .AllInterfaces - .Where(x => x.OriginalDefinition.Equals(wellKnowTypes.Container, SymbolEqualityComparer.Default)) - .Select(nts => - { - var typeParameterSymbol = nts.TypeArguments.Single(); - if (typeParameterSymbol is INamedTypeSymbol { IsUnboundGenericType: false } type && type.IsAccessibleInternally()) - { - return typeParameterSymbol; - } - return null; - }) + .GetAttributes() + .Where(ad => wellKnowTypes.MultiContainerAttribute.Equals(ad.AttributeClass, SymbolEqualityComparer.Default)) + .SelectMany(ad => ad.ConstructorArguments + .Where(tc => tc.Kind == TypedConstantKind.Type) + .OfType() + .Concat(ad.ConstructorArguments.SelectMany(ca => ca.Kind is TypedConstantKind.Array + ? (IEnumerable)ca.Values + : Array.Empty()))) + .Select(tc => tc.Value as INamedTypeSymbol) .OfType() .ToList(); diff --git a/Main/ExecuteImpl.cs b/Main/ExecuteImpl.cs index 807fb656..85a36858 100644 --- a/Main/ExecuteImpl.cs +++ b/Main/ExecuteImpl.cs @@ -53,7 +53,7 @@ public void Execute() .Select(x => semanticModel.GetDeclaredSymbol(x)) .Where(x => x is not null) .OfType() - .Where(x => x.AllInterfaces.Any(x => x.OriginalDefinition.Equals(_wellKnownTypes.Container, SymbolEqualityComparer.Default))) + .Where(x => x.GetAttributes().Any(ad => _wellKnownTypes.MultiContainerAttribute.Equals(ad.AttributeClass, SymbolEqualityComparer.Default))) .ToList(); foreach (var namedTypeSymbol in containerClasses) { diff --git a/Main/IContainer.cs b/Main/IContainer.cs deleted file mode 100644 index 5f970d6f..00000000 --- a/Main/IContainer.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace MrMeeseeks.DIE; - -public interface IContainer -{ - T Resolve(); -} \ No newline at end of file diff --git a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs index 74577a2f..ae416d5b 100644 --- a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs @@ -54,16 +54,16 @@ internal ContainerResolutionBuilder( public void AddCreateResolveFunctions(IReadOnlyList rootTypes) { + var i = 0; foreach (var typeSymbol in rootTypes) _rootResolutions.Add(new RootResolutionFunction( - nameof(IContainer.Resolve), + $"Create{i++}", typeSymbol.FullName(), - "", + "public", _functionResolutionBuilderFactory(this).ResolveFunction(new SwitchTypeParameter( typeSymbol, Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>())), Array.Empty(), - WellKnownTypes.Container.Construct(typeSymbol).FullName(), _containerInfo.Name, DisposalHandling)); } diff --git a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs index 74a788b7..e0e36115 100644 --- a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs @@ -166,7 +166,6 @@ public void DoWork() "internal", resolvable, parameter, - "", Name, DisposalHandling)); } diff --git a/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs b/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs index b697458d..f264f426 100644 --- a/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs @@ -156,7 +156,6 @@ public void DoWork() "internal", resolvable, parameter, - "", Name, DisposalHandling)); } diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index 33d963d8..e76b321b 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -12,7 +12,6 @@ internal record RootResolutionFunction( string AccessModifier, Resolvable Resolvable, IReadOnlyList Parameter, - string ExplicitImplementationFullName, string RangeName, DisposalHandling DisposalHandling) : Resolvable(Reference, TypeFullName); diff --git a/Main/WellKnownTypes.cs b/Main/WellKnownTypes.cs index 9441e64e..000e50c8 100644 --- a/Main/WellKnownTypes.cs +++ b/Main/WellKnownTypes.cs @@ -3,7 +3,6 @@ namespace MrMeeseeks.DIE; internal record WellKnownTypes( - INamedTypeSymbol Container, INamedTypeSymbol SpyAggregationAttribute, INamedTypeSymbol SpyConstructorChoiceAggregationAttribute, INamedTypeSymbol ImplementationAggregationAttribute, @@ -33,6 +32,7 @@ internal record WellKnownTypes( INamedTypeSymbol FilterConstructorChoiceAttribute, INamedTypeSymbol FilterTypeInitializerAttribute, INamedTypeSymbol CustomScopeForRootTypesAttribute, + INamedTypeSymbol MultiContainerAttribute, INamedTypeSymbol Disposable, INamedTypeSymbol AsyncDisposable, INamedTypeSymbol Lazy1, @@ -53,7 +53,6 @@ internal record WellKnownTypes( { internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellKnownTypes) { - var iContainer = compilation.GetTypeOrReport("MrMeeseeks.DIE.IContainer`1"); var iDisposable = compilation.GetTypeOrReport("System.IDisposable"); var iAsyncDisposable = compilation.GetTypeOrReport("System.IAsyncDisposable"); var lazy1 = compilation.GetTypeOrReport("System.Lazy`1"); @@ -154,16 +153,18 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK .GetTypeByMetadataName(typeof(FilterConstructorChoiceAttribute).FullName ?? ""); var customScopeForRootTypesAttribute = compilation - .GetTypeByMetadataName(typeof(CustomScopeForRootTypesAttribute).FullName ?? "");; + .GetTypeByMetadataName(typeof(CustomScopeForRootTypesAttribute).FullName ?? ""); var typeInitializerAttribute = compilation - .GetTypeByMetadataName(typeof(TypeInitializerAttribute).FullName ?? "");; + .GetTypeByMetadataName(typeof(TypeInitializerAttribute).FullName ?? ""); var filterTypeInitializerAttribute = compilation .GetTypeByMetadataName(typeof(FilterTypeInitializerAttribute).FullName ?? ""); - if (iContainer is not null - && spyAggregationAttribute is not null + var multiContainerAttribute = compilation + .GetTypeByMetadataName(typeof(MultiContainerAttribute).FullName ?? ""); + + if (spyAggregationAttribute is not null && spyConstructorChoiceAggregationAttribute is not null && implementationAggregationAttribute is not null && transientAggregationAttribute is not null @@ -192,6 +193,7 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK && filterConstructorChoiceAttribute is not null && filterTypeInitializerAttribute is not null && customScopeForRootTypesAttribute is not null + && multiContainerAttribute is not null && iDisposable is not null && iAsyncDisposable is not null && lazy1 is not null @@ -212,7 +214,6 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK { wellKnownTypes = new WellKnownTypes( - Container: iContainer, SpyAggregationAttribute: spyAggregationAttribute, SpyConstructorChoiceAggregationAttribute: spyConstructorChoiceAggregationAttribute, ImplementationAggregationAttribute: implementationAggregationAttribute, @@ -242,6 +243,7 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK FilterConstructorChoiceAttribute: filterConstructorChoiceAttribute, FilterTypeInitializerAttribute: filterTypeInitializerAttribute, CustomScopeForRootTypesAttribute: customScopeForRootTypesAttribute, + MultiContainerAttribute: multiContainerAttribute, Disposable: iDisposable, AsyncDisposable: iAsyncDisposable, Lazy1: lazy1, diff --git a/Sample/Context.cs b/Sample/Context.cs index 6927e3f7..8f53825a 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; using MrMeeseeks.DIE.Sample; namespace MrMeeseeks.DIE.Test.Async.TaskCollection; @@ -46,6 +47,7 @@ internal class DependencyD : IInterface public bool IsInitialized => true; } -internal partial class Container : IContainer>> +[MultiContainer(typeof(IReadOnlyList>))] +internal partial class Container { } \ No newline at end of file diff --git a/Sample/Program.cs b/Sample/Program.cs index 6d63b683..629e3545 100644 --- a/Sample/Program.cs +++ b/Sample/Program.cs @@ -1,7 +1,4 @@ using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using MrMeeseeks.DIE; using MrMeeseeks.DIE.Test.Async.TaskCollection; internal class Program @@ -10,6 +7,6 @@ private static void Main() { Console.WriteLine("Hello, world!"); var container = new Container(); - Console.WriteLine(((IContainer>>) container).Resolve()); + Console.WriteLine(container.Create0()); } } \ No newline at end of file diff --git a/Test/Async/WrappedDependency/DecorationChaining.cs b/Test/Async/WrappedDependency/DecorationChaining.cs index 02027672..57fc8796 100644 --- a/Test/Async/WrappedDependency/DecorationChaining.cs +++ b/Test/Async/WrappedDependency/DecorationChaining.cs @@ -47,8 +47,9 @@ async ValueTask IValueTaskTypeInitializer.InitializeAsync() } } +[MultiContainer(typeof(Task))] [DecoratorSequenceChoice(typeof(IInterface), typeof(DecoratorA), typeof(DecoratorB))] -internal partial class Container : IContainer> +internal partial class Container { } @@ -58,7 +59,7 @@ public class Tests public async Task Test() { using var container = new Container(); - var instance = await ((IContainer>) container).Resolve().ConfigureAwait(false); + var instance = await container.Create0().ConfigureAwait(false); Assert.True(instance.IsInitialized); } } \ No newline at end of file diff --git a/Test/Async/WrappedDependency/Func.cs b/Test/Async/WrappedDependency/Func.cs index b4e1b6fc..f2b0f26e 100644 --- a/Test/Async/WrappedDependency/Func.cs +++ b/Test/Async/WrappedDependency/Func.cs @@ -1,5 +1,6 @@ using System; using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; using Xunit; namespace MrMeeseeks.DIE.Test.Async.WrappedDependency.Func; @@ -16,7 +17,8 @@ async Task ITaskTypeInitializer.InitializeAsync() } } -internal partial class Container : IContainer>> +[MultiContainer(typeof(Func>))] +internal partial class Container { } @@ -26,7 +28,7 @@ public class Tests public async Task Test() { using var container = new Container(); - var instance = ((IContainer>>) container).Resolve(); + var instance = container.Create0(); Assert.True((await instance().ConfigureAwait(false)).IsInitialized); } } \ No newline at end of file diff --git a/Test/Async/WrappedDependency/Lazy.cs b/Test/Async/WrappedDependency/Lazy.cs index 2dbf0844..108f454b 100644 --- a/Test/Async/WrappedDependency/Lazy.cs +++ b/Test/Async/WrappedDependency/Lazy.cs @@ -1,5 +1,7 @@ using System; +using System.Collections.Generic; using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; using Xunit; namespace MrMeeseeks.DIE.Test.Async.WrappedDependency.Lazy; @@ -16,7 +18,8 @@ async Task ITaskTypeInitializer.InitializeAsync() } } -internal partial class Container : IContainer>> +[MultiContainer(typeof(Lazy>))] +internal partial class Container { } @@ -26,7 +29,7 @@ public class Tests public async Task Test() { using var container = new Container(); - var instance = ((IContainer>>) container).Resolve(); + var instance = container.Create0(); Assert.True((await instance.Value.ConfigureAwait(false)).IsInitialized); } } \ No newline at end of file diff --git a/Test/Async/WrappedDependency/SyncToTask.cs b/Test/Async/WrappedDependency/SyncToTask.cs index 63f2bb76..b570a3ce 100644 --- a/Test/Async/WrappedDependency/SyncToTask.cs +++ b/Test/Async/WrappedDependency/SyncToTask.cs @@ -1,4 +1,5 @@ using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; using Xunit; namespace MrMeeseeks.DIE.Test.Async.WrappedDependency.SyncToTask; @@ -13,7 +14,8 @@ void ITypeInitializer.Initialize() } } -internal partial class Container : IContainer> +[MultiContainer(typeof(Task))] +internal partial class Container { } @@ -23,7 +25,7 @@ public class Tests public async Task Test() { using var container = new Container(); - var instance = await ((IContainer>) container).Resolve().ConfigureAwait(false); + var instance = await container.Create0().ConfigureAwait(false); Assert.True(instance.IsInitialized); } } \ No newline at end of file diff --git a/Test/Async/WrappedDependency/SyncToValueTask.cs b/Test/Async/WrappedDependency/SyncToValueTask.cs index 78abf4b0..a684f297 100644 --- a/Test/Async/WrappedDependency/SyncToValueTask.cs +++ b/Test/Async/WrappedDependency/SyncToValueTask.cs @@ -1,4 +1,6 @@ +using System.Collections.Generic; using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; using Xunit; namespace MrMeeseeks.DIE.Test.Async.WrappedDependency.SyncToValueTask; @@ -13,7 +15,8 @@ void ITypeInitializer.Initialize() } } -internal partial class Container : IContainer> +[MultiContainer(typeof(ValueTask))] +internal partial class Container { } @@ -23,7 +26,7 @@ public class Tests public async Task Test() { using var container = new Container(); - var instance = await ((IContainer>) container).Resolve().ConfigureAwait(false); + var instance = await container.Create0().ConfigureAwait(false); Assert.True(instance.IsInitialized); } } \ No newline at end of file diff --git a/Test/Async/WrappedDependency/TaskCollection.cs b/Test/Async/WrappedDependency/TaskCollection.cs index c17f69c7..62f73920 100644 --- a/Test/Async/WrappedDependency/TaskCollection.cs +++ b/Test/Async/WrappedDependency/TaskCollection.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; using Xunit; namespace MrMeeseeks.DIE.Test.Async.WrappedDependency.TaskCollection; @@ -46,7 +47,8 @@ internal class DependencyD : IInterface public bool IsInitialized => true; } -internal partial class Container : IContainer>> +[MultiContainer(typeof(IReadOnlyList>))] +internal partial class Container { } @@ -56,7 +58,7 @@ public class Tests public async Task Test() { using var container = new Container(); - var instance = ((IContainer>>) container).Resolve(); + var instance = container.Create0(); Assert.Equal(4, instance.Count); await Task.WhenAll(instance).ConfigureAwait(false); foreach (var task in instance) diff --git a/Test/Async/WrappedDependency/TaskComposition.cs b/Test/Async/WrappedDependency/TaskComposition.cs index 214a453b..808377f9 100644 --- a/Test/Async/WrappedDependency/TaskComposition.cs +++ b/Test/Async/WrappedDependency/TaskComposition.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; using Xunit; namespace MrMeeseeks.DIE.Test.Async.WrappedDependency.TaskComposition; @@ -66,7 +67,8 @@ public async Task InitializeAsync() public int Count => _composition.Count; } -internal partial class Container : IContainer> +[MultiContainer(typeof(Task))] +internal partial class Container { } @@ -76,7 +78,7 @@ public class Tests public async Task Test() { using var container = new Container(); - var instance = await ((IContainer>) container).Resolve().ConfigureAwait(false); + var instance = await container.Create0().ConfigureAwait(false); Assert.IsType(instance); Assert.Equal(4, ((Composite) instance).Count); Assert.True(instance.IsInitialized); diff --git a/Test/Async/WrappedDependency/TaskToTask.cs b/Test/Async/WrappedDependency/TaskToTask.cs index caefacaa..6f92f08e 100644 --- a/Test/Async/WrappedDependency/TaskToTask.cs +++ b/Test/Async/WrappedDependency/TaskToTask.cs @@ -1,5 +1,6 @@ using System; using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; using Xunit; namespace MrMeeseeks.DIE.Test.Async.WrappedDependency.TaskToTask; @@ -15,7 +16,8 @@ async Task ITaskTypeInitializer.InitializeAsync() } } -internal partial class Container : IContainer> +[MultiContainer(typeof(Task))] +internal partial class Container { } @@ -25,7 +27,7 @@ public class Tests public async Task Test() { using var container = new Container(); - var instance = await ((IContainer>) container).Resolve().ConfigureAwait(false); + var instance = await container.Create0().ConfigureAwait(false); Assert.True(instance.IsInitialized); } } \ No newline at end of file diff --git a/Test/Async/WrappedDependency/TaskToValueTask.cs b/Test/Async/WrappedDependency/TaskToValueTask.cs index 76797de2..89ffa807 100644 --- a/Test/Async/WrappedDependency/TaskToValueTask.cs +++ b/Test/Async/WrappedDependency/TaskToValueTask.cs @@ -1,5 +1,6 @@ using System; using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; using Xunit; namespace MrMeeseeks.DIE.Test.Async.WrappedDependency.TaskToValueTask; @@ -15,7 +16,8 @@ async Task ITaskTypeInitializer.InitializeAsync() } } -internal partial class Container : IContainer> +[MultiContainer(typeof(ValueTask))] +internal partial class Container { } @@ -25,7 +27,7 @@ public class Tests public async Task Test() { using var container = new Container(); - var instance = await ((IContainer>) container).Resolve().ConfigureAwait(false); + var instance = await container.Create0().ConfigureAwait(false); Assert.True(instance.IsInitialized); } } \ No newline at end of file diff --git a/Test/Async/WrappedDependency/ValueTaskCollection.cs b/Test/Async/WrappedDependency/ValueTaskCollection.cs index 886d6492..85bd1057 100644 --- a/Test/Async/WrappedDependency/ValueTaskCollection.cs +++ b/Test/Async/WrappedDependency/ValueTaskCollection.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; using Xunit; namespace MrMeeseeks.DIE.Test.Async.WrappedDependency.ValueTaskCollection; @@ -46,7 +47,8 @@ internal class DependencyD : IInterface public bool IsInitialized => true; } -internal partial class Container : IContainer>> +[MultiContainer(typeof(IReadOnlyList>))] +internal partial class Container { } @@ -56,7 +58,7 @@ public class Tests public async Task Test() { using var container = new Container(); - var instance = ((IContainer>>) container).Resolve(); + var instance = container.Create0(); Assert.Equal(4, instance.Count); foreach (var task in instance) Assert.True((await task.ConfigureAwait(false)).IsInitialized); diff --git a/Test/Async/WrappedDependency/ValueTaskComposition.cs b/Test/Async/WrappedDependency/ValueTaskComposition.cs index 5400afe9..7e457940 100644 --- a/Test/Async/WrappedDependency/ValueTaskComposition.cs +++ b/Test/Async/WrappedDependency/ValueTaskComposition.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; using Xunit; namespace MrMeeseeks.DIE.Test.Async.WrappedDependency.ValueTaskComposition; @@ -66,7 +67,8 @@ public async Task InitializeAsync() public int Count => _composition.Count; } -internal partial class Container : IContainer> +[MultiContainer(typeof(ValueTask))] +internal partial class Container { } @@ -76,7 +78,7 @@ public class Tests public async Task Test() { using var container = new Container(); - var instance = await ((IContainer>) container).Resolve().ConfigureAwait(false); + var instance = await container.Create0().ConfigureAwait(false); Assert.IsType(instance); Assert.Equal(4, ((Composite) instance).Count); Assert.True(instance.IsInitialized); diff --git a/Test/Async/WrappedDependency/ValueTaskToTask.cs b/Test/Async/WrappedDependency/ValueTaskToTask.cs index 68a8af87..6bf2f256 100644 --- a/Test/Async/WrappedDependency/ValueTaskToTask.cs +++ b/Test/Async/WrappedDependency/ValueTaskToTask.cs @@ -1,5 +1,6 @@ using System; using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; using Xunit; namespace MrMeeseeks.DIE.Test.Async.WrappedDependency.ValueTaskToTask; @@ -15,7 +16,8 @@ async ValueTask IValueTaskTypeInitializer.InitializeAsync() } } -internal partial class Container : IContainer> +[MultiContainer(typeof(Task))] +internal partial class Container { } @@ -25,7 +27,7 @@ public class Tests public async Task Test() { using var container = new Container(); - var instance = await ((IContainer>) container).Resolve().ConfigureAwait(false); + var instance = await container.Create0().ConfigureAwait(false); Assert.True(instance.IsInitialized); } } \ No newline at end of file diff --git a/Test/Async/WrappedDependency/ValueTaskToValueTask.cs b/Test/Async/WrappedDependency/ValueTaskToValueTask.cs index d8a26afe..b5449cb3 100644 --- a/Test/Async/WrappedDependency/ValueTaskToValueTask.cs +++ b/Test/Async/WrappedDependency/ValueTaskToValueTask.cs @@ -1,5 +1,6 @@ using System; using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; using Xunit; namespace MrMeeseeks.DIE.Test.Async.WrappedDependency.ValueTaskToValueTask; @@ -15,7 +16,8 @@ async ValueTask IValueTaskTypeInitializer.InitializeAsync() } } -internal partial class Container : IContainer> +[MultiContainer(typeof(ValueTask))] +internal partial class Container { } @@ -25,7 +27,7 @@ public class Tests public async Task Test() { using var container = new Container(); - var instance = await ((IContainer>) container).Resolve().ConfigureAwait(false); + var instance = await container.Create0().ConfigureAwait(false); Assert.True(instance.IsInitialized); } } \ No newline at end of file diff --git a/Test/CompositeTests.cs b/Test/CompositeTests.cs index 316866fd..dd1d4bfe 100644 --- a/Test/CompositeTests.cs +++ b/Test/CompositeTests.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using MrMeeseeks.DIE; using MrMeeseeks.DIE.Configuration; using MrMeeseeks.DIE.Test; using Xunit; @@ -32,7 +31,8 @@ public CompositeNormal(IReadOnlyList composites) => public IReadOnlyList Composites { get; } } -internal partial class CompositeNormalContainer : IContainer, IContainer> +[MultiContainer(typeof(ICompositeNormal), typeof(IReadOnlyList))] +internal partial class CompositeNormalContainer { } @@ -43,7 +43,7 @@ public partial class CompositeTests public void Normal() { using var container = new CompositeNormalContainer(); - var composite = ((IContainer) container).Resolve(); + var composite = container.Create0(); foreach (var compositeComposite in composite.Composites) { Assert.NotEqual(composite, compositeComposite); @@ -56,7 +56,7 @@ public void Normal() public void NormalList() { using var container = new CompositeNormalContainer(); - var composites = ((IContainer>) container).Resolve(); + var composites = container.Create1(); foreach (var compositeComposite in composites) { var type = compositeComposite.GetType(); @@ -89,7 +89,8 @@ public CompositeContainerInstance(IReadOnlyList com public IReadOnlyList Composites { get; } } -internal partial class CompositeContainerInstanceContainer : IContainer, IContainer> +[MultiContainer(typeof(ICompositeContainerInstance), typeof(IReadOnlyList))] +internal partial class CompositeContainerInstanceContainer { } @@ -100,14 +101,14 @@ public partial class CompositeTests public void ContainerInstance() { using var container = new CompositeContainerInstanceContainer(); - var composite = ((IContainer) container).Resolve(); + var composite = container.Create0(); foreach (var compositeComposite in composite.Composites) { Assert.NotEqual(composite, compositeComposite); var type = compositeComposite.GetType(); Assert.True(type == typeof(CompositeContainerInstanceBasisA) || type == typeof(CompositeContainerInstanceBasisB)); } - var nextComposite = ((IContainer) container).Resolve(); + var nextComposite = container.Create0(); Assert.Equal(composite, nextComposite); } @@ -115,14 +116,14 @@ public void ContainerInstance() public void ContainerInstanceList() { using var container = new CompositeContainerInstanceContainer(); - var composites = ((IContainer>) container).Resolve(); + var composites = container.Create1(); foreach (var compositeComposite in composites) { var type = compositeComposite.GetType(); Assert.True(type == typeof(CompositeContainerInstanceBasisA) || type == typeof(CompositeContainerInstanceBasisB)); } Assert.Equal(2, composites.Count); - var nextComposites = ((IContainer>) container).Resolve(); + var nextComposites = container.Create1(); Assert.Equal(composites[0], nextComposites[0]); Assert.Equal(composites[1], nextComposites[1]); } @@ -151,7 +152,8 @@ public CompositeMixedScoping(IReadOnlyList composites) = public IReadOnlyList Composites { get; } } -internal partial class CompositeMixedScopingContainer : IContainer, IContainer> +[MultiContainer(typeof(ICompositeMixedScoping), typeof(IReadOnlyList))] +internal partial class CompositeMixedScopingContainer { } @@ -162,14 +164,14 @@ public partial class CompositeTests public void MixedScoping() { using var container = new CompositeMixedScopingContainer(); - var composite = ((IContainer) container).Resolve(); + var composite = container.Create0(); foreach (var compositeComposite in composite.Composites) { Assert.NotEqual(composite, compositeComposite); var type = compositeComposite.GetType(); Assert.True(type == typeof(CompositeMixedScopingBasisA) || type == typeof(CompositeMixedScopingBasisB)); } - var nextComposite = ((IContainer) container).Resolve(); + var nextComposite = container.Create0(); Assert.NotEqual(composite, nextComposite); } @@ -177,14 +179,14 @@ public void MixedScoping() public void MixedScopingList() { using var container = new CompositeMixedScopingContainer(); - var composites = ((IContainer>) container).Resolve(); + var composites = container.Create1(); foreach (var compositeComposite in composites) { var type = compositeComposite.GetType(); Assert.True(type == typeof(CompositeMixedScopingBasisA) || type == typeof(CompositeMixedScopingBasisB)); } Assert.Equal(2, composites.Count); - var nextComposites = ((IContainer>) container).Resolve(); + var nextComposites = container.Create1(); Assert.True(composites[0].Equals(nextComposites[0]) && !composites[1].Equals(nextComposites[1]) || composites[1].Equals(nextComposites[1]) && !composites[0].Equals(nextComposites[0])); } @@ -228,7 +230,8 @@ public CompositeScopeRoot(IReadOnlyList composites, ICompos public ICompositeScopeRootDependency Dependency { get; } } -internal partial class CompositeScopeRootContainer : IContainer, IContainer> +[MultiContainer(typeof(ICompositeScopeRoot), typeof(IReadOnlyList))] +internal partial class CompositeScopeRootContainer { } @@ -239,7 +242,7 @@ public partial class CompositeTests public void ScopeRoot() { using var container = new CompositeScopeRootContainer(); - var composite = ((IContainer) container).Resolve(); + var composite = container.Create0(); foreach (var compositeComposite in composite.Composites) { Assert.NotEqual(composite, compositeComposite); @@ -247,7 +250,7 @@ public void ScopeRoot() Assert.True(type == typeof(CompositeScopeRootBasisA) || type == typeof(CompositeScopeRootBasisB)); Assert.Equal(composite.Dependency, compositeComposite.Dependency); } - var next = ((IContainer) container).Resolve(); + var next = container.Create0(); Assert.NotEqual(composite.Dependency, next.Dependency); } @@ -255,7 +258,7 @@ public void ScopeRoot() public void ScopeRootList() { using var container = new CompositeScopeRootContainer(); - var composites = ((IContainer>) container).Resolve(); + var composites = container.Create1(); foreach (var compositeComposite in composites) { var type = compositeComposite.GetType(); @@ -313,7 +316,8 @@ public CompositeDecorated(IReadOnlyList composites) => public ICompositeDecorated Decorated => this; } -internal partial class CompositeDecoratedContainer : IContainer, IContainer> +[MultiContainer(typeof(ICompositeDecorated), typeof(IReadOnlyList))] +internal partial class CompositeDecoratedContainer { } @@ -324,7 +328,7 @@ public partial class CompositeTests public void Decorated() { using var container = new CompositeDecoratedContainer(); - var composite = ((IContainer) container).Resolve(); + var composite = container.Create0(); Assert.IsType(composite); Assert.IsType(composite.Decorated); foreach (var compositeComposite in composite.Composites) @@ -341,7 +345,7 @@ public void Decorated() public void DecoratedList() { using var container = new CompositeDecoratedContainer(); - var composites = ((IContainer>) container).Resolve(); + var composites = container.Create1(); foreach (var compositeComposite in composites) { Assert.IsType(compositeComposite); diff --git a/Test/ConstructorChoiceTests.cs b/Test/ConstructorChoiceTests.cs index 8263b93f..9e1f111a 100644 --- a/Test/ConstructorChoiceTests.cs +++ b/Test/ConstructorChoiceTests.cs @@ -1,5 +1,4 @@ using System; -using MrMeeseeks.DIE; using MrMeeseeks.DIE.Configuration; using Xunit; @@ -8,18 +7,19 @@ namespace MrMeeseeks.DIE.Test; -internal partial class ConstructorChoiceContainer : IContainer +[MultiContainer(typeof(DateTime))] +internal partial class ConstructorChoiceContainer { } -public partial class ImplementationAggregationTests +public class ImplementationAggregationTests { [Fact] public void ResolveExternalType() { using var container = new ConstructorChoiceContainer(); - var dateTime = ((IContainer) container).Resolve(); + var dateTime = container.Create0(); Assert.Equal(DateTime.MinValue, dateTime); } } \ No newline at end of file diff --git a/Test/ConstructorTests.cs b/Test/ConstructorTests.cs index 1382c4f9..ae6f15bd 100644 --- a/Test/ConstructorTests.cs +++ b/Test/ConstructorTests.cs @@ -1,3 +1,4 @@ +using MrMeeseeks.DIE.Configuration; using Xunit; namespace MrMeeseeks.DIE.Test; @@ -16,17 +17,18 @@ internal class ConstructorInit : IConstructorInit public IConstructorInitDependency? Dependency { get; init; } } -internal partial class ConstructorInitContainer : IContainer +[MultiContainer(typeof(IConstructorInit))] +internal partial class ConstructorInitContainer { } -public partial class ConstructorsTests +public class ConstructorsTests { [Fact] public void ResolveInitProperty() { using var container = new ConstructorInitContainer(); - var resolution = ((IContainer) container).Resolve(); + var resolution = container.Create0(); Assert.NotNull(resolution.Dependency); Assert.IsType(resolution.Dependency); } diff --git a/Test/DecoratorTests.cs b/Test/DecoratorTests.cs index 318ad53d..5ae2b36c 100644 --- a/Test/DecoratorTests.cs +++ b/Test/DecoratorTests.cs @@ -26,7 +26,8 @@ public DecoratorNormal(IDecoratedNormal decoratedNormal) => public IDecoratedNormal Decorated { get; } } -internal partial class DecoratorNormalContainer : IContainer +[MultiContainer(typeof(IDecoratedNormal))] +internal partial class DecoratorNormalContainer { } @@ -37,7 +38,7 @@ public partial class DecoratorTests public void Normal() { using var container = new DecoratorNormalContainer(); - var decorated = ((IContainer) container).Resolve(); + var decorated = container.Create0(); Assert.NotEqual(decorated, decorated.Decorated); Assert.IsType(decorated); Assert.IsType(decorated.Decorated); @@ -62,7 +63,8 @@ public DecoratorContainerInstance(IDecoratedContainerInstance decoratedContainer public IDecoratedContainerInstance Decorated { get; } } -internal partial class DecoratorContainerInstanceContainer : IContainer +[MultiContainer(typeof(IDecoratedContainerInstance))] +internal partial class DecoratorContainerInstanceContainer { } @@ -73,12 +75,12 @@ public partial class DecoratorTests public void ContainerInstance() { using var container = new DecoratorContainerInstanceContainer(); - var decorated = ((IContainer) container).Resolve(); + var decorated = container.Create0(); Assert.NotEqual(decorated, decorated.Decorated); Assert.IsType(decorated); Assert.IsType(decorated.Decorated); - var decoratedNextReference = ((IContainer) container).Resolve(); + var decoratedNextReference = container.Create0(); Assert.Equal(decorated, decoratedNextReference); Assert.Equal(decorated.Decorated, decoratedNextReference.Decorated); } @@ -117,7 +119,8 @@ public DecoratorScopeRoot(IDecoratedScopeRoot decorated, IDecoratedScopeRootDepe public IDecoratedScopeRoot Decorated { get; } } -internal partial class DecoratorScopeRootContainer : IContainer +[MultiContainer(typeof(IDecoratedScopeRoot))] +internal partial class DecoratorScopeRootContainer { } @@ -128,14 +131,14 @@ public partial class DecoratorTests public void ScopeRoot() { using var container = new DecoratorScopeRootContainer(); - var decorated = ((IContainer) container).Resolve(); + var decorated = container.Create0(); Assert.NotEqual(decorated, decorated.Decorated); Assert.Equal(decorated.Dependency, decorated.Decorated.Dependency); Assert.IsType(decorated); Assert.IsType(decorated.Decorated); // There is yet no way to check scopes externally - var next = ((IContainer) container).Resolve(); + var next = container.Create0(); Assert.NotEqual(decorated, next); Assert.NotEqual(decorated.Dependency, next.Dependency); } @@ -167,7 +170,8 @@ public DecoratorMultiB(IDecoratedMulti decorated) => public IDecoratedMulti Decorated { get; } } -internal partial class DecoratorMultiContainer : IContainer +[MultiContainer(typeof(IDecoratedMulti))] +internal partial class DecoratorMultiContainer { } @@ -178,7 +182,7 @@ public partial class DecoratorTests public void Multi() { using var container = new DecoratorMultiContainer(); - var decorated = ((IContainer) container).Resolve(); + var decorated = container.Create0(); var decoratedB = decorated; var decoratedA = decorated.Decorated; var decoratedBasis = decoratedA.Decorated; @@ -214,7 +218,8 @@ public DecoratorList(IDecoratedList decorated) => public IDecoratedList Decorated { get; } } -internal partial class DecoratorListContainer : IContainer> +[MultiContainer(typeof(IReadOnlyList))] +internal partial class DecoratorListContainer { } @@ -225,7 +230,7 @@ public partial class DecoratorTests public void List() { using var container = new DecoratorListContainer(); - var decorated = ((IContainer>) container).Resolve(); + var decorated = container.Create0(); var decoratedOfA = decorated[0]; var decoratedOfB = decorated[1]; var decoratedBasisA = decoratedOfA.Decorated; diff --git a/Test/FactoryTests.cs b/Test/FactoryTests.cs index f92757ce..4739d212 100644 --- a/Test/FactoryTests.cs +++ b/Test/FactoryTests.cs @@ -1,4 +1,5 @@ using System.IO; +using MrMeeseeks.DIE.Configuration; using Xunit; namespace MrMeeseeks.DIE.Test; @@ -22,7 +23,8 @@ internal FactoryContainerScope(string yeah) } } -internal partial class FactoryContainer : IContainer, IContainer, IContainer +[MultiContainer(typeof(FileInfo), typeof(FactoryContainerTransientScope), typeof(FactoryContainerScope))] +internal partial class FactoryContainer { private string DIE_Path { get; } @@ -48,7 +50,7 @@ public void ResolveExternalType() { var check = @"C:\HelloWorld.txt"; using var container = new FactoryContainer(check); - var fileInfo = ((IContainer) container).Resolve(); + var fileInfo = container.Create0(); Assert.Equal(check, fileInfo.FullName); } @@ -57,7 +59,7 @@ public void ResolveFromFactoryInTransientScope() { var check = @"C:\HelloWorld.txt"; using var container = new FactoryContainer(check); - var transientScope = ((IContainer) container).Resolve(); + var transientScope = container.Create1(); Assert.Equal(69, transientScope.Number); } @@ -66,7 +68,7 @@ public void ResolveFromFactoryInScope() { var check = @"C:\HelloWorld.txt"; using var container = new FactoryContainer(check); - var scope = ((IContainer) container).Resolve(); + var scope = container.Create2(); Assert.Equal("Yeah", scope.Yeah); } } \ No newline at end of file diff --git a/Test/ImplementationAggregationTests.cs b/Test/ImplementationAggregationTests.cs index a0edc273..18a5a8e0 100644 --- a/Test/ImplementationAggregationTests.cs +++ b/Test/ImplementationAggregationTests.cs @@ -7,7 +7,8 @@ namespace MrMeeseeks.DIE.Test; -internal partial class ImplementationAggregationContainer : IContainer> +[MultiContainer(typeof(Func))] +internal partial class ImplementationAggregationContainer { } @@ -19,7 +20,7 @@ public void ResolveExternalType() { using var container = new ImplementationAggregationContainer(); var path = @"C:\HelloWorld.txt"; - var fileInfo = ((IContainer>) container).Resolve()(path); + var fileInfo = container.Create0()(path); Assert.NotNull(fileInfo); Assert.IsType(fileInfo); Assert.Equal(path, fileInfo.FullName); diff --git a/Test/InstanceTests.cs b/Test/InstanceTests.cs index 1a61b132..51cef6da 100644 --- a/Test/InstanceTests.cs +++ b/Test/InstanceTests.cs @@ -1,3 +1,4 @@ +using MrMeeseeks.DIE.Configuration; using Xunit; namespace MrMeeseeks.DIE.Test; @@ -17,7 +18,8 @@ public InstanceClass(string dependency) } } -internal partial class InstanceContainer : IContainer +[MultiContainer(typeof(IInstanceClass))] +internal partial class InstanceContainer { private readonly string DIE_Dependency; @@ -31,7 +33,7 @@ public void ResolveExternalType() { var check = "Hello, instance!"; using var container = new InstanceContainer(check); - var instanceClass = ((IContainer) container).Resolve(); + var instanceClass = container.Create0(); Assert.Equal(check, instanceClass.Dependency); } } \ No newline at end of file diff --git a/Test/PropertyTests.cs b/Test/PropertyTests.cs index 3e9672bf..0c277770 100644 --- a/Test/PropertyTests.cs +++ b/Test/PropertyTests.cs @@ -1,3 +1,5 @@ +using System.Collections.Generic; +using MrMeeseeks.DIE.Configuration; using Xunit; namespace MrMeeseeks.DIE.Test; @@ -17,7 +19,8 @@ public PropertyClass(string dependency) } } -internal partial class PropertyContainer : IContainer +[MultiContainer(typeof(IPropertyClass))] +internal partial class PropertyContainer { private string DIE_Dependency { get; } @@ -31,7 +34,7 @@ public void ResolveExternalType() { var check = "Hello, Property!"; using var container = new PropertyContainer(check); - var propertyClass = ((IContainer) container).Resolve(); + var propertyClass = container.Create0(); Assert.Equal(check, propertyClass.Dependency); } } \ No newline at end of file diff --git a/Test/ScopeSpecificAttributesTestsWithDecorator.cs b/Test/ScopeSpecificAttributesTestsWithDecorator.cs index 50a5879b..3f2f6fdd 100644 --- a/Test/ScopeSpecificAttributesTestsWithDecorator.cs +++ b/Test/ScopeSpecificAttributesTestsWithDecorator.cs @@ -89,13 +89,9 @@ internal ScopeRoot(IInterface dep) } +[MultiContainer(typeof(IInterface), typeof(TransientScopeRoot), typeof(TransientScopeRootSpecific), typeof(ScopeRoot), typeof(ScopeRootSpecific))] [DecoratorSequenceChoice(typeof(IInterface), typeof(ContainerDecorator))] -internal partial class Container - : IContainer, - IContainer, - IContainer, - IContainer, - IContainer +internal partial class Container { [DecoratorSequenceChoice(typeof(IInterface), typeof(TransientScopeDecorator))] partial class DIE_DefaultTransientScope @@ -130,35 +126,35 @@ public partial class ScopeSpecificAttributesTests public void Container() { using var container = new Container(); - var instance = ((IContainer) container).Resolve(); + var instance = container.Create0(); Assert.Equal(69, instance.CheckNumber); } [Fact] public void TransientScope() { using var container = new Container(); - var instance = ((IContainer) container).Resolve(); + var instance = container.Create1(); Assert.Equal(23, instance.Dep.CheckNumber); } [Fact] public void TransientScopeSpecific() { using var container = new Container(); - var instance = ((IContainer) container).Resolve(); + var instance = container.Create2(); Assert.Equal(7, instance.Dep.CheckNumber); } [Fact] public void Scope() { using var container = new Container(); - var instance = ((IContainer) container).Resolve(); + var instance = container.Create3(); Assert.Equal(3, instance.Dep.CheckNumber); } [Fact] public void ScopeSpecific() { using var container = new Container(); - var instance = ((IContainer) container).Resolve(); + var instance = container.Create4(); Assert.Equal(13, instance.Dep.CheckNumber); } } \ No newline at end of file diff --git a/Test/ScopeSpecificAttributesTestsWithImplementationLists.cs b/Test/ScopeSpecificAttributesTestsWithImplementationLists.cs index 1f659a0e..81db1486 100644 --- a/Test/ScopeSpecificAttributesTestsWithImplementationLists.cs +++ b/Test/ScopeSpecificAttributesTestsWithImplementationLists.cs @@ -26,7 +26,8 @@ internal class Scope : IScopeRoot public IReadOnlyList Dependencies { get; } } -internal partial class Container : IContainer>, IContainer, IContainer +[MultiContainer(typeof(IReadOnlyList), typeof(TransientScope), typeof(Scope))] +internal partial class Container { [FilterImplementationAggregation(typeof(DependencyContainer))] [FilterImplementationAggregation(typeof(DependencyScope))] @@ -49,7 +50,7 @@ public class Tests public void Container() { using var container = new Container(); - var dependencies = ((IContainer>) container).Resolve(); + var dependencies = container.Create0(); Assert.Equal(3, dependencies.Count); Assert.Contains(dependencies, d => d.GetType() == typeof(DependencyContainer)); Assert.Contains(dependencies, d => d.GetType() == typeof(DependencyTransientScope)); @@ -59,7 +60,7 @@ public void Container() public void TransientScope() { using var container = new Container(); - var dependencies = ((IContainer) container).Resolve(); + var dependencies = container.Create1(); Assert.Equal(1, dependencies.Dependencies.Count); Assert.Contains(dependencies.Dependencies, d => d.GetType() == typeof(DependencyTransientScope)); } @@ -67,7 +68,7 @@ public void TransientScope() public void Scope() { using var container = new Container(); - var dependencies = ((IContainer) container).Resolve(); + var dependencies = container.Create2(); Assert.Equal(1, dependencies.Dependencies.Count); Assert.Contains(dependencies.Dependencies, d => d.GetType() == typeof(DependencyScope)); } diff --git a/Test/ScopeSpecificAttributesTestsWithImplementations.cs b/Test/ScopeSpecificAttributesTestsWithImplementations.cs index fda7edf3..7e1b2069 100644 --- a/Test/ScopeSpecificAttributesTestsWithImplementations.cs +++ b/Test/ScopeSpecificAttributesTestsWithImplementations.cs @@ -25,9 +25,10 @@ internal class Scope : IScopeRoot public IDependency Dependency { get; } } +[MultiContainer(typeof(IDependency), typeof(TransientScope), typeof(Scope))] [FilterImplementationAggregation(typeof(DependencyScope))] [FilterImplementationAggregation(typeof(DependencyTransientScope))] -internal partial class Container : IContainer, IContainer, IContainer +internal partial class Container { [FilterImplementationAggregation(typeof(DependencyContainer))] [ImplementationAggregation(typeof(DependencyTransientScope))] @@ -50,21 +51,21 @@ public class Tests public void Container() { using var container = new Container(); - var dependency = ((IContainer) container).Resolve(); + var dependency = container.Create0(); Assert.IsType(dependency); } [Fact] public void TransientScope() { using var container = new Container(); - var dependency = ((IContainer) container).Resolve(); + var dependency = container.Create1(); Assert.IsType(dependency.Dependency); } [Fact] public void Scope() { using var container = new Container(); - var dependency = ((IContainer) container).Resolve(); + var dependency = container.Create2(); Assert.IsType(dependency.Dependency); } } \ No newline at end of file diff --git a/Test/SyncTypeInitializationTest.cs b/Test/SyncTypeInitializationTest.cs index 8ec1ac80..d9c24dab 100644 --- a/Test/SyncTypeInitializationTest.cs +++ b/Test/SyncTypeInitializationTest.cs @@ -1,3 +1,4 @@ +using MrMeeseeks.DIE.Configuration; using Xunit; namespace MrMeeseeks.DIE.Test.SyncTypeInitializationTest; @@ -9,8 +10,8 @@ internal class Dependency : ITypeInitializer void ITypeInitializer.Initialize() => IsInitialized = true; } +[MultiContainer(typeof(Dependency))] internal partial class Container - : IContainer { } @@ -20,7 +21,7 @@ public partial class Tests public void Test() { using var container = new Container(); - var instance = ((IContainer) container).Resolve(); + var instance = container.Create0(); Assert.True(instance.IsInitialized); } } \ No newline at end of file diff --git a/Test/TransientScopeInstanceTests.cs b/Test/TransientScopeInstanceTests.cs index 8a84a2ff..b44a9ef1 100644 --- a/Test/TransientScopeInstanceTests.cs +++ b/Test/TransientScopeInstanceTests.cs @@ -1,4 +1,5 @@ using System; +using MrMeeseeks.DIE.Configuration; using Xunit; namespace MrMeeseeks.DIE.Test; @@ -6,18 +7,13 @@ namespace MrMeeseeks.DIE.Test; internal interface ITransientScopeInstanceInner {} internal class TransientScopeInstance : ITransientScopeInstanceInner, ITransientScopeInstance {} -internal partial class TransientScopeInstanceContainer : IContainer -{ - -} - public partial class TransientScopeInstanceTests { [Fact] public void InContainer() { using var container = new TransientScopeInstanceContainer(); - var _ = ((IContainer) container).Resolve(); + var _ = container.Create0(); } } @@ -28,18 +24,13 @@ internal class ScopeWithTransientScopeInstance : IScopeWithTransientScopeInstanc public ScopeWithTransientScopeInstance(ITransientScopeInstanceInner _) {} } -internal partial class TransientScopeInstanceContainer : IContainer -{ - -} - public partial class TransientScopeInstanceTests { [Fact] public void InScope() { using var container = new TransientScopeInstanceContainer(); - var _ = ((IContainer) container).Resolve(); + var _ = container.Create1(); } } @@ -50,18 +41,13 @@ internal class ScopeWithTransientScopeInstanceAbove : IScopeWithTransientScopeIn public ScopeWithTransientScopeInstanceAbove(IScopeWithTransientScopeInstance _) {} } -internal partial class TransientScopeInstanceContainer : IContainer -{ - -} - public partial class TransientScopeInstanceTests { [Fact] public void InScopeInScope() { using var container = new TransientScopeInstanceContainer(); - var _ = ((IContainer) container).Resolve(); + var _ = container.Create2(); } } @@ -72,18 +58,13 @@ internal class TransientScopeWithTransientScopeInstance : ITransientScopeWithTra public TransientScopeWithTransientScopeInstance(IDisposable scopeDisposal, ITransientScopeInstanceInner _) {} } -internal partial class TransientScopeInstanceContainer : IContainer -{ - -} - public partial class TransientScopeInstanceTests { [Fact] public void InTransientScope() { using var container = new TransientScopeInstanceContainer(); - var _ = ((IContainer) container).Resolve(); + var _ = container.Create3(); } } @@ -134,7 +115,14 @@ public void CleanUp() } } -internal partial class TransientScopeInstanceContainer : IContainer + +[MultiContainer( + typeof(ITransientScopeInstanceInner), + typeof(IScopeWithTransientScopeInstance), + typeof(IScopeWithTransientScopeInstanceAbove), + typeof(ITransientScopeWithTransientScopeInstance), + typeof(ITransientScopeWithScopes))] +internal partial class TransientScopeInstanceContainer { } @@ -145,7 +133,7 @@ public partial class TransientScopeInstanceTests public void TransientScopeWithScopes() { using var container = new TransientScopeInstanceContainer(); - var transientScopeRoot = ((IContainer) container).Resolve(); + var transientScopeRoot = container.Create4(); Assert.NotEqual(transientScopeRoot.A, transientScopeRoot.B); Assert.Equal(transientScopeRoot.A.TransientScopeInstance, transientScopeRoot.B.TransientScopeInstance); transientScopeRoot.CleanUp(); diff --git a/Test/ValueTupleTests.cs b/Test/ValueTupleTests.cs index 44a93396..3317c65c 100644 --- a/Test/ValueTupleTests.cs +++ b/Test/ValueTupleTests.cs @@ -1,4 +1,5 @@ using System; +using MrMeeseeks.DIE.Configuration; using Xunit; namespace MrMeeseeks.DIE.Test; @@ -32,7 +33,8 @@ public ValueTupleBase( int _25) Dependency { get; } } -internal partial class ValueTupleContainer : IContainer +[MultiContainer(typeof(IValueTupleBase))] +internal partial class ValueTupleContainer { private int _i; @@ -45,7 +47,7 @@ public partial class ValueTupleTests public void ResolveValueTuple() { using var container = new ValueTupleContainer(); - var valueTupleBase = ((IContainer) container).Resolve(); + var valueTupleBase = container.Create0(); Assert.Equal(25, valueTupleBase.Dependency._25); } } @@ -76,7 +78,8 @@ public NonSyntaxValueTupleBase( Dependency { get; } } -internal partial class NonSyntaxValueTupleContainer : IContainer +[MultiContainer(typeof(INonSyntaxValueTupleBase))] +internal partial class NonSyntaxValueTupleContainer { private int _i; @@ -89,7 +92,7 @@ public partial class ValueTupleTests public void ResolveNonSyntaxValueTuple() { using var container = new NonSyntaxValueTupleContainer(); - var nonSyntaxValueTupleBase = ((IContainer) container).Resolve(); + var nonSyntaxValueTupleBase = container.Create0(); Assert.Equal(25, nonSyntaxValueTupleBase.Dependency.Item26); } } @@ -111,7 +114,8 @@ public ValueTuple Dependency { get; } } -internal partial class NonSyntaxSingleItemValueTupleContainer : IContainer +[MultiContainer(typeof(INonSyntaxSingleItemValueTupleBase))] +internal partial class NonSyntaxSingleItemValueTupleContainer { private int _i; @@ -124,7 +128,7 @@ public partial class ValueTupleTests public void ResolveNonSyntaxSingleItemValueTuple() { using var container = new NonSyntaxSingleItemValueTupleContainer(); - var NonSyntaxSingleItemValueTupleBase = ((IContainer) container).Resolve(); + var NonSyntaxSingleItemValueTupleBase = container.Create0(); Assert.Equal(0, NonSyntaxSingleItemValueTupleBase.Dependency.Item1); } } @@ -146,7 +150,8 @@ public ValueTuple Dependency { get; } } -internal partial class NonSyntaxDoubleItemValueTupleContainer : IContainer +[MultiContainer(typeof(INonSyntaxDoubleItemValueTupleBase))] +internal partial class NonSyntaxDoubleItemValueTupleContainer { private int _i; @@ -159,7 +164,7 @@ public partial class ValueTupleTests public void ResolveNonSyntaxDoubleItemValueTuple() { using var container = new NonSyntaxDoubleItemValueTupleContainer(); - var NonSyntaxDoubleItemValueTupleBase = ((IContainer) container).Resolve(); + var NonSyntaxDoubleItemValueTupleBase = container.Create0(); Assert.Equal(1, NonSyntaxDoubleItemValueTupleBase.Dependency.Item2); } } \ No newline at end of file From bef228cbd3412ed124f3a8e89c5084b2949b2577 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sat, 12 Mar 2022 10:00:23 +0100 Subject: [PATCH 049/162] Functions as first class resolution building citizen --- Main/CodeBuilding/RangeCodeBaseBuilder.cs | 144 ++++--- Main/CodeBuilding/ScopeCodeBuilder.cs | 2 +- .../CodeBuilding/TransientScopeCodeBuilder.cs | 2 +- .../ContainerResolutionBuilder.cs | 83 ++-- .../FunctionResolutionBuilder.cs | 406 +++++++++++++----- ...entScopeImplementationResolutionBuilder.cs | 5 +- .../RangeResolutionBaseBuilder.cs | 81 ++-- .../RangedFunctionResolutionBuilderManager.cs | 87 ++++ Main/ResolutionBuilding/ResolutionDtos.cs | 16 +- Main/ResolutionBuilding/ScopeManager.cs | 4 +- .../ScopeResolutionBuilder.cs | 73 ++-- ...ransientScopeInterfaceResolutionBuilder.cs | 81 ++-- .../TransientScopeResolutionBuilder.cs | 82 ++-- Main/ResolutionTreeCreationErrorHarvester.cs | 13 +- Main/ResolutionTreeItem.cs | 120 ++++-- Main/SourceGenerator.cs | 69 ++- Sample/Context.cs | 60 ++- Sample/Program.cs | 4 +- Test/DecoratorTests.cs | 1 - Test/Func/Vanilla.cs | 23 + Test/Lazy/Vanilla.cs | 23 + ...opeSpecificAttributesTestsWithDecorator.cs | 2 +- 22 files changed, 909 insertions(+), 472 deletions(-) create mode 100644 Main/ResolutionBuilding/RangedFunctionResolutionBuilderManager.cs create mode 100644 Test/Func/Vanilla.cs create mode 100644 Test/Lazy/Vanilla.cs diff --git a/Main/CodeBuilding/RangeCodeBaseBuilder.cs b/Main/CodeBuilding/RangeCodeBaseBuilder.cs index e2c0ec0b..d78669e4 100644 --- a/Main/CodeBuilding/RangeCodeBaseBuilder.cs +++ b/Main/CodeBuilding/RangeCodeBaseBuilder.cs @@ -26,7 +26,7 @@ protected StringBuilder GenerateResolutionRange( StringBuilder stringBuilder, RangeResolution rangeResolution) { - stringBuilder = rangeResolution.RangedInstances.Aggregate(stringBuilder, GenerateRangedInstanceFunction); + stringBuilder = rangeResolution.RangedInstanceFunctionGroups.Aggregate(stringBuilder, GenerateRangedInstanceFunction); stringBuilder = rangeResolution.RootResolutions.Aggregate(stringBuilder, GenerateResolutionFunction); @@ -51,9 +51,9 @@ private StringBuilder GenerateContainerDisposalFunction( if (_isDisposalHandlingRequired) { - stringBuilder = rangeResolution.RangedInstances.Aggregate( + stringBuilder = rangeResolution.RangedInstanceFunctionGroups.Aggregate( stringBuilder, - (current, containerInstanceResolution) => current.AppendLine($"this.{containerInstanceResolution.Function.LockReference}.Wait();")); + (current, containerInstanceResolution) => current.AppendLine($"this.{containerInstanceResolution.LockReference}.Wait();")); stringBuilder = stringBuilder .AppendLine($"try") @@ -73,9 +73,9 @@ private StringBuilder GenerateContainerDisposalFunction( .AppendLine($"finally") .AppendLine($"{{"); - stringBuilder = rangeResolution.RangedInstances.Aggregate( + stringBuilder = rangeResolution.RangedInstanceFunctionGroups.Aggregate( stringBuilder, - (current, containerInstanceResolution) => current.AppendLine($"this.{containerInstanceResolution.Function.LockReference}.Release();")); + (current, containerInstanceResolution) => current.AppendLine($"this.{containerInstanceResolution.LockReference}.Release();")); return stringBuilder .AppendLine($"}}") @@ -88,17 +88,44 @@ private StringBuilder GenerateContainerDisposalFunction( private StringBuilder GenerateResolutionFunction( StringBuilder stringBuilder, - RootResolutionFunction resolution) + FunctionResolution resolution) { - var parameter = string.Join(",", resolution.Parameter.Select(r => $"{r.TypeFullName} {r.Reference}")); - stringBuilder = stringBuilder - .AppendLine($"{resolution.AccessModifier} {resolution.TypeFullName} {resolution.Reference}({parameter})") - .AppendLine($"{{") - .AppendLine($"if (this.{resolution.DisposalHandling.DisposedPropertyReference}) throw new {WellKnownTypes.ObjectDisposedException}(nameof({resolution.RangeName}));"); + if (resolution is RootResolutionFunction rootResolutionFunction) + { + var parameter = string.Join(",", resolution.Parameter.Select(r => $"{r.TypeFullName} {r.Reference}")); + stringBuilder = stringBuilder + .AppendLine($"{rootResolutionFunction.AccessModifier} {resolution.TypeFullName} {resolution.Reference}({parameter})") + .AppendLine($"{{") + .AppendLine($"if (this.{rootResolutionFunction.DisposalHandling.DisposedPropertyReference}) throw new {WellKnownTypes.ObjectDisposedException}(\"\");"); + + stringBuilder = GenerateResolutionFunctionContent(stringBuilder, resolution.Resolvable) + .AppendLine($"return {resolution.Resolvable.Reference};"); + + stringBuilder = resolution.LocalFunctions.Aggregate(stringBuilder, GenerateResolutionFunction) + .AppendLine($"}}"); + + return stringBuilder; + } + else if (resolution is LocalFunctionResolution localFunctionResolution) + { + var parameter = string.Join(",", resolution.Parameter.Select(r => $"{r.TypeFullName} {r.Reference}")); + stringBuilder = stringBuilder + .AppendLine($"{resolution.TypeFullName} {resolution.Reference}({parameter})") + .AppendLine($"{{") + .AppendLine($"if (this.{localFunctionResolution.DisposalHandling.DisposedPropertyReference}) throw new {WellKnownTypes.ObjectDisposedException}(\"\");"); + + stringBuilder = GenerateResolutionFunctionContent(stringBuilder, resolution.Resolvable) + .AppendLine($"return {resolution.Resolvable.Reference};"); + + stringBuilder = resolution.LocalFunctions.Aggregate(stringBuilder, GenerateResolutionFunction) + .AppendLine($"}}"); + + - return GenerateResolutionFunctionContent(stringBuilder, resolution.Resolvable) - .AppendLine($"return {resolution.Resolvable.Reference};") - .AppendLine($"}}"); + return stringBuilder; + } + + throw new Exception(); } private StringBuilder GenerateResolutionFunctionContent( @@ -115,6 +142,10 @@ private static StringBuilder GenerateFields( { switch (resolution) { + case LazyResolution(var reference, var typeFullName, _): + stringBuilder = stringBuilder + .AppendLine($"{typeFullName} {reference};"); + break; case TaskFromTaskResolution(var wrappedResolvable, _, var taskReference, var taskFullName): stringBuilder = GenerateFields(stringBuilder, wrappedResolvable); stringBuilder = stringBuilder @@ -145,15 +176,13 @@ private static StringBuilder GenerateFields( stringBuilder = stringBuilder .AppendLine($"{valueTaskFullName} {valueTaskReference};"); break; - case TransientScopeRootResolution(var reference, var typeFullName, var transientScopeReference, var transientScopeTypeFullName, _, _, _, _): - stringBuilder = stringBuilder - .AppendLine($"{transientScopeTypeFullName} {transientScopeReference};") - .AppendLine($"{typeFullName} {reference};"); + case TransientScopeRootResolution(var transientScopeReference, var transientScopeTypeFullName, _, _, var functionCallResolution): + stringBuilder = stringBuilder.AppendLine($"{transientScopeTypeFullName} {transientScopeReference};"); + stringBuilder = GenerateFields(stringBuilder, functionCallResolution); break; - case ScopeRootResolution(var reference, var typeFullName, var scopeReference, var scopeTypeFullName, _, _, _, _, _): - stringBuilder = stringBuilder - .AppendLine($"{scopeTypeFullName} {scopeReference};") - .AppendLine($"{typeFullName} {reference};"); + case ScopeRootResolution(var scopeReference, var scopeTypeFullName, _, _, _, var functionCallResolution): + stringBuilder = stringBuilder.AppendLine($"{scopeTypeFullName} {scopeReference};"); + stringBuilder = GenerateFields(stringBuilder, functionCallResolution); break; case TransientScopeAsDisposableResolution(var reference, var typeFullName): stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); @@ -175,11 +204,13 @@ private static StringBuilder GenerateFields( stringBuilder = items.Aggregate(stringBuilder, GenerateFields); stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); break; - case FuncResolution(var reference, var typeFullName, _, _): + case FuncResolution(var reference, var typeFullName, _): stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); break; case ParameterResolution: break; // the parameter is the field + case MethodGroupResolution: + break; // referenced directly case FieldResolution(var reference, var typeFullName, _): stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); break; @@ -208,6 +239,20 @@ private StringBuilder GenerateResolutions( { switch (resolution) { + case LazyResolution(var reference, var typeFullName, var methodGroup): + string owner = ""; + if (methodGroup.OwnerReference is { } explicitOwner) + owner = $"{explicitOwner}."; + stringBuilder = stringBuilder + .AppendLine($"{reference} = new {typeFullName}({owner}{methodGroup.Reference});"); + break; + case FunctionCallResolution(var reference, var typeFullName, var functionReference, var functionOwner, var parameters): + string owner2 = ""; + if (functionOwner is { } explicitOwner2) + owner2 = $"{explicitOwner2}."; + stringBuilder = stringBuilder + .AppendLine($"{reference} = ({typeFullName}){owner2}{functionReference}({string.Join(", ", parameters.Select(p => $"{p.Name}: {p.Reference}"))});"); + break; case TaskFromTaskResolution(var wrappedResolvable, var initialization, var taskReference, _): stringBuilder = GenerateResolutions(stringBuilder, wrappedResolvable); stringBuilder = stringBuilder @@ -272,23 +317,20 @@ private StringBuilder GenerateResolutions( stringBuilder = GenerateResolutions(stringBuilder, wrappedResolvable); stringBuilder = stringBuilder.AppendLine($"{valueTaskReference} = {WellKnownTypes.ValueTask.FullName()}.FromResult({wrappedResolvable.Reference});"); break; - case TransientScopeRootResolution(var reference, var typeFullName, var transientScopeReference, var transientScopeTypeFullName, var containerInstanceScopeReference, var parameter, var (_, _, _, _, _, _), var (createFunctionReference, _)): + case TransientScopeRootResolution(var transientScopeReference, var transientScopeTypeFullName, var containerInstanceScopeReference, var (_, _, _, _, _, _), var createFunctionCall): stringBuilder = stringBuilder .AppendLine($"{transientScopeReference} = new {transientScopeTypeFullName}({containerInstanceScopeReference});") - .AppendLine($"{_rangeResolution.ContainerReference}.{_containerResolution.DisposalHandling.DisposableCollection.Reference}.Add(({WellKnownTypes.Disposable.FullName()}) {transientScopeReference});") - .AppendLine($"{reference} = ({typeFullName}) {transientScopeReference}.{createFunctionReference}({string.Join(", ", parameter.Select(p => p.Reference))});"); + .AppendLine($"{_rangeResolution.ContainerReference}.{_containerResolution.DisposalHandling.DisposableCollection.Reference}.Add(({WellKnownTypes.Disposable.FullName()}) {transientScopeReference});"); + stringBuilder = GenerateResolutions(stringBuilder, createFunctionCall); _isDisposalHandlingRequired = true; break; - case ScopeRootResolution(var reference, var typeFullName, var scopeReference, var scopeTypeFullName, var containerInstanceScopeReference, var transientInstanceScopeReference, var parameter, var (disposableCollectionReference, _, _, _, _, _), var (createFunctionReference, _)): + case ScopeRootResolution(var scopeReference, var scopeTypeFullName, var containerInstanceScopeReference, var transientInstanceScopeReference, var (disposableCollectionReference, _, _, _, _, _), var createFunctionCall): stringBuilder = stringBuilder .AppendLine($"{scopeReference} = new {scopeTypeFullName}({containerInstanceScopeReference}, {transientInstanceScopeReference});") - .AppendLine($"{disposableCollectionReference}.Add(({WellKnownTypes.Disposable.FullName()}) {scopeReference});") - .AppendLine($"{reference} = ({typeFullName}) {scopeReference}.{createFunctionReference}({string.Join(", ", parameter.Select(p => p.Reference))});"); + .AppendLine($"{disposableCollectionReference}.Add(({WellKnownTypes.Disposable.FullName()}) {scopeReference});"); + stringBuilder = GenerateResolutions(stringBuilder, createFunctionCall); _isDisposalHandlingRequired = true; break; - case RangedInstanceReferenceResolution(var reference, { Reference: {} functionReference}, var parameter, var owningObjectReference): - stringBuilder = stringBuilder.AppendLine($"{reference} = {owningObjectReference}.{functionReference}({string.Join(", ", parameter.Select(p => p.Reference))});"); - break; case InterfaceResolution(var reference, var typeFullName, Resolvable resolutionBase): stringBuilder = GenerateResolutions(stringBuilder, resolutionBase); stringBuilder = stringBuilder.AppendLine( @@ -334,12 +376,12 @@ private StringBuilder GenerateResolutions( stringBuilder = items.Aggregate(stringBuilder, GenerateResolutions); stringBuilder = stringBuilder.AppendLine($"{reference} = ({string.Join(", ", items.Select(d => d.Reference))});"); break; - case FuncResolution(var reference, _, var parameter, Resolvable resolutionBase): - stringBuilder = stringBuilder.AppendLine($"{reference} = ({string.Join(", ", parameter.Select(fpr => fpr.Reference))}) =>"); - stringBuilder = stringBuilder.AppendLine($"{{"); - GenerateResolutionFunctionContent(stringBuilder, resolutionBase); - stringBuilder = stringBuilder.AppendLine($"return {resolutionBase.Reference};"); - stringBuilder = stringBuilder.AppendLine($"}};"); + case FuncResolution(var reference, _, var methodGroup): + string owner1 = ""; + if (methodGroup.OwnerReference is { } explicitOwner1) + owner1 = $"{explicitOwner1}."; + stringBuilder = stringBuilder + .AppendLine($"{reference} = {owner1}{methodGroup.Reference};"); break; case ParameterResolution: break; // parameter exists already @@ -363,40 +405,40 @@ private StringBuilder GenerateResolutions( return stringBuilder; } - private StringBuilder GenerateRangedInstanceFunction(StringBuilder stringBuilder, RangedInstance rangedInstance) + private StringBuilder GenerateRangedInstanceFunction(StringBuilder stringBuilder, RangedInstanceFunctionGroupResolution rangedInstanceFunctionGroupResolution) { stringBuilder = stringBuilder .AppendLine( - $"private {rangedInstance.Function.TypeFullName} {rangedInstance.Function.FieldReference};") + $"private {rangedInstanceFunctionGroupResolution.TypeFullName} {rangedInstanceFunctionGroupResolution.FieldReference};") .AppendLine( - $"private {WellKnownTypes.SemaphoreSlim.FullName()} {rangedInstance.Function.LockReference} = new {WellKnownTypes.SemaphoreSlim.FullName()}(1);"); + $"private {WellKnownTypes.SemaphoreSlim.FullName()} {rangedInstanceFunctionGroupResolution.LockReference} = new {WellKnownTypes.SemaphoreSlim.FullName()}(1);"); - foreach (var (resolvable, funcParameterResolutions) in rangedInstance.Overloads) + foreach (var overload in rangedInstanceFunctionGroupResolution.Overloads) { var parameters = string.Join(", ", - funcParameterResolutions.Select(p => $"{p.TypeFullName} {p.Reference}")); + overload.Parameter.Select(p => $"{p.TypeFullName} {p.Reference}")); stringBuilder = stringBuilder.AppendLine( - $"public {rangedInstance.Function.TypeFullName} {rangedInstance.Function.Reference}({parameters})") + $"public {overload.TypeFullName} {overload.Reference}({parameters})") .AppendLine($"{{") - .AppendLine($"this.{rangedInstance.Function.LockReference}.Wait();") + .AppendLine($"this.{rangedInstanceFunctionGroupResolution.LockReference}.Wait();") .AppendLine($"try") .AppendLine($"{{") .AppendLine( - $"if (this.{rangedInstance.DisposalHandling.DisposedPropertyReference}) throw new {WellKnownTypes.ObjectDisposedException}(nameof({rangedInstance.DisposalHandling.RangeName}));") + $"if (this.{overload.DisposalHandling.DisposedPropertyReference}) throw new {WellKnownTypes.ObjectDisposedException}(nameof({overload.DisposalHandling.RangeName}));") .AppendLine( - $"if (!object.ReferenceEquals({rangedInstance.Function.FieldReference}, null)) return {rangedInstance.Function.FieldReference};"); + $"if (!object.ReferenceEquals({rangedInstanceFunctionGroupResolution.FieldReference}, null)) return {rangedInstanceFunctionGroupResolution.FieldReference};"); - stringBuilder = GenerateResolutionFunctionContent(stringBuilder, resolvable); + stringBuilder = GenerateResolutionFunctionContent(stringBuilder, overload.Resolvable); stringBuilder = stringBuilder .AppendLine( - $"this.{rangedInstance.Function.FieldReference} = {resolvable.Reference};") + $"this.{rangedInstanceFunctionGroupResolution.FieldReference} = {overload.Resolvable.Reference};") .AppendLine($"}}") .AppendLine($"finally") .AppendLine($"{{") - .AppendLine($"this.{rangedInstance.Function.LockReference}.Release();") + .AppendLine($"this.{rangedInstanceFunctionGroupResolution.LockReference}.Release();") .AppendLine($"}}") - .AppendLine($"return this.{rangedInstance.Function.FieldReference};") + .AppendLine($"return this.{rangedInstanceFunctionGroupResolution.FieldReference};") .AppendLine($"}}"); } diff --git a/Main/CodeBuilding/ScopeCodeBuilder.cs b/Main/CodeBuilding/ScopeCodeBuilder.cs index 9c77228f..2193c752 100644 --- a/Main/CodeBuilding/ScopeCodeBuilder.cs +++ b/Main/CodeBuilding/ScopeCodeBuilder.cs @@ -13,7 +13,7 @@ internal class ScopeCodeBuilder : RangeCodeBaseBuilder, IScopeCodeBuilder public override StringBuilder Build(StringBuilder stringBuilder) { - if (!_scopeResolution.RootResolutions.Any() && !_scopeResolution.RangedInstances.Any()) + if (!_scopeResolution.RootResolutions.Any() && !_scopeResolution.RangedInstanceFunctionGroups.Any()) return stringBuilder; stringBuilder = stringBuilder diff --git a/Main/CodeBuilding/TransientScopeCodeBuilder.cs b/Main/CodeBuilding/TransientScopeCodeBuilder.cs index 646d5905..fbfe8e29 100644 --- a/Main/CodeBuilding/TransientScopeCodeBuilder.cs +++ b/Main/CodeBuilding/TransientScopeCodeBuilder.cs @@ -13,7 +13,7 @@ internal class TransientScopeCodeBuilder : RangeCodeBaseBuilder, ITransientScope public override StringBuilder Build(StringBuilder stringBuilder) { - if (!_transientScopeResolution.RootResolutions.Any() && !_transientScopeResolution.RangedInstances.Any()) + if (!_transientScopeResolution.RootResolutions.Any() && !_transientScopeResolution.RangedInstanceFunctionGroups.Any()) return stringBuilder; stringBuilder = stringBuilder diff --git a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs index ae416d5b..8832c9da 100644 --- a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs @@ -6,7 +6,7 @@ internal interface IContainerResolutionBuilder : IRangeResolutionBaseBuilder { void AddCreateResolveFunctions(IReadOnlyList rootTypes); - RangedInstanceReferenceResolution CreateContainerInstanceReferenceResolution( + FunctionCallResolution CreateContainerInstanceReferenceResolution( ForConstructorParameter parameter, string containerReference); @@ -17,9 +17,9 @@ internal class ContainerResolutionBuilder : RangeResolutionBaseBuilder, IContain { private readonly IContainerInfo _containerInfo; private readonly ITransientScopeInterfaceResolutionBuilder _transientScopeInterfaceResolutionBuilder; - private readonly Func _functionResolutionBuilderFactory; + private readonly Func _createFunctionResolutionBuilderFactory; - private readonly List _rootResolutions = new (); + private readonly List _rootResolutions = new (); private readonly string _transientScopeAdapterReference; private readonly IScopeManager _scopeManager; @@ -33,7 +33,8 @@ internal ContainerResolutionBuilder( ICheckTypeProperties checkTypeProperties, WellKnownTypes wellKnownTypes, Func scopeManagerFactory, - Func functionResolutionBuilderFactory, + Func createFunctionResolutionBuilderFactory, + Func rangedFunctionGroupResolutionBuilderFactory, IUserProvidedScopeElements userProvidedScopeElement) : base( containerInfo.Name, @@ -41,11 +42,11 @@ internal ContainerResolutionBuilder( userProvidedScopeElement, wellKnownTypes, referenceGeneratorFactory, - functionResolutionBuilderFactory) + rangedFunctionGroupResolutionBuilderFactory) { _containerInfo = containerInfo; _transientScopeInterfaceResolutionBuilder = transientScopeInterfaceResolutionBuilder; - _functionResolutionBuilderFactory = functionResolutionBuilderFactory; + _createFunctionResolutionBuilderFactory = createFunctionResolutionBuilderFactory; _scopeManager = scopeManagerFactory(this, transientScopeInterfaceResolutionBuilder); transientScopeInterfaceResolutionBuilder.AddImplementation(this); @@ -54,30 +55,21 @@ internal ContainerResolutionBuilder( public void AddCreateResolveFunctions(IReadOnlyList rootTypes) { - var i = 0; foreach (var typeSymbol in rootTypes) - _rootResolutions.Add(new RootResolutionFunction( - $"Create{i++}", - typeSymbol.FullName(), - "public", - _functionResolutionBuilderFactory(this).ResolveFunction(new SwitchTypeParameter( - typeSymbol, - Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>())), - Array.Empty(), - _containerInfo.Name, - DisposalHandling)); + _rootResolutions.Add(_createFunctionResolutionBuilderFactory(this, typeSymbol)); } - public RangedInstanceReferenceResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter, string containerReference) => + public FunctionCallResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter, string containerReference) => CreateRangedInstanceReferenceResolution( parameter, "Container", + null, containerReference); - public override RangedInstanceReferenceResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter) => + public override FunctionCallResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter) => CreateContainerInstanceReferenceResolution(parameter, "this"); - public override RangedInstanceReferenceResolution CreateTransientScopeInstanceReferenceResolution(ForConstructorParameter parameter) => + public override FunctionCallResolution CreateTransientScopeInstanceReferenceResolution(ForConstructorParameter parameter) => _transientScopeInterfaceResolutionBuilder.CreateTransientScopeInstanceReferenceResolution(parameter, "this"); public override TransientScopeRootResolution CreateTransientScopeRootResolution(IScopeRootParameter parameter, INamedTypeSymbol rootType, @@ -108,7 +100,35 @@ public override ScopeRootResolution CreateScopeRootResolution( public ContainerResolution Build() { - while (RangedInstanceResolutionsQueue.Any() + var privateRootFunctions = _rootResolutions + .Select(b => b.Build()) + .Select(f => new RootResolutionFunction( + f.Reference, + f.TypeFullName, + "private", + f.Resolvable, + f.Parameter, + DisposalHandling, + f.LocalFunctions)) + .ToList(); + + var i = 0; + var publicRootFunctions = privateRootFunctions + .Select(f => new RootResolutionFunction( + $"Create{i++}", + f.TypeFullName, + "public", + new FunctionCallResolution( + RootReferenceGenerator.Generate("result"), + f.TypeFullName, + f.Reference, + "this", + Array.Empty<(string, string)>()), + f.Parameter, + DisposalHandling, + Array.Empty())); + + while (RangedInstanceReferenceResolutions.Values.Any(r => r.HasWorkToDo) || _scopeManager.HasWorkToDo) { DoRangedInstancesWork(); @@ -116,22 +136,23 @@ public ContainerResolution Build() } var (transientScopeResolutions, scopeResolutions) = _scopeManager.Build(); - + return new( - _rootResolutions, + privateRootFunctions.Concat(publicRootFunctions).ToList(), DisposalHandling, - RangedInstances - .GroupBy(t => t.Item1) - .Select(g => new RangedInstance( - g.Key, - g.Select(t => t.Item2).ToList(), - DisposalHandling)) - .ToList(), + RangedInstanceReferenceResolutions.Values.Select(b => b.Build()).ToList(), _transientScopeInterfaceResolutionBuilder.Build(), _transientScopeAdapterReference, transientScopeResolutions, scopeResolutions); } - public void EnqueueRangedInstanceResolution(RangedInstanceResolutionsQueueItem item) => RangedInstanceResolutionsQueue.Enqueue(item); + public void EnqueueRangedInstanceResolution( + ForConstructorParameter parameter, + string label, + string reference) => CreateRangedInstanceReferenceResolution( + parameter, + label, + reference, + "Doesn'tMatter"); } \ No newline at end of file diff --git a/Main/ResolutionBuilding/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/FunctionResolutionBuilder.cs index 54997297..707ab1ce 100644 --- a/Main/ResolutionBuilding/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/FunctionResolutionBuilder.cs @@ -4,42 +4,274 @@ namespace MrMeeseeks.DIE.ResolutionBuilding; internal interface IFunctionResolutionBuilder { - Resolvable ResolveFunction(SwitchTypeParameter parameter); - Resolvable RangedFunction(ForConstructorParameter parameter); - Resolvable ScopeRootFunction(CreateInterfaceParameter parameter); - Resolvable ScopeRootFunction(SwitchImplementationParameter parameter); - Resolvable ScopeRootFunction(SwitchInterfaceAfterScopeRootParameter parameter); + FunctionCallResolution BuildFunctionCall( + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters, + string? ownerReference); + + MethodGroupResolution BuildMethodGroup(); + + FunctionResolution Build(); +} + +internal interface ILocalFunctionResolutionBuilder : IFunctionResolutionBuilder +{ +} + +internal class LocalFunctionResolutionBuilder : FunctionResolutionBuilder, ILocalFunctionResolutionBuilder +{ + private readonly IRangeResolutionBaseBuilder _rangeResolutionBaseBuilder; + private readonly INamedTypeSymbol _returnType; + private readonly IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> _parameters; + + public LocalFunctionResolutionBuilder( + // parameter + IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, + INamedTypeSymbol returnType, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> parameters, + + + // dependencies + WellKnownTypes wellKnownTypes, + IReferenceGeneratorFactory referenceGeneratorFactory, + Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) + : base(rangeResolutionBaseBuilder, returnType, parameters, wellKnownTypes, referenceGeneratorFactory, localFunctionResolutionBuilderFactory) + { + _rangeResolutionBaseBuilder = rangeResolutionBaseBuilder; + _returnType = returnType; + _parameters = parameters; + + Name = RootReferenceGenerator.Generate("Create", _returnType); + } + + protected override string Name { get; } + + public override FunctionResolution Build() => + new(Name, + TypeFullName, + SwitchType(new SwitchTypeParameter(_returnType, _parameters)).Item1, + _parameters.Select(t => t.Resolution).ToList(), + _rangeResolutionBaseBuilder.DisposalHandling, + LocalFunctions + .Select(lf => lf.Build()) + .Select(f => new LocalFunctionResolution( + f.Reference, + f.TypeFullName, + f.Resolvable, + f.Parameter, + f.DisposalHandling, + f.LocalFunctions)) + .ToList()); +} + +internal interface IContainerCreateFunctionResolutionBuilder : IFunctionResolutionBuilder +{ +} + +internal class ContainerCreateFunctionResolutionBuilder : FunctionResolutionBuilder, IContainerCreateFunctionResolutionBuilder +{ + private readonly IRangeResolutionBaseBuilder _rangeResolutionBaseBuilder; + private readonly INamedTypeSymbol _returnType; + + public ContainerCreateFunctionResolutionBuilder( + // parameter + IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, + INamedTypeSymbol returnType, + + + // dependencies + WellKnownTypes wellKnownTypes, + IReferenceGeneratorFactory referenceGeneratorFactory, + Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) + : base(rangeResolutionBaseBuilder, returnType, Array.Empty<(ITypeSymbol, ParameterResolution)>(), wellKnownTypes, referenceGeneratorFactory, localFunctionResolutionBuilderFactory) + { + _rangeResolutionBaseBuilder = rangeResolutionBaseBuilder; + _returnType = returnType; + + Name = RootReferenceGenerator.Generate("Create"); + } + + protected override string Name { get; } + + public override FunctionResolution Build() => + new(RootReferenceGenerator.Generate("Create"), + TypeFullName, + SwitchType(new SwitchTypeParameter( + _returnType, + Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>())).Item1, + Array.Empty(), + _rangeResolutionBaseBuilder.DisposalHandling, + LocalFunctions + .Select(lf => lf.Build()) + .Select(f => new LocalFunctionResolution( + f.Reference, + f.TypeFullName, + f.Resolvable, + f.Parameter, + f.DisposalHandling, + f.LocalFunctions)) + .ToList()); } -internal class FunctionResolutionBuilder : IFunctionResolutionBuilder +internal interface IScopeRootCreateFunctionResolutionBuilder : IFunctionResolutionBuilder +{ +} + +internal class ScopeRootCreateFunctionResolutionBuilder : FunctionResolutionBuilder, IScopeRootCreateFunctionResolutionBuilder { + private readonly IRangeResolutionBaseBuilder _rangeResolutionBaseBuilder; + private readonly IScopeRootParameter _scopeRootParameter; + + public ScopeRootCreateFunctionResolutionBuilder( + // parameter + IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, + IScopeRootParameter scopeRootParameter, + + + // dependencies + WellKnownTypes wellKnownTypes, + IReferenceGeneratorFactory referenceGeneratorFactory, + Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) + : base(rangeResolutionBaseBuilder, scopeRootParameter.ReturnType, scopeRootParameter.CurrentParameters, wellKnownTypes, referenceGeneratorFactory, localFunctionResolutionBuilderFactory) + { + _rangeResolutionBaseBuilder = rangeResolutionBaseBuilder; + _scopeRootParameter = scopeRootParameter; + + Name = RootReferenceGenerator.Generate("Create"); + } + + protected override string Name { get; } + + public override FunctionResolution Build() + { + var resolvable = _scopeRootParameter switch + { + CreateInterfaceParameter createInterfaceParameter => CreateInterface(createInterfaceParameter).Item1, + SwitchImplementationParameter switchImplementationParameter => SwitchImplementation(switchImplementationParameter).Item1, + SwitchInterfaceAfterScopeRootParameter switchInterfaceAfterScopeRootParameter => SwitchInterfaceAfterScopeRoot(switchInterfaceAfterScopeRootParameter).Item1, + _ => throw new ArgumentOutOfRangeException(nameof(_scopeRootParameter)) + }; + + return new( + Name, + TypeFullName, + resolvable, + Parameters, + _rangeResolutionBaseBuilder.DisposalHandling, + LocalFunctions + .Select(lf => lf.Build()) + .Select(f => new LocalFunctionResolution( + f.Reference, + f.TypeFullName, + f.Resolvable, + f.Parameter, + f.DisposalHandling, + f.LocalFunctions)) + .ToList()); + } +} + +internal interface IRangedFunctionResolutionBuilder : IFunctionResolutionBuilder +{ +} + +internal class RangedFunctionResolutionBuilder : FunctionResolutionBuilder, IRangedFunctionResolutionBuilder +{ + private readonly IRangeResolutionBaseBuilder _rangeResolutionBaseBuilder; + private readonly string _reference; + private readonly ForConstructorParameter _forConstructorParameter; + + public RangedFunctionResolutionBuilder( + // parameter + IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, + string reference, + ForConstructorParameter forConstructorParameter, + + + // dependencies + WellKnownTypes wellKnownTypes, + IReferenceGeneratorFactory referenceGeneratorFactory, + Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) + : base(rangeResolutionBaseBuilder, forConstructorParameter.ImplementationType, forConstructorParameter.CurrentFuncParameters, wellKnownTypes, referenceGeneratorFactory, localFunctionResolutionBuilderFactory) + { + _rangeResolutionBaseBuilder = rangeResolutionBaseBuilder; + _reference = reference; + _forConstructorParameter = forConstructorParameter; + + Name = reference; + } + + protected override string Name { get; } + + public override FunctionResolution Build() + { + var resolvable = CreateConstructorResolution(_forConstructorParameter).Item1; + + return new( + _reference, + TypeFullName, + resolvable, + _forConstructorParameter.CurrentFuncParameters.Select(t => t.Resolution).ToList(), + _rangeResolutionBaseBuilder.DisposalHandling, + LocalFunctions + .Select(lf => lf.Build()) + .Select(f => new LocalFunctionResolution( + f.Reference, + f.TypeFullName, + f.Resolvable, + f.Parameter, + f.DisposalHandling, + f.LocalFunctions)) + .ToList()); + } +} + +internal abstract class FunctionResolutionBuilder : IFunctionResolutionBuilder +{ + public INamedTypeSymbol ReturnType { get; } private readonly IRangeResolutionBaseBuilder _rangeResolutionBaseBuilder; private readonly WellKnownTypes _wellKnownTypes; + private readonly Func, ILocalFunctionResolutionBuilder> _localFunctionResolutionBuilderFactory; private readonly ICheckTypeProperties _checkTypeProperties; - private readonly IReferenceGenerator _rootReferenceGenerator; + protected readonly IReferenceGenerator RootReferenceGenerator; private readonly DisposableCollectionResolution _disposableCollectionResolution; private readonly IUserProvidedScopeElements _userProvidedScopeElements; + protected readonly IList LocalFunctions = new List(); + + protected abstract string Name { get; } + protected string TypeFullName => ReturnType.FullName(); + + protected IReadOnlyList Parameters { get; } + internal FunctionResolutionBuilder( // parameters IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, + INamedTypeSymbol returnType, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters, + // dependencies WellKnownTypes wellKnownTypes, - IReferenceGeneratorFactory referenceGeneratorFactory) + IReferenceGeneratorFactory referenceGeneratorFactory, + Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) { + ReturnType = returnType; _rangeResolutionBaseBuilder = rangeResolutionBaseBuilder; _wellKnownTypes = wellKnownTypes; + _localFunctionResolutionBuilderFactory = localFunctionResolutionBuilderFactory; _checkTypeProperties = rangeResolutionBaseBuilder.CheckTypeProperties; _userProvidedScopeElements = rangeResolutionBaseBuilder.UserProvidedScopeElements; - _rootReferenceGenerator = referenceGeneratorFactory.Create(); + RootReferenceGenerator = referenceGeneratorFactory.Create(); _disposableCollectionResolution = _rangeResolutionBaseBuilder.DisposableCollectionResolution; + Parameters = currentParameters + .Select(p => new ParameterResolution(RootReferenceGenerator.Generate(p.Type), TypeFullName)) + .ToList(); } - private (Resolvable, ConstructorResolution?) SwitchType(SwitchTypeParameter parameter) + protected (Resolvable, ConstructorResolution?) SwitchType(SwitchTypeParameter parameter) { var (type, currentFuncParameters) = parameter; if (currentFuncParameters.FirstOrDefault(t => SymbolEqualityComparer.Default.Equals(t.Type.OriginalDefinition, type.OriginalDefinition)) is { Type: not null, Resolution: not null } funcParameter) @@ -48,7 +280,7 @@ internal FunctionResolutionBuilder( if (_userProvidedScopeElements.GetInstanceFor(type) is { } instance) return ( new FieldResolution( - _rootReferenceGenerator.Generate(instance.Type), + RootReferenceGenerator.Generate(instance.Type), instance.Type.FullName(), instance.Name), null); @@ -56,7 +288,7 @@ internal FunctionResolutionBuilder( if (_userProvidedScopeElements.GetPropertyFor(type) is { } property) return ( new FieldResolution( - _rootReferenceGenerator.Generate(property.Type), + RootReferenceGenerator.Generate(property.Type), property.Type.FullName(), property.Name), null); @@ -64,7 +296,7 @@ internal FunctionResolutionBuilder( if (_userProvidedScopeElements.GetFactoryFor(type) is { } factory) return ( new FactoryResolution( - _rootReferenceGenerator.Generate(factory.ReturnType), + RootReferenceGenerator.Generate(factory.ReturnType), factory.ReturnType.FullName(), factory.Name, factory @@ -84,7 +316,7 @@ internal FunctionResolutionBuilder( if (type.FullName().StartsWith("global::System.ValueTuple<") && type is INamedTypeSymbol valueTupleType) { var constructorResolution = new ConstructorResolution( - _rootReferenceGenerator.Generate(valueTupleType), + RootReferenceGenerator.Generate(valueTupleType), valueTupleType.FullName(), ImplementsIDisposable(valueTupleType, _wellKnownTypes, _disposableCollectionResolution, _checkTypeProperties), valueTupleType @@ -101,7 +333,7 @@ internal FunctionResolutionBuilder( var itemTypes = GetTypeArguments(syntaxValueTupleType).ToList(); return (new SyntaxValueTupleResolution( - _rootReferenceGenerator.Generate("syntaxValueTuple"), + RootReferenceGenerator.Generate("syntaxValueTuple"), syntaxValueTupleType.FullName(), itemTypes .Select(t => SwitchType(new SwitchTypeParameter(t, currentFuncParameters)).Item1) @@ -142,29 +374,45 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup }), null); } - - var dependency = SwitchType(new SwitchTypeParameter( - genericType, - Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>())); - var constructorInjection = new ConstructorResolution( - _rootReferenceGenerator.Generate(namedTypeSymbol), + + var newLocalFunction = _localFunctionResolutionBuilderFactory(_rangeResolutionBaseBuilder, genericType, Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>()); + LocalFunctions.Add(newLocalFunction); + + var constructorInjection = new LazyResolution( + RootReferenceGenerator.Generate(namedTypeSymbol), namedTypeSymbol.FullName(), - ImplementsIDisposable(namedTypeSymbol, _wellKnownTypes, _disposableCollectionResolution, _checkTypeProperties), - new ReadOnlyCollection<(string Name, Resolvable Dependency)>( - new List<(string Name, Resolvable Dependency)> - { - ( - "valueFactory", - new FuncResolution( - _rootReferenceGenerator.Generate("func"), - $"global::System.Func<{genericType.FullName()}>", - Array.Empty(), - dependency.Item1) - ) - }), - Array.Empty<(string Name, Resolvable Dependency)>(), + newLocalFunction.BuildMethodGroup()); + return (constructorInjection, null); + } + + if (type.TypeKind == TypeKind.Delegate + && type.FullName().StartsWith("global::System.Func<") + && type is INamedTypeSymbol namedTypeSymbol0) + { + var returnTypeRaw = namedTypeSymbol0.TypeArguments.Last(); + + if (returnTypeRaw is not INamedTypeSymbol returnType) + { + return ( + new ErrorTreeItem($"[{type.FullName()}] Func: Return type not named"), + null); + } + + var parameterTypes = namedTypeSymbol0 + .TypeArguments + .Take(namedTypeSymbol0.TypeArguments.Length - 1) + .Select(ts => (Type: ts, Resolution: new ParameterResolution(RootReferenceGenerator.Generate(ts), ts.FullName()))) + .ToArray(); + + var newLocalFunction = _localFunctionResolutionBuilderFactory(_rangeResolutionBaseBuilder, returnType, parameterTypes); + LocalFunctions.Add(newLocalFunction); + + return ( + new FuncResolution( + RootReferenceGenerator.Generate(type), + type.FullName(), + newLocalFunction.BuildMethodGroup()), null); - return (constructorInjection, constructorInjection); } if (type.OriginalDefinition.Equals(_wellKnownTypes.Enumerable1, SymbolEqualityComparer.Default) @@ -243,7 +491,7 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup return ( new CollectionResolution( - _rootReferenceGenerator.Generate(type), + RootReferenceGenerator.Generate(type), type.FullName(), wrappedItemType.FullName(), items), @@ -256,29 +504,6 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup if (type.TypeKind is TypeKind.Class or TypeKind.Struct) return SwitchClass(new SwitchClassParameter(type, currentFuncParameters)); - if (type.TypeKind == TypeKind.Delegate - && type.FullName().StartsWith("global::System.Func<") - && type is INamedTypeSymbol namedTypeSymbol0) - { - var returnType = namedTypeSymbol0.TypeArguments.Last(); - var parameterTypes = namedTypeSymbol0 - .TypeArguments - .Take(namedTypeSymbol0.TypeArguments.Length - 1) - .Select(ts => (Type: ts, Resolution: new ParameterResolution(_rootReferenceGenerator.Generate(ts), ts.FullName()))) - .ToArray(); - - var dependency = SwitchType(new SwitchTypeParameter( - returnType, - parameterTypes)); - return ( - new FuncResolution( - _rootReferenceGenerator.Generate(type), - type.FullName(), - parameterTypes.Select(t => t.Resolution).ToArray(), - dependency.Item1), - null); - } - return ( new ErrorTreeItem($"[{type.FullName()}] Couldn't process in resolution tree creation."), null); @@ -292,7 +517,7 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup .ConstructUnboundGenericType() .FullName() .Replace("<>", $"<{resolution.Item1.TypeFullName}>"); - var wrappedTaskReference = _rootReferenceGenerator.Generate(_wellKnownTypes.Task); + var wrappedTaskReference = RootReferenceGenerator.Generate(_wellKnownTypes.Task); if (resolution.Item2 is { } constructorResolution) { if (constructorResolution.Initialization is TaskBaseTypeInitializationResolution taskBaseResolution) @@ -324,7 +549,7 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup .ConstructUnboundGenericType() .FullName() .Replace("<>", $"<{resolution.Item1.TypeFullName}>"); - var wrappedValueTaskReference = _rootReferenceGenerator.Generate(_wellKnownTypes.ValueTask); + var wrappedValueTaskReference = RootReferenceGenerator.Generate(_wellKnownTypes.ValueTask); if (resolution.Item2 is { } constructorResolution) { if (constructorResolution.Initialization is TaskBaseTypeInitializationResolution taskBaseResolution) @@ -377,7 +602,7 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup }; } - private (Resolvable, ConstructorResolution?) SwitchInterfaceAfterScopeRoot( + protected (Resolvable, ConstructorResolution?) SwitchInterfaceAfterScopeRoot( SwitchInterfaceAfterScopeRootParameter parameter) { var (interfaceType, implementations, currentParameters) = parameter; @@ -444,7 +669,7 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup }; } - private (InterfaceResolution, ConstructorResolution?) CreateInterface(CreateInterfaceParameter parameter) + protected (InterfaceResolution, ConstructorResolution?) CreateInterface(CreateInterfaceParameter parameter) { var (interfaceType, implementationType, currentParameters) = parameter; var shouldBeDecorated = _checkTypeProperties.ShouldBeDecorated(interfaceType); @@ -461,7 +686,7 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup }; var currentInterfaceResolution = new InterfaceResolution( - _rootReferenceGenerator.Generate(interfaceType), + RootReferenceGenerator.Generate(interfaceType), interfaceType.FullName(), SwitchImplementation(nextParameter).Item1); @@ -481,7 +706,7 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup currentParameters, decoration)).Item1; currentInterfaceResolution = new InterfaceResolution( - _rootReferenceGenerator.Generate(interfaceType), + RootReferenceGenerator.Generate(interfaceType), interfaceType.FullName(), decoratorResolution); } @@ -528,7 +753,7 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup }; } - private (Resolvable, ConstructorResolution?) SwitchImplementation(SwitchImplementationParameter parameter) + protected (Resolvable, ConstructorResolution?) SwitchImplementation(SwitchImplementationParameter parameter) { var (implementationType, currentParameters) = parameter; var scopeLevel = parameter switch @@ -561,7 +786,7 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup }; } - private (Resolvable, ConstructorResolution?) CreateConstructorResolution(ForConstructorParameter parameter) + protected (Resolvable, ConstructorResolution?) CreateConstructorResolution(ForConstructorParameter parameter) { var (implementationType, currentParameters) = parameter; @@ -613,20 +838,20 @@ false when initializationMethod.ReturnType.Equals(_wellKnownTypes.Task, SymbolEq initializationTypeFullName, initializationMethodName, _wellKnownTypes.Task.FullName(), - _rootReferenceGenerator.Generate(_wellKnownTypes.Task)), + RootReferenceGenerator.Generate(_wellKnownTypes.Task)), false when initializationMethod.ReturnType.Equals(_wellKnownTypes.ValueTask, SymbolEqualityComparer.Default) => new ValueTaskTypeInitializationResolution( initializationTypeFullName, initializationMethodName, _wellKnownTypes.ValueTask.FullName(), - _rootReferenceGenerator.Generate(_wellKnownTypes.ValueTask)), + RootReferenceGenerator.Generate(_wellKnownTypes.ValueTask)), _ => typeInitializationResolution }; } var resolution = new ConstructorResolution( - _rootReferenceGenerator.Generate(implementationType), + RootReferenceGenerator.Generate(implementationType), implementationType.FullName(), ImplementsIDisposable( implementationType, @@ -673,7 +898,7 @@ false when initializationMethod.ReturnType.Equals(_wellKnownTypes.ValueTask, Sym || typeSymbol.Equals(_wellKnownTypes.ReadOnlyCollection1.Construct(composition.InterfaceType), SymbolEqualityComparer.Default) || typeSymbol.Equals(_wellKnownTypes.ReadOnlyList1.Construct(composition.InterfaceType), SymbolEqualityComparer.Default)) return (parameterName, new CollectionResolution( - _rootReferenceGenerator.Generate(typeSymbol), + RootReferenceGenerator.Generate(typeSymbol), typeSymbol.FullName(), composition.InterfaceType.FullName(), composition.InterfaceResolutionComposition)); @@ -682,7 +907,7 @@ false when initializationMethod.ReturnType.Equals(_wellKnownTypes.ValueTask, Sym || typeSymbol.Equals(_wellKnownTypes.ReadOnlyCollection1.Construct(_wellKnownTypes.Task1.Construct(composition.InterfaceType)), SymbolEqualityComparer.Default) || typeSymbol.Equals(_wellKnownTypes.ReadOnlyList1.Construct(_wellKnownTypes.Task1.Construct(composition.InterfaceType)), SymbolEqualityComparer.Default)) return (parameterName, new CollectionResolution( - _rootReferenceGenerator.Generate(typeSymbol), + RootReferenceGenerator.Generate(typeSymbol), typeSymbol.FullName(), _wellKnownTypes.Task1.Construct(composition.InterfaceType).FullName(), composition.InterfaceResolutionComposition @@ -699,7 +924,7 @@ false when initializationMethod.ReturnType.Equals(_wellKnownTypes.ValueTask, Sym || typeSymbol.Equals(_wellKnownTypes.ReadOnlyCollection1.Construct(_wellKnownTypes.ValueTask1.Construct(composition.InterfaceType)), SymbolEqualityComparer.Default) || typeSymbol.Equals(_wellKnownTypes.ReadOnlyList1.Construct(_wellKnownTypes.ValueTask1.Construct(composition.InterfaceType)), SymbolEqualityComparer.Default)) return (parameterName, new CollectionResolution( - _rootReferenceGenerator.Generate(typeSymbol), + RootReferenceGenerator.Generate(typeSymbol), typeSymbol.FullName(), _wellKnownTypes.ValueTask1.Construct(composition.InterfaceType).FullName(), composition.InterfaceResolutionComposition @@ -716,7 +941,7 @@ false when initializationMethod.ReturnType.Equals(_wellKnownTypes.ValueTask, Sym if (isTransientScopeRoot && typeSymbol.Equals(_wellKnownTypes.Disposable, SymbolEqualityComparer.Default)) return (parameterName, new TransientScopeAsDisposableResolution( - _rootReferenceGenerator.Generate(_wellKnownTypes.Disposable), + RootReferenceGenerator.Generate(_wellKnownTypes.Disposable), _wellKnownTypes.Disposable.FullName())); if (typeSymbol is not INamedTypeSymbol parameterType) return ("", @@ -740,28 +965,15 @@ false when initializationMethod.ReturnType.Equals(_wellKnownTypes.ValueTask, Sym ? disposableCollectionResolution : null; - public Resolvable ResolveFunction(SwitchTypeParameter parameter) - { - return SwitchType(parameter).Item1; - } + public FunctionCallResolution BuildFunctionCall( + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters, string? ownerReference) => + new(RootReferenceGenerator.Generate("ret"), + TypeFullName, + Name, + ownerReference, + Parameters.Zip(currentParameters, (p, cp) => (p.Reference, cp.Resolution.Reference)).ToList()); - public Resolvable RangedFunction(ForConstructorParameter parameter) - { - return CreateConstructorResolution(parameter).Item1; - } + public MethodGroupResolution BuildMethodGroup() => new (Name, TypeFullName, null); - public Resolvable ScopeRootFunction(CreateInterfaceParameter parameter) - { - return CreateInterface(parameter).Item1; - } - - public Resolvable ScopeRootFunction(SwitchImplementationParameter parameter) - { - return SwitchImplementation(parameter).Item1; - } - - public Resolvable ScopeRootFunction(SwitchInterfaceAfterScopeRootParameter parameter) - { - return SwitchInterfaceAfterScopeRoot(parameter).Item1; - } + public abstract FunctionResolution Build(); } \ No newline at end of file diff --git a/Main/ResolutionBuilding/ITransientScopeImplementationResolutionBuilder.cs b/Main/ResolutionBuilding/ITransientScopeImplementationResolutionBuilder.cs index 6c0ebd11..60200759 100644 --- a/Main/ResolutionBuilding/ITransientScopeImplementationResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ITransientScopeImplementationResolutionBuilder.cs @@ -2,5 +2,8 @@ namespace MrMeeseeks.DIE.ResolutionBuilding; internal interface ITransientScopeImplementationResolutionBuilder { - void EnqueueRangedInstanceResolution(RangedInstanceResolutionsQueueItem item); + void EnqueueRangedInstanceResolution( + ForConstructorParameter parameter, + string label, + string reference); } \ No newline at end of file diff --git a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs index c8976084..d145c932 100644 --- a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs +++ b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs @@ -7,14 +7,15 @@ internal interface IRangeResolutionBaseBuilder ICheckTypeProperties CheckTypeProperties { get; } IUserProvidedScopeElements UserProvidedScopeElements { get; } DisposableCollectionResolution DisposableCollectionResolution { get; } + DisposalHandling DisposalHandling { get; } - RangedInstanceReferenceResolution CreateContainerInstanceReferenceResolution( + FunctionCallResolution CreateContainerInstanceReferenceResolution( ForConstructorParameter parameter); - RangedInstanceReferenceResolution CreateTransientScopeInstanceReferenceResolution( + FunctionCallResolution CreateTransientScopeInstanceReferenceResolution( ForConstructorParameter parameter); - RangedInstanceReferenceResolution CreateScopeInstanceReferenceResolution( + FunctionCallResolution CreateScopeInstanceReferenceResolution( ForConstructorParameter parameter); TransientScopeRootResolution CreateTransientScopeRootResolution( @@ -35,18 +36,14 @@ internal abstract class RangeResolutionBaseBuilder : IRangeResolutionBaseBuilder public ICheckTypeProperties CheckTypeProperties { get; } public IUserProvidedScopeElements UserProvidedScopeElements { get; } public DisposableCollectionResolution DisposableCollectionResolution { get; } + public DisposalHandling DisposalHandling { get; } protected readonly WellKnownTypes WellKnownTypes; - private readonly Func _functionResolutionBuilderFactory; + private readonly Func _rangedFunctionGroupResolutionBuilderFactory; protected readonly IReferenceGenerator RootReferenceGenerator; - protected readonly IDictionary RangedInstanceReferenceResolutions = - new Dictionary(); - protected readonly HashSet<(RangedInstanceFunction, string)> RangedInstanceQueuedOverloads = new (); - protected readonly Queue RangedInstanceResolutionsQueue = new(); - - protected readonly List<(RangedInstanceFunction, RangedInstanceFunctionOverload)> RangedInstances = new (); - protected readonly DisposalHandling DisposalHandling; + protected readonly IDictionary RangedInstanceReferenceResolutions = + new Dictionary(); protected readonly string Name; protected RangeResolutionBaseBuilder( @@ -58,12 +55,12 @@ protected RangeResolutionBaseBuilder( // dependencies WellKnownTypes wellKnownTypes, IReferenceGeneratorFactory referenceGeneratorFactory, - Func functionResolutionBuilderFactory) + Func rangedFunctionGroupResolutionBuilderFactory) { CheckTypeProperties = checkTypeProperties; UserProvidedScopeElements = userProvidedScopeElements; WellKnownTypes = wellKnownTypes; - _functionResolutionBuilderFactory = functionResolutionBuilderFactory; + _rangedFunctionGroupResolutionBuilderFactory = rangedFunctionGroupResolutionBuilderFactory; RootReferenceGenerator = referenceGeneratorFactory.Create(); DisposableCollectionResolution = new DisposableCollectionResolution( @@ -80,15 +77,16 @@ protected RangeResolutionBaseBuilder( RootReferenceGenerator.Generate("disposable")); } - public abstract RangedInstanceReferenceResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter); + public abstract FunctionCallResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter); - public abstract RangedInstanceReferenceResolution CreateTransientScopeInstanceReferenceResolution(ForConstructorParameter parameter); + public abstract FunctionCallResolution CreateTransientScopeInstanceReferenceResolution(ForConstructorParameter parameter); - public RangedInstanceReferenceResolution CreateScopeInstanceReferenceResolution( + public FunctionCallResolution CreateScopeInstanceReferenceResolution( ForConstructorParameter parameter) => CreateRangedInstanceReferenceResolution( parameter, "Scope", + null, "this"); public abstract TransientScopeRootResolution CreateTransientScopeRootResolution( @@ -103,9 +101,10 @@ public abstract ScopeRootResolution CreateScopeRootResolution( DisposableCollectionResolution disposableCollectionResolution, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters); - protected RangedInstanceReferenceResolution CreateRangedInstanceReferenceResolution( + protected FunctionCallResolution CreateRangedInstanceReferenceResolution( ForConstructorParameter parameter, string label, + string? reference, string owningObjectReference) { var (implementationType, currentParameters) = parameter; @@ -116,54 +115,26 @@ protected RangedInstanceReferenceResolution CreateRangedInstanceReferenceResolut _ => null }; var key = $"{implementationType.FullName()}{interfaceExtension?.KeySuffix() ?? ""}"; - if (!RangedInstanceReferenceResolutions.TryGetValue( - key, - out RangedInstanceFunction function)) + if (!RangedInstanceReferenceResolutions.TryGetValue(key, out var functionGroup)) { var decorationSuffix = interfaceExtension?.RangedNameSuffix() ?? ""; - function = new RangedInstanceFunction( - RootReferenceGenerator.Generate($"Get{label}Instance", implementationType, decorationSuffix), - implementationType.FullName(), - RootReferenceGenerator.Generate($"_{label.ToLower()}InstanceField", implementationType, decorationSuffix), - RootReferenceGenerator.Generate($"_{label.ToLower()}InstanceLock{decorationSuffix}")); - RangedInstanceReferenceResolutions[key] = function; - } - - var listedParameterTypes = string.Join(",", currentParameters.Select(p => p.Item2.TypeFullName)); - if (!RangedInstanceQueuedOverloads.Contains((function, listedParameterTypes))) - { - var tempParameter = currentParameters - .Select(t => (t.Type, new ParameterResolution(RootReferenceGenerator.Generate(t.Type), t.Type.FullName()))) - .ToList(); - RangedInstanceResolutionsQueue.Enqueue(new RangedInstanceResolutionsQueueItem(function, tempParameter, implementationType, interfaceExtension)); - RangedInstanceQueuedOverloads.Add((function, listedParameterTypes)); + functionGroup = _rangedFunctionGroupResolutionBuilderFactory(label, reference, implementationType, decorationSuffix, this); + RangedInstanceReferenceResolutions[key] = functionGroup; } - return new RangedInstanceReferenceResolution( - RootReferenceGenerator.Generate(implementationType), - function, - currentParameters.Select(t => t.Resolution).ToList(), - owningObjectReference); + return functionGroup + .GetInstanceFunction(parameter) + .BuildFunctionCall(currentParameters, owningObjectReference); } protected void DoRangedInstancesWork() { - while (RangedInstanceResolutionsQueue.Any()) + while (RangedInstanceReferenceResolutions.Values.Any(r => r.HasWorkToDo)) { - var (scopeInstanceFunction, parameter, type, interfaceExtension) = RangedInstanceResolutionsQueue.Dequeue(); - var resolvable = interfaceExtension switch + foreach (var builder in RangedInstanceReferenceResolutions.Values.ToList()) { - DecorationInterfaceExtension decoration => _functionResolutionBuilderFactory(this).RangedFunction(new ForConstructorParameterWithDecoration( - decoration.DecoratorType, parameter, decoration)), - CompositionInterfaceExtension composition => _functionResolutionBuilderFactory(this).RangedFunction(new ForConstructorParameterWithComposition( - composition.CompositeType, parameter, composition)), - _ => _functionResolutionBuilderFactory(this).RangedFunction(new ForConstructorParameter(type, parameter)) - }; - RangedInstances.Add(( - scopeInstanceFunction, - new RangedInstanceFunctionOverload( - resolvable, - parameter.Select(t => t.Item2).ToList()))); + builder.DoWork(); + } } } } \ No newline at end of file diff --git a/Main/ResolutionBuilding/RangedFunctionResolutionBuilderManager.cs b/Main/ResolutionBuilding/RangedFunctionResolutionBuilderManager.cs new file mode 100644 index 00000000..bb0dbcd5 --- /dev/null +++ b/Main/ResolutionBuilding/RangedFunctionResolutionBuilderManager.cs @@ -0,0 +1,87 @@ +namespace MrMeeseeks.DIE.ResolutionBuilding; + +internal interface IRangedFunctionGroupResolutionBuilder +{ + IRangedFunctionResolutionBuilder GetInstanceFunction(ForConstructorParameter parameter); + + bool HasWorkToDo { get; } + + void DoWork(); + + RangedInstanceFunctionGroupResolution Build(); +} + +internal class RangedFunctionGroupResolutionBuilder : IRangedFunctionGroupResolutionBuilder +{ + private readonly IRangeResolutionBaseBuilder _rangeResolutionBaseBuilder; + private readonly Func _rangedFunctionResolutionBuilderFactory; + private readonly string _reference; + private readonly string _typeFullName; + private readonly string _fieldReference; + private readonly string _lockReference; + + private readonly Dictionary _overloads = new(); + private readonly Queue _functionQueue = new(); + private readonly List _overloadResolutions = new(); + + internal RangedFunctionGroupResolutionBuilder( + // parameter + string label, + string? reference, + INamedTypeSymbol implementationType, + string decorationSuffix, + IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, + + // dependencies + IReferenceGeneratorFactory referenceGeneratorFactory, + Func rangedFunctionResolutionBuilderFactory) + { + _rangeResolutionBaseBuilder = rangeResolutionBaseBuilder; + _rangedFunctionResolutionBuilderFactory = rangedFunctionResolutionBuilderFactory; + var rootReferenceGenerator = referenceGeneratorFactory.Create(); + _reference = reference ?? rootReferenceGenerator.Generate($"Get{label}Instance", implementationType, decorationSuffix); + _typeFullName = implementationType.FullName(); + _fieldReference = + rootReferenceGenerator.Generate($"_{label.ToLower()}InstanceField", implementationType, decorationSuffix); + _lockReference = rootReferenceGenerator.Generate($"_{label.ToLower()}InstanceLock{decorationSuffix}"); + } + + public IRangedFunctionResolutionBuilder GetInstanceFunction(ForConstructorParameter parameter) + { + var listedParameterTypes = string.Join(",", parameter.CurrentFuncParameters.Select(p => p.Item2.TypeFullName)); + if (!_overloads.TryGetValue(listedParameterTypes, out var function)) + { + function = _rangedFunctionResolutionBuilderFactory(_rangeResolutionBaseBuilder, _reference, parameter); + _overloads[listedParameterTypes] = function; + _functionQueue.Enqueue(function); + } + return function; + } + + public bool HasWorkToDo => _functionQueue.Any(); + + public void DoWork() + { + while (_functionQueue.Any()) + { + var function = _functionQueue.Dequeue(); + var functionResolution = function.Build(); + _overloadResolutions.Add(new RangedInstanceFunctionResolution( + functionResolution.Reference, + functionResolution.TypeFullName, + functionResolution.Resolvable, + functionResolution.Parameter, + functionResolution.DisposalHandling, + functionResolution.LocalFunctions)); + } + } + + public RangedInstanceFunctionGroupResolution Build() + { + return new RangedInstanceFunctionGroupResolution( + _typeFullName, + _overloadResolutions, + _fieldReference, + _lockReference); + } +} \ No newline at end of file diff --git a/Main/ResolutionBuilding/ResolutionDtos.cs b/Main/ResolutionBuilding/ResolutionDtos.cs index dd5a3eaa..a37acf4e 100644 --- a/Main/ResolutionBuilding/ResolutionDtos.cs +++ b/Main/ResolutionBuilding/ResolutionDtos.cs @@ -47,6 +47,9 @@ internal record SwitchInterfaceParameter( internal interface IScopeRootParameter { + INamedTypeSymbol ReturnType { get; } + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters { get; } + string KeySuffix(); string RootFunctionSuffix(); } @@ -57,6 +60,8 @@ internal record SwitchInterfaceAfterScopeRootParameter( IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters) : IScopeRootParameter { + public INamedTypeSymbol ReturnType => InterfaceType; + public string KeySuffix() => ":::InterfaceAfterRoot"; public string RootFunctionSuffix() => "_InterfaceAfterRoot"; @@ -74,6 +79,8 @@ internal record CreateInterfaceParameter( IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters) : IScopeRootParameter { + public INamedTypeSymbol ReturnType => InterfaceType; + public virtual string KeySuffix() => ":::NormalInterface"; public virtual string RootFunctionSuffix() => "_NormalInterface"; @@ -100,6 +107,8 @@ internal record SwitchImplementationParameter( IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters) : IScopeRootParameter { + public INamedTypeSymbol ReturnType => ImplementationType; + public virtual string KeySuffix() => ":::Implementation"; public virtual string RootFunctionSuffix() => ""; @@ -141,10 +150,9 @@ internal record ForConstructorParameterWithComposition( //(RangedInstanceFunction, IReadOnlyList<(ITypeSymbol, ParameterResolution)>, INamedTypeSymbol, InterfaceExtension?) internal record RangedInstanceResolutionsQueueItem( - RangedInstanceFunction Function, - IReadOnlyList<(ITypeSymbol, ParameterResolution)> Parameters, - INamedTypeSymbol ImplementationType, - InterfaceExtension? InterfaceExtension); + ForConstructorParameter Parameter, + string Label, + string Reference); internal record SwitchTaskParameter((Resolvable, ConstructorResolution?) InnerResolution) : Parameter; diff --git a/Main/ResolutionBuilding/ScopeManager.cs b/Main/ResolutionBuilding/ScopeManager.cs index 0a55e81a..27f88ca0 100644 --- a/Main/ResolutionBuilding/ScopeManager.cs +++ b/Main/ResolutionBuilding/ScopeManager.cs @@ -219,9 +219,9 @@ public void DoWork() { if (_defaultScopeBuilder.IsValueCreated) _defaultScopeBuilder.Value.DoWork(); if (_defaultTransientScopeBuilder.IsValueCreated) _defaultTransientScopeBuilder.Value.DoWork(); - foreach (var customScopeBuilder in _customScopeBuilders.Values) + foreach (var customScopeBuilder in _customScopeBuilders.Values.ToList()) customScopeBuilder.DoWork(); - foreach (var customTransientScopeBuilder in _customTransientScopeBuilders.Values) + foreach (var customTransientScopeBuilder in _customTransientScopeBuilders.Values.ToList()) customTransientScopeBuilder.DoWork(); } diff --git a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs index e0e36115..5ed74f65 100644 --- a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs @@ -24,16 +24,16 @@ internal class ScopeResolutionBuilder : RangeResolutionBaseBuilder, IScopeResolu private readonly IContainerResolutionBuilder _containerResolutionBuilder; private readonly ITransientScopeInterfaceResolutionBuilder _transientScopeInterfaceResolutionBuilder; private readonly IScopeManager _scopeManager; - private readonly Func _functionResolutionBuilderFactory; + private readonly Func _scopeRootCreateFunctionResolutionBuilderFactory; private readonly List _rootResolutions = new (); private readonly string _containerReference; private readonly string _containerParameterReference; private readonly string _transientScopeReference; private readonly string _transientScopeParameterReference; - private readonly Dictionary _scopeRootFunctionResolutions = new (); - private readonly HashSet<(ScopeRootFunction, string)> _scopeRootFunctionQueuedOverloads = new (); - private readonly Queue<(ScopeRootFunction, IReadOnlyList, INamedTypeSymbol, IScopeRootParameter)> _scopeRootFunctionResolutionsQueue = new(); + private readonly Dictionary _scopeRootFunctionResolutions = new (); + private readonly HashSet<(IScopeRootCreateFunctionResolutionBuilder, string)> _scopeRootFunctionQueuedOverloads = new (); + private readonly Queue _scopeRootFunctionResolutionsQueue = new(); internal ScopeResolutionBuilder( // parameter @@ -47,29 +47,30 @@ internal ScopeResolutionBuilder( // dependencies WellKnownTypes wellKnownTypes, IReferenceGeneratorFactory referenceGeneratorFactory, - Func functionResolutionBuilderFactory) + Func scopeRootCreateFunctionResolutionBuilderFactory, + Func rangedFunctionGroupResolutionBuilderFactory) : base( name, checkTypeProperties, userProvidedScopeElements, wellKnownTypes, referenceGeneratorFactory, - functionResolutionBuilderFactory) + rangedFunctionGroupResolutionBuilderFactory) { _containerResolutionBuilder = containerResolutionBuilder; _transientScopeInterfaceResolutionBuilder = transientScopeInterfaceResolutionBuilder; _scopeManager = scopeManager; - _functionResolutionBuilderFactory = functionResolutionBuilderFactory; + _scopeRootCreateFunctionResolutionBuilderFactory = scopeRootCreateFunctionResolutionBuilderFactory; _containerReference = RootReferenceGenerator.Generate("_container"); _containerParameterReference = RootReferenceGenerator.Generate("container"); _transientScopeReference = RootReferenceGenerator.Generate("_transientScope"); _transientScopeParameterReference = RootReferenceGenerator.Generate("transientScope"); } - public override RangedInstanceReferenceResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter) => + public override FunctionCallResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter) => _containerResolutionBuilder.CreateContainerInstanceReferenceResolution(parameter, _containerReference); - public override RangedInstanceReferenceResolution CreateTransientScopeInstanceReferenceResolution(ForConstructorParameter parameter) => + public override FunctionCallResolution CreateTransientScopeInstanceReferenceResolution(ForConstructorParameter parameter) => _transientScopeInterfaceResolutionBuilder.CreateTransientScopeInstanceReferenceResolution(parameter, _transientScopeReference); public override TransientScopeRootResolution CreateTransientScopeRootResolution( @@ -101,7 +102,7 @@ public override ScopeRootResolution CreateScopeRootResolution( disposableCollectionResolution, currentParameters); - public bool HasWorkToDo => _scopeRootFunctionResolutionsQueue.Any() || RangedInstanceResolutionsQueue.Any(); + public bool HasWorkToDo => _scopeRootFunctionResolutionsQueue.Any() || RangedInstanceReferenceResolutions.Values.Any(r => r.HasWorkToDo); public ScopeRootResolution AddCreateResolveFunction( IScopeRootParameter parameter, @@ -114,34 +115,28 @@ public ScopeRootResolution AddCreateResolveFunction( var key = $"{rootType.FullName()}{parameter.KeySuffix()}"; if (!_scopeRootFunctionResolutions.TryGetValue( key, - out ScopeRootFunction function)) + out var function)) { - function = new ScopeRootFunction( - RootReferenceGenerator.Generate("Create", rootType, parameter.RootFunctionSuffix()), - rootType.FullName()); + function = _scopeRootCreateFunctionResolutionBuilderFactory(this, parameter); _scopeRootFunctionResolutions[key] = function; } var listedParameterTypes = string.Join(",", currentParameters.Select(p => p.Item2.TypeFullName)); if (!_scopeRootFunctionQueuedOverloads.Contains((function, listedParameterTypes))) { - var currParameter = currentParameters - .Select(t => new ParameterResolution(RootReferenceGenerator.Generate(t.Type), t.Type.FullName())) - .ToList(); - _scopeRootFunctionResolutionsQueue.Enqueue((function, currParameter, rootType, parameter)); + _scopeRootFunctionResolutionsQueue.Enqueue(function); _scopeRootFunctionQueuedOverloads.Add((function, listedParameterTypes)); } + var scopeRootReference = RootReferenceGenerator.Generate("scopeRoot"); + return new ScopeRootResolution( - RootReferenceGenerator.Generate(rootType), - rootType.FullName(), - RootReferenceGenerator.Generate("scopeRoot"), + scopeRootReference, Name, containerInstanceScopeReference, transientInstanceScopeReference, - currentParameters.Select(t => t.Resolution).ToList(), disposableCollectionResolution, - function); + function.BuildFunctionCall(currentParameters, scopeRootReference)); } public void DoWork() @@ -150,24 +145,18 @@ public void DoWork() { while (_scopeRootFunctionResolutionsQueue.Any()) { - var (scopeRootFunction, parameter, type, functionParameter) = _scopeRootFunctionResolutionsQueue.Dequeue(); - - var resolvable = functionParameter switch - { - CreateInterfaceParameter createInterfaceParameter => _functionResolutionBuilderFactory(this).ScopeRootFunction(createInterfaceParameter), - SwitchImplementationParameter switchImplementationParameter => _functionResolutionBuilderFactory(this).ScopeRootFunction(switchImplementationParameter), - SwitchInterfaceAfterScopeRootParameter switchInterfaceAfterScopeRootParameter => _functionResolutionBuilderFactory(this).ScopeRootFunction(switchInterfaceAfterScopeRootParameter), - _ => throw new ArgumentOutOfRangeException(nameof(functionParameter)) - }; + var functionResolution = _scopeRootFunctionResolutionsQueue + .Dequeue() + .Build(); _rootResolutions.Add(new RootResolutionFunction( - scopeRootFunction.Reference, - type.FullName(), + functionResolution.Reference, + functionResolution.TypeFullName, "internal", - resolvable, - parameter, - Name, - DisposalHandling)); + functionResolution.Resolvable, + functionResolution.Parameter, + functionResolution.DisposalHandling, + functionResolution.LocalFunctions)); } DoRangedInstancesWork(); @@ -177,13 +166,7 @@ public void DoWork() public ScopeResolution Build() => new(_rootResolutions, DisposalHandling, - RangedInstances - .GroupBy(t => t.Item1) - .Select(g => new RangedInstance( - g.Key, - g.Select(t => t.Item2).ToList(), - DisposalHandling)) - .ToList(), + RangedInstanceReferenceResolutions.Values.Select(b => b.Build()).ToList(), _containerReference, _containerParameterReference, _transientScopeReference, diff --git a/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs b/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs index 898f9123..73db3921 100644 --- a/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs +++ b/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs @@ -3,7 +3,7 @@ namespace MrMeeseeks.DIE.ResolutionBuilding; internal interface ITransientScopeInterfaceResolutionBuilder { void AddImplementation(ITransientScopeImplementationResolutionBuilder implementation); - RangedInstanceReferenceResolution CreateTransientScopeInstanceReferenceResolution( + FunctionCallResolution CreateTransientScopeInstanceReferenceResolution( ForConstructorParameter parameter, string containerReference); @@ -13,21 +13,23 @@ RangedInstanceReferenceResolution CreateTransientScopeInstanceReferenceResolutio internal class TransientScopeInterfaceResolutionBuilder : ITransientScopeInterfaceResolutionBuilder { private readonly IReferenceGenerator _rootReferenceGenerator; - private readonly IDictionary _rangedInstanceReferenceResolutions = - new Dictionary(); - private readonly HashSet<(RangedInstanceFunction, string)> _rangedInstanceQueuedOverloads = new (); private readonly HashSet _pastQueuedItems = new(); private readonly IList _implementations = new List(); + protected readonly IDictionary RangedInstanceReferenceResolutions = + new Dictionary(); + private readonly Func _rangedFunctionGroupResolutionBuilderFactory; private readonly string _name; private readonly string _containerAdapterName; public TransientScopeInterfaceResolutionBuilder( - IReferenceGeneratorFactory referenceGeneratorFactory) + IReferenceGeneratorFactory referenceGeneratorFactory, + Func rangedFunctionGroupResolutionBuilderFactory) { + _rangedFunctionGroupResolutionBuilderFactory = rangedFunctionGroupResolutionBuilderFactory; _rootReferenceGenerator = referenceGeneratorFactory.Create(); _name = _rootReferenceGenerator.Generate("ITransientScope"); @@ -38,29 +40,27 @@ public TransientScopeInterfaceResolutionBuilder( public void AddImplementation(ITransientScopeImplementationResolutionBuilder implementation) { - foreach (var item in _pastQueuedItems) - implementation.EnqueueRangedInstanceResolution(item); + foreach (var (parameter, label, reference) in _pastQueuedItems) + implementation.EnqueueRangedInstanceResolution( + parameter, + label, + reference); _implementations.Add(implementation); } - public RangedInstanceReferenceResolution CreateTransientScopeInstanceReferenceResolution(ForConstructorParameter parameter, string containerReference) => + public FunctionCallResolution CreateTransientScopeInstanceReferenceResolution(ForConstructorParameter parameter, string containerReference) => CreateRangedInstanceReferenceResolution( parameter, "TransientScope", containerReference); public TransientScopeInterfaceResolution Build() => new( - _pastQueuedItems - .Select(i => new TransientScopeInstanceInterfaceFunction( - i.Parameters.Select(p => new ParameterResolution(p.Item2.Reference, p.Item2.TypeFullName)).ToList(), - i.Function.Reference, - i.Function.TypeFullName)) - .ToList(), + RangedInstanceReferenceResolutions.Values.ToList(), _name, _containerAdapterName); - private RangedInstanceReferenceResolution CreateRangedInstanceReferenceResolution( + private FunctionCallResolution CreateRangedInstanceReferenceResolution( ForConstructorParameter parameter, string label, string owningObjectReference) @@ -73,36 +73,35 @@ private RangedInstanceReferenceResolution CreateRangedInstanceReferenceResolutio _ => null }; var key = $"{implementationType.FullName()}{interfaceExtension?.KeySuffix() ?? ""}"; - if (!_rangedInstanceReferenceResolutions.TryGetValue( - key, - out RangedInstanceFunction function)) + if (!RangedInstanceReferenceResolutions.TryGetValue(key, out var interfaceDeclaration)) { var decorationSuffix = interfaceExtension?.RangedNameSuffix() ?? ""; - function = new RangedInstanceFunction( - _rootReferenceGenerator.Generate($"Get{label}Instance", implementationType, decorationSuffix), - implementationType.FullName(), - _rootReferenceGenerator.Generate($"_{label.ToLower()}InstanceField", implementationType, decorationSuffix), - _rootReferenceGenerator.Generate($"_{label.ToLower()}InstanceLock{decorationSuffix}")); - _rangedInstanceReferenceResolutions[key] = function; - } + var reference = _rootReferenceGenerator.Generate($"Get{label}Instance", implementationType, decorationSuffix); + var queueItem = new RangedInstanceResolutionsQueueItem( + parameter, + label, + reference); - var listedParameterTypes = string.Join(",", currentParameters.Select(p => p.Item2.TypeFullName)); - if (!_rangedInstanceQueuedOverloads.Contains((function, listedParameterTypes))) - { - var tempParameter = currentParameters - .Select(t => (t.Type, new ParameterResolution(_rootReferenceGenerator.Generate(t.Type), t.Type.FullName()))) - .ToList(); - var queueItem = new RangedInstanceResolutionsQueueItem(function, tempParameter, implementationType, interfaceExtension); - foreach (var implementation in _implementations) - implementation.EnqueueRangedInstanceResolution(queueItem); _pastQueuedItems.Add(queueItem); - _rangedInstanceQueuedOverloads.Add((function, listedParameterTypes)); - } + + foreach (var implementation in _implementations) + implementation.EnqueueRangedInstanceResolution( + queueItem.Parameter, + queueItem.Label, + queueItem.Reference); - return new RangedInstanceReferenceResolution( - _rootReferenceGenerator.Generate(implementationType), - function, - currentParameters.Select(t => t.Resolution).ToList(), - owningObjectReference); + interfaceDeclaration = new InterfaceFunctionDeclarationResolution( + reference, + implementationType.FullName(), + currentParameters.Select(t => + new ParameterResolution(_rootReferenceGenerator.Generate(t.Type), t.Type.FullName())).ToList()); + RangedInstanceReferenceResolutions[key] = interfaceDeclaration; + } + + return new(_rootReferenceGenerator.Generate("ret"), + interfaceDeclaration.TypeFullName, + interfaceDeclaration.Reference, + owningObjectReference, + interfaceDeclaration.Parameter.Zip(currentParameters, (p, cp) => (p.Reference, cp.Resolution.Reference)).ToList()); } } \ No newline at end of file diff --git a/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs b/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs index f264f426..6082dbbf 100644 --- a/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs @@ -23,14 +23,14 @@ internal class TransientScopeResolutionBuilder : RangeResolutionBaseBuilder, ITr private readonly IContainerResolutionBuilder _containerResolutionBuilder; private readonly ITransientScopeInterfaceResolutionBuilder _transientScopeInterfaceResolutionBuilder; private readonly IScopeManager _scopeManager; - private readonly Func _functionResolutionBuilderFactory; + private readonly Func _scopeRootCreateFunctionResolutionBuilderFactory; private readonly List _rootResolutions = new (); private readonly string _containerReference; private readonly string _containerParameterReference; - private readonly Dictionary _transientScopeRootFunctionResolutions = new (); - private readonly HashSet<(ScopeRootFunction, string)> _transientScopeRootFunctionQueuedOverloads = new (); - private readonly Queue<(ScopeRootFunction, IReadOnlyList, INamedTypeSymbol, IScopeRootParameter)> _transientScopeRootFunctionResolutionsQueue = new(); + private readonly Dictionary _transientScopeRootFunctionResolutions = new (); + private readonly HashSet<(IScopeRootCreateFunctionResolutionBuilder, string)> _transientScopeRootFunctionQueuedOverloads = new (); + private readonly Queue _transientScopeRootFunctionResolutionsQueue = new(); internal TransientScopeResolutionBuilder( // parameter @@ -44,27 +44,28 @@ internal TransientScopeResolutionBuilder( // dependencies WellKnownTypes wellKnownTypes, IReferenceGeneratorFactory referenceGeneratorFactory, - Func functionResolutionBuilderFactory) + Func scopeRootCreateFunctionResolutionBuilderFactory, + Func rangedFunctionGroupResolutionBuilderFactory) : base( name, checkTypeProperties, userProvidedScopeElements, wellKnownTypes, referenceGeneratorFactory, - functionResolutionBuilderFactory) + rangedFunctionGroupResolutionBuilderFactory) { _containerResolutionBuilder = containerResolutionBuilder; _transientScopeInterfaceResolutionBuilder = transientScopeInterfaceResolutionBuilder; _scopeManager = scopeManager; - _functionResolutionBuilderFactory = functionResolutionBuilderFactory; + _scopeRootCreateFunctionResolutionBuilderFactory = scopeRootCreateFunctionResolutionBuilderFactory; _containerReference = RootReferenceGenerator.Generate("_container"); _containerParameterReference = RootReferenceGenerator.Generate("container"); } - public override RangedInstanceReferenceResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter) => + public override FunctionCallResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter) => _containerResolutionBuilder.CreateContainerInstanceReferenceResolution(parameter, _containerReference); - public override RangedInstanceReferenceResolution CreateTransientScopeInstanceReferenceResolution(ForConstructorParameter parameter) => + public override FunctionCallResolution CreateTransientScopeInstanceReferenceResolution(ForConstructorParameter parameter) => _transientScopeInterfaceResolutionBuilder.CreateTransientScopeInstanceReferenceResolution(parameter, "this"); public override TransientScopeRootResolution CreateTransientScopeRootResolution(IScopeRootParameter parameter, INamedTypeSymbol rootType, @@ -93,7 +94,7 @@ public override ScopeRootResolution CreateScopeRootResolution( disposableCollectionResolution, currentParameters); - public bool HasWorkToDo => _transientScopeRootFunctionResolutionsQueue.Any() || RangedInstanceResolutionsQueue.Any(); + public bool HasWorkToDo => _transientScopeRootFunctionResolutionsQueue.Any() || RangedInstanceReferenceResolutions.Values.Any(r => r.HasWorkToDo); public TransientScopeRootResolution AddCreateResolveFunction( IScopeRootParameter parameter, @@ -105,33 +106,27 @@ public TransientScopeRootResolution AddCreateResolveFunction( var key = $"{rootType.FullName()}{parameter.KeySuffix()}"; if (!_transientScopeRootFunctionResolutions.TryGetValue( key, - out ScopeRootFunction function)) + out var function)) { - function = new ScopeRootFunction( - RootReferenceGenerator.Generate("Create", rootType, parameter.RootFunctionSuffix()), - rootType.FullName()); + function = _scopeRootCreateFunctionResolutionBuilderFactory(this, parameter); _transientScopeRootFunctionResolutions[key] = function; } var listedParameterTypes = string.Join(",", currentParameters.Select(p => p.Item2.TypeFullName)); if (!_transientScopeRootFunctionQueuedOverloads.Contains((function, listedParameterTypes))) { - var currParameter = currentParameters - .Select(t => new ParameterResolution(RootReferenceGenerator.Generate(t.Type), t.Type.FullName())) - .ToList(); - _transientScopeRootFunctionResolutionsQueue.Enqueue((function, currParameter, rootType, parameter)); + _transientScopeRootFunctionResolutionsQueue.Enqueue(function); _transientScopeRootFunctionQueuedOverloads.Add((function, listedParameterTypes)); } + var transientScopeRootReference = RootReferenceGenerator.Generate("transientScopeRoot"); + return new TransientScopeRootResolution( - RootReferenceGenerator.Generate(rootType), - rootType.FullName(), - RootReferenceGenerator.Generate("transientScopeRoot"), + transientScopeRootReference, Name, containerInstanceScopeReference, - currentParameters.Select(t => t.Resolution).ToList(), disposableCollectionResolution, - function); + function.BuildFunctionCall(currentParameters, transientScopeRootReference)); } public void DoWork() @@ -140,24 +135,18 @@ public void DoWork() { while (_transientScopeRootFunctionResolutionsQueue.Any()) { - var (scopeRootFunction, parameter, type, functionParameter) = _transientScopeRootFunctionResolutionsQueue.Dequeue(); - - var resolvable = functionParameter switch - { - CreateInterfaceParameter createInterfaceParameter => _functionResolutionBuilderFactory(this).ScopeRootFunction(createInterfaceParameter), - SwitchImplementationParameter switchImplementationParameter => _functionResolutionBuilderFactory(this).ScopeRootFunction(switchImplementationParameter), - SwitchInterfaceAfterScopeRootParameter switchInterfaceAfterScopeRootParameter => _functionResolutionBuilderFactory(this).ScopeRootFunction(switchInterfaceAfterScopeRootParameter), - _ => throw new ArgumentOutOfRangeException(nameof(functionParameter)) - }; + var functionResolution = _transientScopeRootFunctionResolutionsQueue + .Dequeue() + .Build(); _rootResolutions.Add(new RootResolutionFunction( - scopeRootFunction.Reference, - type.FullName(), + functionResolution.Reference, + functionResolution.TypeFullName, "internal", - resolvable, - parameter, - Name, - DisposalHandling)); + functionResolution.Resolvable, + functionResolution.Parameter, + functionResolution.DisposalHandling, + functionResolution.LocalFunctions)); } DoRangedInstancesWork(); @@ -167,16 +156,17 @@ public void DoWork() public TransientScopeResolution Build() => new(_rootResolutions, DisposalHandling, - RangedInstances - .GroupBy(t => t.Item1) - .Select(g => new RangedInstance( - g.Key, - g.Select(t => t.Item2).ToList(), - DisposalHandling)) - .ToList(), + RangedInstanceReferenceResolutions.Values.Select(b => b.Build()).ToList(), _containerReference, _containerParameterReference, Name); - public void EnqueueRangedInstanceResolution(RangedInstanceResolutionsQueueItem item) => RangedInstanceResolutionsQueue.Enqueue(item); + public void EnqueueRangedInstanceResolution( + ForConstructorParameter parameter, + string label, + string reference) => CreateRangedInstanceReferenceResolution( + parameter, + label, + reference, + "Doesn'tMatter"); } \ No newline at end of file diff --git a/Main/ResolutionTreeCreationErrorHarvester.cs b/Main/ResolutionTreeCreationErrorHarvester.cs index 83af3b46..e7e4d437 100644 --- a/Main/ResolutionTreeCreationErrorHarvester.cs +++ b/Main/ResolutionTreeCreationErrorHarvester.cs @@ -17,12 +17,12 @@ static void Inner(ResolutionTreeItem item, ICollection errorTreeI { switch (item) { + case FunctionCallResolution: + break; case RootResolutionFunction: break; case TransientScopeAsDisposableResolution: break; - case RangedInstanceReferenceResolution: - break; case ScopeRootFunction: break; case ScopeRootResolution: @@ -30,8 +30,8 @@ static void Inner(ResolutionTreeItem item, ICollection errorTreeI case FieldResolution: break; case RangeResolution containerResolution: - foreach (var overload in containerResolution.RangedInstances.SelectMany(ri => ri.Overloads)) - Inner(overload.Dependency, errorTreeItems); + foreach (var overload in containerResolution.RangedInstanceFunctionGroups.SelectMany(ri => ri.Overloads)) + Inner(overload.Resolvable, errorTreeItems); foreach (var rootResolution in containerResolution.RootResolutions) Inner(rootResolution, errorTreeItems); break; @@ -52,10 +52,7 @@ static void Inner(ResolutionTreeItem item, ICollection errorTreeI break; case ParameterResolution: break; - case FuncResolution funcResolution: - foreach (var funcParameterResolution in funcResolution.Parameter) - Inner(funcParameterResolution, errorTreeItems); - Inner(funcResolution.Dependency, errorTreeItems); + case FuncResolution: break; case InterfaceResolution interfaceResolution: Inner(interfaceResolution.Dependency, errorTreeItems); diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index e76b321b..e4835531 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -6,14 +6,53 @@ internal abstract record Resolvable( string Reference, string TypeFullName) : ResolutionTreeItem; +internal record FunctionResolution( + string Reference, + string TypeFullName, + Resolvable Resolvable, + IReadOnlyList Parameter, + DisposalHandling DisposalHandling, + IReadOnlyList LocalFunctions) : Resolvable(Reference, TypeFullName); + internal record RootResolutionFunction( string Reference, string TypeFullName, string AccessModifier, Resolvable Resolvable, IReadOnlyList Parameter, - string RangeName, - DisposalHandling DisposalHandling) : Resolvable(Reference, TypeFullName); + DisposalHandling DisposalHandling, + IReadOnlyList LocalFunctions) + : FunctionResolution(Reference, TypeFullName, Resolvable, Parameter, DisposalHandling, LocalFunctions); + +internal record LocalFunctionResolution( + string Reference, + string TypeFullName, + Resolvable Resolvable, + IReadOnlyList Parameter, + DisposalHandling DisposalHandling, + IReadOnlyList LocalFunctions) + : FunctionResolution(Reference, TypeFullName, Resolvable, Parameter, DisposalHandling, LocalFunctions); + +internal record RangedInstanceFunctionResolution( + string Reference, + string TypeFullName, + Resolvable Resolvable, + IReadOnlyList Parameter, + DisposalHandling DisposalHandling, + IReadOnlyList LocalFunctions) + : FunctionResolution(Reference, TypeFullName, Resolvable, Parameter, DisposalHandling, LocalFunctions); + +internal record RangedInstanceFunctionGroupResolution( + string TypeFullName, + IReadOnlyList Overloads, + string FieldReference, + string LockReference); + +internal record MethodGroupResolution( + string Reference, + string TypeFullName, + string? OwnerReference) + : Resolvable(Reference, TypeFullName); internal record TransientScopeAsDisposableResolution( string Reference, @@ -62,71 +101,48 @@ internal record ConstructorResolution( IReadOnlyList<(string Name, Resolvable Dependency)> InitializedProperties, ITypeInitializationResolution? Initialization) : Resolvable(Reference, TypeFullName); +internal record LazyResolution( + string Reference, + string TypeFullName, + MethodGroupResolution MethodGroup) : Resolvable(Reference, TypeFullName); + internal record SyntaxValueTupleResolution( string Reference, string TypeFullName, IReadOnlyList Items) : Resolvable(Reference, TypeFullName); internal record TransientScopeRootResolution( - string Reference, - string TypeFullName, string TransientScopeReference, string TransientScopeTypeFullName, string ContainerInstanceScopeReference, - IReadOnlyList Parameter, DisposableCollectionResolution DisposableCollectionResolution, - ScopeRootFunction ScopeRootFunction) : Resolvable(Reference, TypeFullName); + FunctionCallResolution ScopeRootFunction) : Resolvable(ScopeRootFunction.Reference, ScopeRootFunction.TypeFullName); internal record ScopeRootResolution( - string Reference, - string TypeFullName, string ScopeReference, string ScopeTypeFullName, string ContainerInstanceScopeReference, string TransientInstanceScopeReference, - IReadOnlyList Parameter, DisposableCollectionResolution DisposableCollectionResolution, - ScopeRootFunction ScopeRootFunction) : Resolvable(Reference, TypeFullName); + FunctionCallResolution ScopeRootFunction) : Resolvable(ScopeRootFunction.Reference, ScopeRootFunction.TypeFullName); internal record ScopeRootFunction( string Reference, string TypeFullName) : Resolvable(Reference, TypeFullName); -internal record RangedInstance( - RangedInstanceFunction Function, - IReadOnlyList Overloads, - DisposalHandling DisposalHandling); - internal record ParameterResolution( string Reference, string TypeFullName) : Resolvable(Reference, TypeFullName); -internal record RangedInstanceFunction( +internal record InterfaceFunctionDeclarationResolution( string Reference, string TypeFullName, - string FieldReference, - string LockReference); - -internal record TransientScopeInstanceInterfaceFunction( - IReadOnlyList Parameter, - string Reference, - string TypeFullName); - -internal record RangedInstanceFunctionOverload( - Resolvable Dependency, IReadOnlyList Parameter); -internal record RangedInstanceReferenceResolution( - string Reference, - RangedInstanceFunction Function, - IReadOnlyList Parameter, - string OwningObjectReference) : Resolvable(Reference, Function.TypeFullName); - internal record FuncResolution( string Reference, string TypeFullName, - IReadOnlyList Parameter, - ResolutionTreeItem Dependency) : Resolvable(Reference, TypeFullName); + MethodGroupResolution MethodGroupResolution) : Resolvable(Reference, TypeFullName); internal record FactoryResolution( string Reference, @@ -154,43 +170,43 @@ internal record DisposableCollectionResolution( internal abstract record RangeResolution( IReadOnlyList RootResolutions, DisposalHandling DisposalHandling, - IReadOnlyList RangedInstances, + IReadOnlyList RangedInstanceFunctionGroups, string ContainerReference) : ResolutionTreeItem; internal record TransientScopeInterfaceResolution( - IReadOnlyList Functions, + IReadOnlyList Functions, string Name, string ContainerAdapterName); internal record ScopeResolution( IReadOnlyList RootResolutions, DisposalHandling DisposalHandling, - IReadOnlyList RangedInstances, + IReadOnlyList RangedInstanceFunctionGroups, string ContainerReference, string ContainerParameterReference, string TransientScopeReference, string TransientScopeParameterReference, string Name) - : RangeResolution(RootResolutions, DisposalHandling, RangedInstances, ContainerReference); + : RangeResolution(RootResolutions, DisposalHandling, RangedInstanceFunctionGroups, ContainerReference); internal record TransientScopeResolution( IReadOnlyList RootResolutions, DisposalHandling DisposalHandling, - IReadOnlyList RangedInstances, + IReadOnlyList RangedInstanceFunctionGroups, string ContainerReference, string ContainerParameterReference, string Name) - : RangeResolution(RootResolutions, DisposalHandling, RangedInstances, ContainerReference); + : RangeResolution(RootResolutions, DisposalHandling, RangedInstanceFunctionGroups, ContainerReference); internal record ContainerResolution( IReadOnlyList RootResolutions, DisposalHandling DisposalHandling, - IReadOnlyList RangedInstances, + IReadOnlyList RangedInstanceFunctionGroups, TransientScopeInterfaceResolution TransientScopeInterface, string TransientScopeAdapterReference, IReadOnlyList TransientScopes, IReadOnlyList Scopes) - : RangeResolution(RootResolutions, DisposalHandling, RangedInstances, "this"); + : RangeResolution(RootResolutions, DisposalHandling, RangedInstanceFunctionGroups, "this"); internal record DisposalHandling( DisposableCollectionResolution DisposableCollection, @@ -238,4 +254,22 @@ internal record ValueTaskFromValueTaskResolution( internal record ValueTaskFromSyncResolution( Resolvable WrappedResolvable, string ValueTaskReference, - string ValueTaskFullName) : TaskBaseResolution(WrappedResolvable, ValueTaskReference, ValueTaskFullName); \ No newline at end of file + string ValueTaskFullName) : TaskBaseResolution(WrappedResolvable, ValueTaskReference, ValueTaskFullName); + +internal record TaskFromWrappedValueTask( + Resolvable WrappedResolvable, + string TaskReference, + string TaskFullName); + +internal record ValueTaskFromWrappedTask( + Resolvable WrappedResolvable, + string ValueTaskReference, + string ValueTaskFullName); + +internal record FunctionCallResolution( + string Reference, + string TypeFullName, + string FunctionReference, + string? OwnerReference, + IReadOnlyList<(string Name, string Reference)> Parameters) + : Resolvable(Reference, TypeFullName); \ No newline at end of file diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index f94157a2..6624cd48 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -42,12 +42,13 @@ IContainerResolutionBuilder ResolutionTreeFactory(IContainerInfo ci) return new ContainerResolutionBuilder( ci, - new TransientScopeInterfaceResolutionBuilder(referenceGeneratorFactory), + new TransientScopeInterfaceResolutionBuilder(referenceGeneratorFactory, RangedFunctionGroupResolutionBuilderFactory), referenceGeneratorFactory, new CheckTypeProperties(new CurrentlyConsideredTypes(containerTypesFromAttributesList, context)), wellKnownTypes, ScopeManagerFactory, - FunctionResolutionBuilderFactory, + ContainerCreateFunctionResolutionBuilderFactory, + RangedFunctionGroupResolutionBuilderFactory, new UserProvidedScopeElements(ci.ContainerType)); IScopeManager ScopeManagerFactory( @@ -81,7 +82,8 @@ ITransientScopeResolutionBuilder TransientScopeResolutionBuilderFactory( wellKnownTypes, referenceGeneratorFactory, - FunctionResolutionBuilderFactory); + ScopeRootCreateFunctionResolutionBuilderFactory, + RangedFunctionGroupResolutionBuilderFactory); IScopeResolutionBuilder ScopeResolutionBuilderFactory( string name, IContainerResolutionBuilder containerBuilder, @@ -98,14 +100,67 @@ IScopeResolutionBuilder ScopeResolutionBuilderFactory( wellKnownTypes, referenceGeneratorFactory, - FunctionResolutionBuilderFactory); + ScopeRootCreateFunctionResolutionBuilderFactory, + RangedFunctionGroupResolutionBuilderFactory); - IFunctionResolutionBuilder FunctionResolutionBuilderFactory( - IRangeResolutionBaseBuilder rangeResolutionBaseBuilder) => new FunctionResolutionBuilder( + ILocalFunctionResolutionBuilder LocalFunctionResolutionBuilderFactory( + IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, + INamedTypeSymbol returnType, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> parameters) => new LocalFunctionResolutionBuilder( rangeResolutionBaseBuilder, + returnType, + parameters, wellKnownTypes, - referenceGeneratorFactory); + referenceGeneratorFactory, + LocalFunctionResolutionBuilderFactory); + + IContainerCreateFunctionResolutionBuilder ContainerCreateFunctionResolutionBuilderFactory( + IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, + INamedTypeSymbol returnType) => new ContainerCreateFunctionResolutionBuilder( + rangeResolutionBaseBuilder, + returnType, + + wellKnownTypes, + referenceGeneratorFactory, + LocalFunctionResolutionBuilderFactory); + + IScopeRootCreateFunctionResolutionBuilder ScopeRootCreateFunctionResolutionBuilderFactory( + IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, + IScopeRootParameter scopeRootParameter) => new ScopeRootCreateFunctionResolutionBuilder( + rangeResolutionBaseBuilder, + scopeRootParameter, + + wellKnownTypes, + referenceGeneratorFactory, + LocalFunctionResolutionBuilderFactory); + + IRangedFunctionResolutionBuilder RangedFunctionResolutionBuilderFactory( + IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, + string reference, + ForConstructorParameter forConstructorParameter) => new RangedFunctionResolutionBuilder( + rangeResolutionBaseBuilder, + reference, + forConstructorParameter, + + wellKnownTypes, + referenceGeneratorFactory, + LocalFunctionResolutionBuilderFactory); + + IRangedFunctionGroupResolutionBuilder RangedFunctionGroupResolutionBuilderFactory( + string label, + string? reference, + INamedTypeSymbol implementationType, + string decorationSuffix, + IRangeResolutionBaseBuilder rangeResolutionBaseBuilder) => new RangedFunctionGroupResolutionBuilder( + label, + reference, + implementationType, + decorationSuffix, + rangeResolutionBaseBuilder, + + referenceGeneratorFactory, + RangedFunctionResolutionBuilderFactory); } IContainerInfo ContainerInfoFactory(INamedTypeSymbol type) => new ContainerInfo(type, wellKnownTypes); IReferenceGenerator ReferenceGeneratorFactory(int j) => new ReferenceGenerator(j); diff --git a/Sample/Context.cs b/Sample/Context.cs index 8f53825a..9b8f7eaf 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -1,53 +1,43 @@ -using System.Collections.Generic; -using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration; using MrMeeseeks.DIE.Sample; -namespace MrMeeseeks.DIE.Test.Async.TaskCollection; +namespace MrMeeseeks.DIE.Test; -internal interface IInterface +internal interface IDecoratedScopeRoot { - bool IsInitialized { get; } + IDecoratedScopeRootDependency Dependency { get; } + IDecoratedScopeRoot Decorated { get; } } -internal class DependencyA : ITaskTypeInitializer, IInterface -{ - public bool IsInitialized { get; private set; } - - async Task ITaskTypeInitializer.InitializeAsync() - { - await Task.Delay(500).ConfigureAwait(false); - IsInitialized = true; - } -} +internal interface IDecoratedScopeRootDependency {} + +internal class DecoratedScopeRootDependency : IDecoratedScopeRootDependency, IScopeInstance {} -internal class DependencyB : IValueTaskTypeInitializer, IInterface +internal class DecoratorScopeRootBasis : IDecoratedScopeRoot, IScopeRoot, IScopeInstance { - public bool IsInitialized { get; private set; } - - async ValueTask IValueTaskTypeInitializer.InitializeAsync() - { - await Task.Delay(500).ConfigureAwait(false); - IsInitialized = true; - } + public IDecoratedScopeRootDependency Dependency { get; } + + public IDecoratedScopeRoot Decorated => this; + + public DecoratorScopeRootBasis( + IDecoratedScopeRootDependency dependency) => + Dependency = dependency; } -internal class DependencyC : ITypeInitializer, IInterface +internal class DecoratorScopeRoot : IDecoratedScopeRoot, IDecorator { - public bool IsInitialized { get; private set; } - - void ITypeInitializer.Initialize() + public DecoratorScopeRoot(IDecoratedScopeRoot decorated, IDecoratedScopeRootDependency dependency) { - IsInitialized = true; + Decorated = decorated; + Dependency = dependency; } -} -internal class DependencyD : IInterface -{ - public bool IsInitialized => true; + public IDecoratedScopeRootDependency Dependency { get; } + public IDecoratedScopeRoot Decorated { get; } } -[MultiContainer(typeof(IReadOnlyList>))] -internal partial class Container +[MultiContainer(typeof(IDecoratedScopeRoot))] +internal partial class DecoratorScopeRootContainer { + } \ No newline at end of file diff --git a/Sample/Program.cs b/Sample/Program.cs index 629e3545..152ae191 100644 --- a/Sample/Program.cs +++ b/Sample/Program.cs @@ -1,12 +1,12 @@ using System; -using MrMeeseeks.DIE.Test.Async.TaskCollection; +using MrMeeseeks.DIE.Test; internal class Program { private static void Main() { Console.WriteLine("Hello, world!"); - var container = new Container(); + var container = new DecoratorScopeRootContainer(); Console.WriteLine(container.Create0()); } } \ No newline at end of file diff --git a/Test/DecoratorTests.cs b/Test/DecoratorTests.cs index 5ae2b36c..6aa724db 100644 --- a/Test/DecoratorTests.cs +++ b/Test/DecoratorTests.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using MrMeeseeks.DIE; using MrMeeseeks.DIE.Configuration; using MrMeeseeks.DIE.Test; using Xunit; diff --git a/Test/Func/Vanilla.cs b/Test/Func/Vanilla.cs new file mode 100644 index 00000000..4a3024f6 --- /dev/null +++ b/Test/Func/Vanilla.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Func.Vanilla; + +internal class Dependency{} + +[MultiContainer(typeof(Func, Dependency>))] +internal partial class Container +{ +} + +public class Tests +{ + [Fact] + public void Test() + { + using var container = new Container(); + var _ = container.Create0()(DateTime.Now, new List()); + } +} diff --git a/Test/Lazy/Vanilla.cs b/Test/Lazy/Vanilla.cs new file mode 100644 index 00000000..b5bfb8c2 --- /dev/null +++ b/Test/Lazy/Vanilla.cs @@ -0,0 +1,23 @@ +using System; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Lazy.Vanilla; + +internal class Dependency{} + +[MultiContainer(typeof(Lazy))] +internal partial class Container +{ +} + +public class Tests +{ + [Fact] + public void Test() + { + using var container = new Container(); + var lazy = container.Create0(); + var _ = lazy.Value; + } +} diff --git a/Test/ScopeSpecificAttributesTestsWithDecorator.cs b/Test/ScopeSpecificAttributesTestsWithDecorator.cs index 3f2f6fdd..64a402b5 100644 --- a/Test/ScopeSpecificAttributesTestsWithDecorator.cs +++ b/Test/ScopeSpecificAttributesTestsWithDecorator.cs @@ -120,7 +120,7 @@ partial class DIE_Scope_A } } -public partial class ScopeSpecificAttributesTests +public class ScopeSpecificAttributesTests { [Fact] public void Container() From 4628e5c1d8cd1a8f6e152b6ba1a445e70bc49bb7 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sun, 20 Mar 2022 00:11:44 +0100 Subject: [PATCH 050/162] WIP --- Main/CodeBuilding/RangeCodeBaseBuilder.cs | 12 ++++-- Main/Configuration/Attributes.cs | 4 +- Main/ContainerInfo.cs | 26 ++++++------ Main/ExecuteImpl.cs | 4 +- .../ContainerResolutionBuilder.cs | 10 +++-- .../FunctionResolutionBuilder.cs | 40 +++++++++++++++---- .../RangedFunctionResolutionBuilderManager.cs | 3 +- .../ScopeResolutionBuilder.cs | 3 +- .../TransientScopeResolutionBuilder.cs | 3 +- Main/ResolutionTreeCreationErrorHarvester.cs | 2 + Main/ResolutionTreeItem.cs | 32 ++++++++++----- Main/WellKnownTypes.cs | 10 ++--- Test/Async/AwaitedDependency/Dependency.cs | 33 +++++++++++++++ 13 files changed, 133 insertions(+), 49 deletions(-) create mode 100644 Test/Async/AwaitedDependency/Dependency.cs diff --git a/Main/CodeBuilding/RangeCodeBaseBuilder.cs b/Main/CodeBuilding/RangeCodeBaseBuilder.cs index d78669e4..7a8b6a16 100644 --- a/Main/CodeBuilding/RangeCodeBaseBuilder.cs +++ b/Main/CodeBuilding/RangeCodeBaseBuilder.cs @@ -94,7 +94,7 @@ private StringBuilder GenerateResolutionFunction( { var parameter = string.Join(",", resolution.Parameter.Select(r => $"{r.TypeFullName} {r.Reference}")); stringBuilder = stringBuilder - .AppendLine($"{rootResolutionFunction.AccessModifier} {resolution.TypeFullName} {resolution.Reference}({parameter})") + .AppendLine($"{rootResolutionFunction.AccessModifier} {(rootResolutionFunction.IsAsync ? "async " : "")}{resolution.TypeFullName} {resolution.Reference}({parameter})") .AppendLine($"{{") .AppendLine($"if (this.{rootResolutionFunction.DisposalHandling.DisposedPropertyReference}) throw new {WellKnownTypes.ObjectDisposedException}(\"\");"); @@ -110,7 +110,7 @@ private StringBuilder GenerateResolutionFunction( { var parameter = string.Join(",", resolution.Parameter.Select(r => $"{r.TypeFullName} {r.Reference}")); stringBuilder = stringBuilder - .AppendLine($"{resolution.TypeFullName} {resolution.Reference}({parameter})") + .AppendLine($"{(localFunctionResolution.IsAsync ? "async " : "")}{resolution.TypeFullName} {resolution.Reference}({parameter})") .AppendLine($"{{") .AppendLine($"if (this.{localFunctionResolution.DisposalHandling.DisposedPropertyReference}) throw new {WellKnownTypes.ObjectDisposedException}(\"\");"); @@ -146,6 +146,9 @@ private static StringBuilder GenerateFields( stringBuilder = stringBuilder .AppendLine($"{typeFullName} {reference};"); break; + case DeferringResolvable { Resolvable: {} resolvable}: + stringBuilder = GenerateFields(stringBuilder, resolvable); + break; case TaskFromTaskResolution(var wrappedResolvable, _, var taskReference, var taskFullName): stringBuilder = GenerateFields(stringBuilder, wrappedResolvable); stringBuilder = stringBuilder @@ -239,6 +242,9 @@ private StringBuilder GenerateResolutions( { switch (resolution) { + case DeferringResolvable { Resolvable: {} resolvable}: + stringBuilder = GenerateResolutions(stringBuilder, resolvable); + break; case LazyResolution(var reference, var typeFullName, var methodGroup): string owner = ""; if (methodGroup.OwnerReference is { } explicitOwner) @@ -418,7 +424,7 @@ private StringBuilder GenerateRangedInstanceFunction(StringBuilder stringBuilder var parameters = string.Join(", ", overload.Parameter.Select(p => $"{p.TypeFullName} {p.Reference}")); stringBuilder = stringBuilder.AppendLine( - $"public {overload.TypeFullName} {overload.Reference}({parameters})") + $"public {(overload.IsAsync ? "async " : "")}{overload.TypeFullName} {overload.Reference}({parameters})") .AppendLine($"{{") .AppendLine($"this.{rangedInstanceFunctionGroupResolution.LockReference}.Wait();") .AppendLine($"try") diff --git a/Main/Configuration/Attributes.cs b/Main/Configuration/Attributes.cs index 6dc78f7f..ee754284 100644 --- a/Main/Configuration/Attributes.cs +++ b/Main/Configuration/Attributes.cs @@ -187,9 +187,9 @@ public FilterTypeInitializerAttribute(Type type) } [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] -public class MultiContainerAttribute : Attribute +public class CreateFunctionAttribute : Attribute { - public MultiContainerAttribute(params Type[] types) + public CreateFunctionAttribute(Type type, string methodNamePrefix) { } } diff --git a/Main/ContainerInfo.cs b/Main/ContainerInfo.cs index 9e8e1e86..2254b082 100644 --- a/Main/ContainerInfo.cs +++ b/Main/ContainerInfo.cs @@ -7,7 +7,7 @@ internal interface IContainerInfo string FullName { get; } bool IsValid { get; } INamedTypeSymbol ContainerType { get; } - IReadOnlyList ResolutionRootTypes { get; } + IReadOnlyList<(INamedTypeSymbol, string)> CreateFunctionData { get; } } internal class ContainerInfo : IContainerInfo @@ -24,20 +24,20 @@ internal ContainerInfo( FullName = containerClass.FullName(); ContainerType = containerClass; - ResolutionRootTypes = containerClass + CreateFunctionData = containerClass .GetAttributes() - .Where(ad => wellKnowTypes.MultiContainerAttribute.Equals(ad.AttributeClass, SymbolEqualityComparer.Default)) - .SelectMany(ad => ad.ConstructorArguments - .Where(tc => tc.Kind == TypedConstantKind.Type) - .OfType() - .Concat(ad.ConstructorArguments.SelectMany(ca => ca.Kind is TypedConstantKind.Array - ? (IEnumerable)ca.Values - : Array.Empty()))) - .Select(tc => tc.Value as INamedTypeSymbol) - .OfType() + .Where(ad => wellKnowTypes.CreateFunctionAttribute.Equals(ad.AttributeClass, SymbolEqualityComparer.Default)) + .Select(ad => ad.ConstructorArguments.Length == 2 + && ad.ConstructorArguments[0].Kind == TypedConstantKind.Type + && ad.ConstructorArguments[0].Value is INamedTypeSymbol type + && ad.ConstructorArguments[1].Kind == TypedConstantKind.Primitive + && ad.ConstructorArguments[1].Value is string methodNamePrefix + ? (type, methodNamePrefix) + : ((INamedTypeSymbol, string)?) null) + .OfType<(INamedTypeSymbol, string)>() .ToList(); - IsValid = ResolutionRootTypes.Any(); + IsValid = CreateFunctionData.Any(); } public string Name { get; } @@ -45,5 +45,5 @@ internal ContainerInfo( public string FullName { get; } public bool IsValid { get; } public INamedTypeSymbol ContainerType { get; } - public IReadOnlyList ResolutionRootTypes { get; } + public IReadOnlyList<(INamedTypeSymbol, string)> CreateFunctionData { get; } } \ No newline at end of file diff --git a/Main/ExecuteImpl.cs b/Main/ExecuteImpl.cs index 85a36858..a203362e 100644 --- a/Main/ExecuteImpl.cs +++ b/Main/ExecuteImpl.cs @@ -53,7 +53,7 @@ public void Execute() .Select(x => semanticModel.GetDeclaredSymbol(x)) .Where(x => x is not null) .OfType() - .Where(x => x.GetAttributes().Any(ad => _wellKnownTypes.MultiContainerAttribute.Equals(ad.AttributeClass, SymbolEqualityComparer.Default))) + .Where(x => x.GetAttributes().Any(ad => _wellKnownTypes.CreateFunctionAttribute.Equals(ad.AttributeClass, SymbolEqualityComparer.Default))) .ToList(); foreach (var namedTypeSymbol in containerClasses) { @@ -63,7 +63,7 @@ public void Execute() if (containerInfo.IsValid) { var containerResolutionBuilder = _containerResolutionBuilderFactory(containerInfo); - containerResolutionBuilder.AddCreateResolveFunctions(containerInfo.ResolutionRootTypes); + containerResolutionBuilder.AddCreateResolveFunctions(containerInfo.CreateFunctionData); var containerResolution = containerResolutionBuilder.Build(); var errorTreeItems = _resolutionTreeCreationErrorHarvester.Harvest(containerResolution); if (errorTreeItems.Any()) diff --git a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs index 8832c9da..98334772 100644 --- a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs @@ -4,7 +4,7 @@ namespace MrMeeseeks.DIE.ResolutionBuilding; internal interface IContainerResolutionBuilder : IRangeResolutionBaseBuilder { - void AddCreateResolveFunctions(IReadOnlyList rootTypes); + void AddCreateResolveFunctions(IReadOnlyList<(INamedTypeSymbol, string)> createFunctionData); FunctionCallResolution CreateContainerInstanceReferenceResolution( ForConstructorParameter parameter, @@ -53,7 +53,7 @@ internal ContainerResolutionBuilder( _transientScopeAdapterReference = RootReferenceGenerator.Generate("TransientScopeAdapter"); } - public void AddCreateResolveFunctions(IReadOnlyList rootTypes) + public void AddCreateResolveFunctions(IReadOnlyList<(INamedTypeSymbol, string)> createFunctionData) { foreach (var typeSymbol in rootTypes) _rootResolutions.Add(_createFunctionResolutionBuilderFactory(this, typeSymbol)); @@ -109,7 +109,8 @@ public ContainerResolution Build() f.Resolvable, f.Parameter, DisposalHandling, - f.LocalFunctions)) + f.LocalFunctions, + f.IsAsync)) .ToList(); var i = 0; @@ -126,7 +127,8 @@ public ContainerResolution Build() Array.Empty<(string, string)>()), f.Parameter, DisposalHandling, - Array.Empty())); + Array.Empty(), + f.IsAsync)); while (RangedInstanceReferenceResolutions.Values.Any(r => r.HasWorkToDo) || _scopeManager.HasWorkToDo) diff --git a/Main/ResolutionBuilding/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/FunctionResolutionBuilder.cs index 707ab1ce..98ff2764 100644 --- a/Main/ResolutionBuilding/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/FunctionResolutionBuilder.cs @@ -2,8 +2,16 @@ namespace MrMeeseeks.DIE.ResolutionBuilding; +internal enum SynchronicityDecision +{ + Undecided, + Sync, + Async +} + internal interface IFunctionResolutionBuilder { + FunctionCallResolution BuildFunctionCall( IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters, string? ownerReference); @@ -59,8 +67,10 @@ public override FunctionResolution Build() => f.Resolvable, f.Parameter, f.DisposalHandling, - f.LocalFunctions)) - .ToList()); + f.LocalFunctions, + f.IsAsync)) + .ToList(), + IsAsync); } internal interface IContainerCreateFunctionResolutionBuilder : IFunctionResolutionBuilder @@ -108,8 +118,10 @@ public override FunctionResolution Build() => f.Resolvable, f.Parameter, f.DisposalHandling, - f.LocalFunctions)) - .ToList()); + f.LocalFunctions, + f.IsAsync)) + .ToList(), + IsAsync); } internal interface IScopeRootCreateFunctionResolutionBuilder : IFunctionResolutionBuilder @@ -165,8 +177,10 @@ public override FunctionResolution Build() f.Resolvable, f.Parameter, f.DisposalHandling, - f.LocalFunctions)) - .ToList()); + f.LocalFunctions, + f.IsAsync)) + .ToList(), + IsAsync); } } @@ -220,8 +234,10 @@ public override FunctionResolution Build() f.Resolvable, f.Parameter, f.DisposalHandling, - f.LocalFunctions)) - .ToList()); + f.LocalFunctions, + f.IsAsync)) + .ToList(), + IsAsync); } } @@ -239,12 +255,16 @@ internal abstract class FunctionResolutionBuilder : IFunctionResolutionBuilder private readonly IUserProvidedScopeElements _userProvidedScopeElements; protected readonly IList LocalFunctions = new List(); + + protected readonly IList PotentialAwaits = new List(); protected abstract string Name { get; } protected string TypeFullName => ReturnType.FullName(); protected IReadOnlyList Parameters { get; } + protected bool IsAsync => PotentialAwaits.Any(pa => pa.Await); + internal FunctionResolutionBuilder( // parameters IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, @@ -847,6 +867,10 @@ false when initializationMethod.ReturnType.Equals(_wellKnownTypes.ValueTask, Sym RootReferenceGenerator.Generate(_wellKnownTypes.ValueTask)), _ => typeInitializationResolution }; + if (typeInitializationResolution is IAwaitableResolution awaitableResolution) + { + PotentialAwaits.Add(awaitableResolution); + } } diff --git a/Main/ResolutionBuilding/RangedFunctionResolutionBuilderManager.cs b/Main/ResolutionBuilding/RangedFunctionResolutionBuilderManager.cs index bb0dbcd5..7c25997c 100644 --- a/Main/ResolutionBuilding/RangedFunctionResolutionBuilderManager.cs +++ b/Main/ResolutionBuilding/RangedFunctionResolutionBuilderManager.cs @@ -72,7 +72,8 @@ public void DoWork() functionResolution.Resolvable, functionResolution.Parameter, functionResolution.DisposalHandling, - functionResolution.LocalFunctions)); + functionResolution.LocalFunctions, + false)); // todo async support } } diff --git a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs index 5ed74f65..812e8ff3 100644 --- a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs @@ -156,7 +156,8 @@ public void DoWork() functionResolution.Resolvable, functionResolution.Parameter, functionResolution.DisposalHandling, - functionResolution.LocalFunctions)); + functionResolution.LocalFunctions, + functionResolution.IsAsync)); } DoRangedInstancesWork(); diff --git a/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs b/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs index 6082dbbf..b1e14f7d 100644 --- a/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs @@ -146,7 +146,8 @@ public void DoWork() functionResolution.Resolvable, functionResolution.Parameter, functionResolution.DisposalHandling, - functionResolution.LocalFunctions)); + functionResolution.LocalFunctions, + functionResolution.IsAsync)); } DoRangedInstancesWork(); diff --git a/Main/ResolutionTreeCreationErrorHarvester.cs b/Main/ResolutionTreeCreationErrorHarvester.cs index e7e4d437..5e550077 100644 --- a/Main/ResolutionTreeCreationErrorHarvester.cs +++ b/Main/ResolutionTreeCreationErrorHarvester.cs @@ -17,6 +17,8 @@ static void Inner(ResolutionTreeItem item, ICollection errorTreeI { switch (item) { + case DeferringResolvable: + break; case FunctionCallResolution: break; case RootResolutionFunction: diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index e4835531..9ee05aa2 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -6,13 +6,19 @@ internal abstract record Resolvable( string Reference, string TypeFullName) : ResolutionTreeItem; +internal record DeferringResolvable() : Resolvable("", "") +{ + internal Resolvable? Resolvable { get; set; } +} + internal record FunctionResolution( string Reference, string TypeFullName, Resolvable Resolvable, IReadOnlyList Parameter, DisposalHandling DisposalHandling, - IReadOnlyList LocalFunctions) : Resolvable(Reference, TypeFullName); + IReadOnlyList LocalFunctions, + bool IsAsync) : Resolvable(Reference, TypeFullName); internal record RootResolutionFunction( string Reference, @@ -21,8 +27,9 @@ internal record RootResolutionFunction( Resolvable Resolvable, IReadOnlyList Parameter, DisposalHandling DisposalHandling, - IReadOnlyList LocalFunctions) - : FunctionResolution(Reference, TypeFullName, Resolvable, Parameter, DisposalHandling, LocalFunctions); + IReadOnlyList LocalFunctions, + bool IsAsync) + : FunctionResolution(Reference, TypeFullName, Resolvable, Parameter, DisposalHandling, LocalFunctions, IsAsync); internal record LocalFunctionResolution( string Reference, @@ -30,8 +37,9 @@ internal record LocalFunctionResolution( Resolvable Resolvable, IReadOnlyList Parameter, DisposalHandling DisposalHandling, - IReadOnlyList LocalFunctions) - : FunctionResolution(Reference, TypeFullName, Resolvable, Parameter, DisposalHandling, LocalFunctions); + IReadOnlyList LocalFunctions, + bool IsAsync) + : FunctionResolution(Reference, TypeFullName, Resolvable, Parameter, DisposalHandling, LocalFunctions, IsAsync); internal record RangedInstanceFunctionResolution( string Reference, @@ -39,8 +47,9 @@ internal record RangedInstanceFunctionResolution( Resolvable Resolvable, IReadOnlyList Parameter, DisposalHandling DisposalHandling, - IReadOnlyList LocalFunctions) - : FunctionResolution(Reference, TypeFullName, Resolvable, Parameter, DisposalHandling, LocalFunctions); + IReadOnlyList LocalFunctions, + bool IsAsync) + : FunctionResolution(Reference, TypeFullName, Resolvable, Parameter, DisposalHandling, LocalFunctions, IsAsync); internal record RangedInstanceFunctionGroupResolution( string TypeFullName, @@ -72,13 +81,18 @@ internal record SyncTypeInitializationResolution( string TypeFullName, string MethodName) : ITypeInitializationResolution; +internal interface IAwaitableResolution +{ + bool Await { get; } +} + internal record TaskBaseTypeInitializationResolution( string TypeFullName, string MethodName, string TaskTypeFullName, - string TaskReference) : ITypeInitializationResolution + string TaskReference) : ITypeInitializationResolution, IAwaitableResolution { - internal bool Await { get; set; } = true; + public bool Await { get; set; } = true; } internal record TaskTypeInitializationResolution( diff --git a/Main/WellKnownTypes.cs b/Main/WellKnownTypes.cs index 000e50c8..94d6b01c 100644 --- a/Main/WellKnownTypes.cs +++ b/Main/WellKnownTypes.cs @@ -32,7 +32,7 @@ internal record WellKnownTypes( INamedTypeSymbol FilterConstructorChoiceAttribute, INamedTypeSymbol FilterTypeInitializerAttribute, INamedTypeSymbol CustomScopeForRootTypesAttribute, - INamedTypeSymbol MultiContainerAttribute, + INamedTypeSymbol CreateFunctionAttribute, INamedTypeSymbol Disposable, INamedTypeSymbol AsyncDisposable, INamedTypeSymbol Lazy1, @@ -161,8 +161,8 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK var filterTypeInitializerAttribute = compilation .GetTypeByMetadataName(typeof(FilterTypeInitializerAttribute).FullName ?? ""); - var multiContainerAttribute = compilation - .GetTypeByMetadataName(typeof(MultiContainerAttribute).FullName ?? ""); + var createFunctionAttribute = compilation + .GetTypeByMetadataName(typeof(CreateFunctionAttribute).FullName ?? ""); if (spyAggregationAttribute is not null && spyConstructorChoiceAggregationAttribute is not null @@ -193,7 +193,7 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK && filterConstructorChoiceAttribute is not null && filterTypeInitializerAttribute is not null && customScopeForRootTypesAttribute is not null - && multiContainerAttribute is not null + && createFunctionAttribute is not null && iDisposable is not null && iAsyncDisposable is not null && lazy1 is not null @@ -243,7 +243,7 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK FilterConstructorChoiceAttribute: filterConstructorChoiceAttribute, FilterTypeInitializerAttribute: filterTypeInitializerAttribute, CustomScopeForRootTypesAttribute: customScopeForRootTypesAttribute, - MultiContainerAttribute: multiContainerAttribute, + CreateFunctionAttribute: createFunctionAttribute, Disposable: iDisposable, AsyncDisposable: iAsyncDisposable, Lazy1: lazy1, diff --git a/Test/Async/AwaitedDependency/Dependency.cs b/Test/Async/AwaitedDependency/Dependency.cs new file mode 100644 index 00000000..7c1bdb04 --- /dev/null +++ b/Test/Async/AwaitedDependency/Dependency.cs @@ -0,0 +1,33 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Async.AwaitedDependency.Dependency; + + +internal class Dependency : ITaskTypeInitializer +{ + public bool IsInitialized { get; private set; } + + async Task ITaskTypeInitializer.InitializeAsync() + { + await Task.Delay(500).ConfigureAwait(false); + IsInitialized = true; + } +} + +//[MultiContainer(typeof(Dependency))] +internal partial class Container +{ +} + +public class Tests +{ + [Fact] + public void Test() + { + using var container = new Container(); + var instance = container.Create0(); + Assert.True(instance.IsInitialized); + } +} \ No newline at end of file From a12c281cee42a0534f10aeb326fc1cec015415ac Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sat, 26 Mar 2022 12:00:29 +0100 Subject: [PATCH 051/162] CreateFunctionAttribute instead of MultiContainerAttribute --- Main/CodeBuilding/RangeCodeBaseBuilder.cs | 20 +++ .../ContainerResolutionBuilder.cs | 157 ++++++++++++++---- .../FunctionResolutionBuilder.cs | 46 +++-- Main/ResolutionTreeItem.cs | 12 +- Sample/Context.cs | 43 ++--- Sample/Program.cs | 6 +- Test/Async/AwaitedDependency/Dependency.cs | 6 +- .../WrappedDependency/DecorationChaining.cs | 4 +- Test/Async/WrappedDependency/Func.cs | 4 +- Test/Async/WrappedDependency/Lazy.cs | 4 +- Test/Async/WrappedDependency/SyncToTask.cs | 4 +- .../WrappedDependency/SyncToValueTask.cs | 4 +- .../Async/WrappedDependency/TaskCollection.cs | 4 +- .../WrappedDependency/TaskComposition.cs | 5 +- Test/Async/WrappedDependency/TaskToTask.cs | 5 +- .../WrappedDependency/TaskToValueTask.cs | 4 +- .../WrappedDependency/ValueTaskCollection.cs | 2 +- .../WrappedDependency/ValueTaskComposition.cs | 2 +- .../WrappedDependency/ValueTaskToTask.cs | 2 +- .../WrappedDependency/ValueTaskToValueTask.cs | 2 +- Test/CompositeTests.cs | 45 ++--- Test/ConstructorChoiceTests.cs | 4 +- Test/ConstructorTests.cs | 4 +- Test/DecoratorTests.cs | 24 +-- Test/FactoryTests.cs | 10 +- Test/Func/Vanilla.cs | 4 +- Test/ImplementationAggregationTests.cs | 4 +- Test/InstanceTests.cs | 5 +- Test/Lazy/Vanilla.cs | 4 +- Test/PropertyTests.cs | 4 +- ...opeSpecificAttributesTestsWithDecorator.cs | 7 +- ...cAttributesTestsWithImplementationLists.cs | 4 +- ...cificAttributesTestsWithImplementations.cs | 4 +- Test/SyncTypeInitializationTest.cs | 2 +- Test/TransientScopeInstanceTests.cs | 12 +- Test/ValueTupleTests.cs | 16 +- 36 files changed, 306 insertions(+), 183 deletions(-) diff --git a/Main/CodeBuilding/RangeCodeBaseBuilder.cs b/Main/CodeBuilding/RangeCodeBaseBuilder.cs index 7a8b6a16..243661fa 100644 --- a/Main/CodeBuilding/RangeCodeBaseBuilder.cs +++ b/Main/CodeBuilding/RangeCodeBaseBuilder.cs @@ -149,6 +149,16 @@ private static StringBuilder GenerateFields( case DeferringResolvable { Resolvable: {} resolvable}: stringBuilder = GenerateFields(stringBuilder, resolvable); break; + case ValueTaskFromWrappedTaskResolution(var resolvable, var reference, var fullName): + stringBuilder = GenerateFields(stringBuilder, resolvable); + stringBuilder = stringBuilder + .AppendLine($"{fullName} {reference};"); + break; + case TaskFromWrappedValueTaskResolution(var resolvable, var reference, var fullName): + stringBuilder = GenerateFields(stringBuilder, resolvable); + stringBuilder = stringBuilder + .AppendLine($"{fullName} {reference};"); + break; case TaskFromTaskResolution(var wrappedResolvable, _, var taskReference, var taskFullName): stringBuilder = GenerateFields(stringBuilder, wrappedResolvable); stringBuilder = stringBuilder @@ -259,6 +269,16 @@ private StringBuilder GenerateResolutions( stringBuilder = stringBuilder .AppendLine($"{reference} = ({typeFullName}){owner2}{functionReference}({string.Join(", ", parameters.Select(p => $"{p.Name}: {p.Reference}"))});"); break; + case ValueTaskFromWrappedTaskResolution(var resolvable, var reference, var fullName): + stringBuilder = GenerateResolutions(stringBuilder, resolvable); + stringBuilder = stringBuilder + .AppendLine($"{reference} = new {fullName}({resolvable.Reference});"); + break; + case TaskFromWrappedValueTaskResolution(var resolvable, var reference, var fullName): + stringBuilder = GenerateResolutions(stringBuilder, resolvable); + stringBuilder = stringBuilder + .AppendLine($"{reference} = {resolvable.Reference}.AsTask();"); + break; case TaskFromTaskResolution(var wrappedResolvable, var initialization, var taskReference, _): stringBuilder = GenerateResolutions(stringBuilder, wrappedResolvable); stringBuilder = stringBuilder diff --git a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs index 98334772..a9d66a34 100644 --- a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration; namespace MrMeeseeks.DIE.ResolutionBuilding; @@ -17,9 +18,10 @@ internal class ContainerResolutionBuilder : RangeResolutionBaseBuilder, IContain { private readonly IContainerInfo _containerInfo; private readonly ITransientScopeInterfaceResolutionBuilder _transientScopeInterfaceResolutionBuilder; + private readonly WellKnownTypes _wellKnownTypes; private readonly Func _createFunctionResolutionBuilderFactory; - private readonly List _rootResolutions = new (); + private readonly List<(IContainerCreateFunctionResolutionBuilder CreateFunction, string MethodNamePrefix)> _rootResolutions = new (); private readonly string _transientScopeAdapterReference; private readonly IScopeManager _scopeManager; @@ -46,6 +48,7 @@ internal ContainerResolutionBuilder( { _containerInfo = containerInfo; _transientScopeInterfaceResolutionBuilder = transientScopeInterfaceResolutionBuilder; + _wellKnownTypes = wellKnownTypes; _createFunctionResolutionBuilderFactory = createFunctionResolutionBuilderFactory; _scopeManager = scopeManagerFactory(this, transientScopeInterfaceResolutionBuilder); @@ -55,8 +58,8 @@ internal ContainerResolutionBuilder( public void AddCreateResolveFunctions(IReadOnlyList<(INamedTypeSymbol, string)> createFunctionData) { - foreach (var typeSymbol in rootTypes) - _rootResolutions.Add(_createFunctionResolutionBuilderFactory(this, typeSymbol)); + foreach (var (typeSymbol, methodNamePrefix) in createFunctionData) + _rootResolutions.Add((_createFunctionResolutionBuilderFactory(this, typeSymbol), methodNamePrefix)); } public FunctionCallResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter, string containerReference) => @@ -100,35 +103,127 @@ public override ScopeRootResolution CreateScopeRootResolution( public ContainerResolution Build() { - var privateRootFunctions = _rootResolutions - .Select(b => b.Build()) - .Select(f => new RootResolutionFunction( - f.Reference, - f.TypeFullName, + var rootFunctions = new List(); + foreach (var (createFunction, methodNamePrefix) in _rootResolutions) + { + var privateFunctionResolution = createFunction.Build(); + var privateRootResolutionFunction = new RootResolutionFunction( + privateFunctionResolution.Reference, + privateFunctionResolution.TypeFullName, "private", - f.Resolvable, - f.Parameter, - DisposalHandling, - f.LocalFunctions, - f.IsAsync)) - .ToList(); - - var i = 0; - var publicRootFunctions = privateRootFunctions - .Select(f => new RootResolutionFunction( - $"Create{i++}", - f.TypeFullName, - "public", - new FunctionCallResolution( - RootReferenceGenerator.Generate("result"), - f.TypeFullName, - f.Reference, - "this", - Array.Empty<(string, string)>()), - f.Parameter, + privateFunctionResolution.Resolvable, + privateFunctionResolution.Parameter, DisposalHandling, - Array.Empty(), - f.IsAsync)); + privateFunctionResolution.LocalFunctions, + privateFunctionResolution.IsAsync); + + rootFunctions.Add(privateRootResolutionFunction); + + // Create function stays sync + if (createFunction.OriginalReturnType.Equals( + createFunction.ActualReturnType, + SymbolEqualityComparer.Default)) + { + var publicSyncResolutionFunction = new RootResolutionFunction( + methodNamePrefix, + privateRootResolutionFunction.TypeFullName, + "public", + createFunction.BuildFunctionCall( + Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>(), + "this"), + privateRootResolutionFunction.Parameter, + DisposalHandling, + Array.Empty(), + false); + + rootFunctions.Add(publicSyncResolutionFunction); + + var boundTaskTypeFullName = _wellKnownTypes + .Task1 + .Construct(createFunction.OriginalReturnType) + .FullName(); + var wrappedTaskReference = RootReferenceGenerator.Generate(_wellKnownTypes.Task); + var publicTaskResolutionFunction = new RootResolutionFunction( + $"{methodNamePrefix}Async", + boundTaskTypeFullName, + "public", + new TaskFromSyncResolution( + createFunction.BuildFunctionCall( + Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>(), + "this"), + wrappedTaskReference, + boundTaskTypeFullName), + privateRootResolutionFunction.Parameter, + DisposalHandling, + Array.Empty(), + false); + + rootFunctions.Add(publicTaskResolutionFunction); + + var boundValueTaskTypeFullName = _wellKnownTypes + .ValueTask1 + .Construct(createFunction.OriginalReturnType) + .FullName(); + var wrappedValueTaskReference = RootReferenceGenerator.Generate(_wellKnownTypes.Task); + var publicValueTaskResolutionFunction = new RootResolutionFunction( + $"{methodNamePrefix}ValueAsync", + boundValueTaskTypeFullName, + "public", + new ValueTaskFromSyncResolution( + createFunction.BuildFunctionCall( + Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>(), + "this"), + wrappedValueTaskReference, + boundValueTaskTypeFullName), + privateRootResolutionFunction.Parameter, + DisposalHandling, + Array.Empty(), + false); + + rootFunctions.Add(publicValueTaskResolutionFunction); + } + else if (createFunction.ActualReturnType is { } actual + && actual.Equals(_wellKnownTypes.Task1.Construct(createFunction.OriginalReturnType), + SymbolEqualityComparer.Default)) + { + var wrappedTaskReference = RootReferenceGenerator.Generate(_wellKnownTypes.Task); + var publicTaskResolutionFunction = new RootResolutionFunction( + $"{methodNamePrefix}Async", + actual.FullName(), + "public", + createFunction.BuildFunctionCall( + Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>(), + "this"), + privateRootResolutionFunction.Parameter, + DisposalHandling, + Array.Empty(), + false); + + rootFunctions.Add(publicTaskResolutionFunction); + + var boundValueTaskTypeFullName = _wellKnownTypes + .ValueTask1 + .Construct(createFunction.OriginalReturnType) + .FullName(); + var wrappedValueTaskReference = RootReferenceGenerator.Generate(_wellKnownTypes.Task); + var publicValueTaskResolutionFunction = new RootResolutionFunction( + $"{methodNamePrefix}ValueAsync", + boundValueTaskTypeFullName, + "public", + new ValueTaskFromWrappedTaskResolution( + createFunction.BuildFunctionCall( + Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>(), + "this"), + wrappedValueTaskReference, + boundValueTaskTypeFullName), + privateRootResolutionFunction.Parameter, + DisposalHandling, + Array.Empty(), + false); + + rootFunctions.Add(publicValueTaskResolutionFunction); + } + } while (RangedInstanceReferenceResolutions.Values.Any(r => r.HasWorkToDo) || _scopeManager.HasWorkToDo) @@ -140,7 +235,7 @@ public ContainerResolution Build() var (transientScopeResolutions, scopeResolutions) = _scopeManager.Build(); return new( - privateRootFunctions.Concat(publicRootFunctions).ToList(), + rootFunctions, DisposalHandling, RangedInstanceReferenceResolutions.Values.Select(b => b.Build()).ToList(), _transientScopeInterfaceResolutionBuilder.Build(), diff --git a/Main/ResolutionBuilding/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/FunctionResolutionBuilder.cs index 98ff2764..c96039ee 100644 --- a/Main/ResolutionBuilding/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/FunctionResolutionBuilder.cs @@ -11,6 +11,8 @@ internal enum SynchronicityDecision internal interface IFunctionResolutionBuilder { + INamedTypeSymbol OriginalReturnType { get; } + INamedTypeSymbol? ActualReturnType { get; } FunctionCallResolution BuildFunctionCall( IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters, @@ -53,8 +55,11 @@ public LocalFunctionResolutionBuilder( protected override string Name { get; } - public override FunctionResolution Build() => - new(Name, + public override FunctionResolution Build() + { + AdjustForSynchronicity(); + return new( + Name, TypeFullName, SwitchType(new SwitchTypeParameter(_returnType, _parameters)).Item1, _parameters.Select(t => t.Resolution).ToList(), @@ -71,6 +76,7 @@ public override FunctionResolution Build() => f.IsAsync)) .ToList(), IsAsync); + } } internal interface IContainerCreateFunctionResolutionBuilder : IFunctionResolutionBuilder @@ -102,12 +108,16 @@ public ContainerCreateFunctionResolutionBuilder( protected override string Name { get; } - public override FunctionResolution Build() => - new(RootReferenceGenerator.Generate("Create"), + public override FunctionResolution Build() + { + var resolvable = SwitchType(new SwitchTypeParameter( + _returnType, + Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>())).Item1; + AdjustForSynchronicity(); + return new( + Name, TypeFullName, - SwitchType(new SwitchTypeParameter( - _returnType, - Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>())).Item1, + resolvable, Array.Empty(), _rangeResolutionBaseBuilder.DisposalHandling, LocalFunctions @@ -122,6 +132,7 @@ public override FunctionResolution Build() => f.IsAsync)) .ToList(), IsAsync); + } } internal interface IScopeRootCreateFunctionResolutionBuilder : IFunctionResolutionBuilder @@ -155,6 +166,7 @@ public ScopeRootCreateFunctionResolutionBuilder( public override FunctionResolution Build() { + AdjustForSynchronicity(); var resolvable = _scopeRootParameter switch { CreateInterfaceParameter createInterfaceParameter => CreateInterface(createInterfaceParameter).Item1, @@ -191,7 +203,6 @@ internal interface IRangedFunctionResolutionBuilder : IFunctionResolutionBuilder internal class RangedFunctionResolutionBuilder : FunctionResolutionBuilder, IRangedFunctionResolutionBuilder { private readonly IRangeResolutionBaseBuilder _rangeResolutionBaseBuilder; - private readonly string _reference; private readonly ForConstructorParameter _forConstructorParameter; public RangedFunctionResolutionBuilder( @@ -208,7 +219,6 @@ public RangedFunctionResolutionBuilder( : base(rangeResolutionBaseBuilder, forConstructorParameter.ImplementationType, forConstructorParameter.CurrentFuncParameters, wellKnownTypes, referenceGeneratorFactory, localFunctionResolutionBuilderFactory) { _rangeResolutionBaseBuilder = rangeResolutionBaseBuilder; - _reference = reference; _forConstructorParameter = forConstructorParameter; Name = reference; @@ -218,10 +228,11 @@ public RangedFunctionResolutionBuilder( public override FunctionResolution Build() { + AdjustForSynchronicity(); var resolvable = CreateConstructorResolution(_forConstructorParameter).Item1; return new( - _reference, + Name, TypeFullName, resolvable, _forConstructorParameter.CurrentFuncParameters.Select(t => t.Resolution).ToList(), @@ -243,7 +254,6 @@ public override FunctionResolution Build() internal abstract class FunctionResolutionBuilder : IFunctionResolutionBuilder { - public INamedTypeSymbol ReturnType { get; } private readonly IRangeResolutionBaseBuilder _rangeResolutionBaseBuilder; private readonly WellKnownTypes _wellKnownTypes; private readonly Func, ILocalFunctionResolutionBuilder> _localFunctionResolutionBuilderFactory; @@ -259,11 +269,14 @@ internal abstract class FunctionResolutionBuilder : IFunctionResolutionBuilder protected readonly IList PotentialAwaits = new List(); protected abstract string Name { get; } - protected string TypeFullName => ReturnType.FullName(); + protected string TypeFullName => ActualReturnType?.FullName() ?? OriginalReturnType.FullName(); protected IReadOnlyList Parameters { get; } protected bool IsAsync => PotentialAwaits.Any(pa => pa.Await); + + public INamedTypeSymbol OriginalReturnType { get; } + public INamedTypeSymbol? ActualReturnType { get; protected set; } internal FunctionResolutionBuilder( // parameters @@ -277,7 +290,7 @@ internal FunctionResolutionBuilder( IReferenceGeneratorFactory referenceGeneratorFactory, Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) { - ReturnType = returnType; + OriginalReturnType = returnType; _rangeResolutionBaseBuilder = rangeResolutionBaseBuilder; _wellKnownTypes = wellKnownTypes; _localFunctionResolutionBuilderFactory = localFunctionResolutionBuilderFactory; @@ -980,6 +993,13 @@ false when initializationMethod.ReturnType.Equals(_wellKnownTypes.ValueTask, Sym } } + protected void AdjustForSynchronicity() + { + ActualReturnType = IsAsync + ? _wellKnownTypes.Task1.Construct(OriginalReturnType) + : OriginalReturnType; + } + private static DisposableCollectionResolution? ImplementsIDisposable( INamedTypeSymbol type, WellKnownTypes wellKnownTypes, diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index 9ee05aa2..393eadce 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -270,15 +270,15 @@ internal record ValueTaskFromSyncResolution( string ValueTaskReference, string ValueTaskFullName) : TaskBaseResolution(WrappedResolvable, ValueTaskReference, ValueTaskFullName); -internal record TaskFromWrappedValueTask( +internal record TaskFromWrappedValueTaskResolution( Resolvable WrappedResolvable, - string TaskReference, - string TaskFullName); + string Reference, + string FullName) : Resolvable(Reference, FullName); -internal record ValueTaskFromWrappedTask( +internal record ValueTaskFromWrappedTaskResolution( Resolvable WrappedResolvable, - string ValueTaskReference, - string ValueTaskFullName); + string Reference, + string FullName) : Resolvable(Reference, FullName); internal record FunctionCallResolution( string Reference, diff --git a/Sample/Context.cs b/Sample/Context.cs index 9b8f7eaf..96cf4f87 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -1,43 +1,22 @@ -using MrMeeseeks.DIE.Configuration; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; using MrMeeseeks.DIE.Sample; -namespace MrMeeseeks.DIE.Test; +namespace MrMeeseeks.DIE.Test.Async.AwaitedDependency.Dependency; -internal interface IDecoratedScopeRoot -{ - IDecoratedScopeRootDependency Dependency { get; } - IDecoratedScopeRoot Decorated { get; } -} - -internal interface IDecoratedScopeRootDependency {} - -internal class DecoratedScopeRootDependency : IDecoratedScopeRootDependency, IScopeInstance {} - -internal class DecoratorScopeRootBasis : IDecoratedScopeRoot, IScopeRoot, IScopeInstance -{ - public IDecoratedScopeRootDependency Dependency { get; } - public IDecoratedScopeRoot Decorated => this; - - public DecoratorScopeRootBasis( - IDecoratedScopeRootDependency dependency) => - Dependency = dependency; -} - -internal class DecoratorScopeRoot : IDecoratedScopeRoot, IDecorator +internal class Dependency : ITaskTypeInitializer { - public DecoratorScopeRoot(IDecoratedScopeRoot decorated, IDecoratedScopeRootDependency dependency) + public bool IsInitialized { get; private set; } + + async Task ITaskTypeInitializer.InitializeAsync() { - Decorated = decorated; - Dependency = dependency; + await Task.Delay(500).ConfigureAwait(false); + IsInitialized = true; } - - public IDecoratedScopeRootDependency Dependency { get; } - public IDecoratedScopeRoot Decorated { get; } } -[MultiContainer(typeof(IDecoratedScopeRoot))] -internal partial class DecoratorScopeRootContainer +[CreateFunction(typeof(Dependency), "CreateDep")] +internal partial class Container { - } \ No newline at end of file diff --git a/Sample/Program.cs b/Sample/Program.cs index 152ae191..1dfb3ebf 100644 --- a/Sample/Program.cs +++ b/Sample/Program.cs @@ -1,12 +1,12 @@ using System; -using MrMeeseeks.DIE.Test; +using MrMeeseeks.DIE.Test.Async.AwaitedDependency.Dependency; internal class Program { private static void Main() { Console.WriteLine("Hello, world!"); - var container = new DecoratorScopeRootContainer(); - Console.WriteLine(container.Create0()); + var container = new Container(); + Console.WriteLine(container.CreateDepAsync().ConfigureAwait(false)); } } \ No newline at end of file diff --git a/Test/Async/AwaitedDependency/Dependency.cs b/Test/Async/AwaitedDependency/Dependency.cs index 7c1bdb04..2ac91baf 100644 --- a/Test/Async/AwaitedDependency/Dependency.cs +++ b/Test/Async/AwaitedDependency/Dependency.cs @@ -16,7 +16,7 @@ async Task ITaskTypeInitializer.InitializeAsync() } } -//[MultiContainer(typeof(Dependency))] +[CreateFunction(typeof(Dependency), "CreateDep")] internal partial class Container { } @@ -24,10 +24,10 @@ internal partial class Container public class Tests { [Fact] - public void Test() + public async Task Test() { using var container = new Container(); - var instance = container.Create0(); + var instance = await container.CreateDepAsync().ConfigureAwait(false); Assert.True(instance.IsInitialized); } } \ No newline at end of file diff --git a/Test/Async/WrappedDependency/DecorationChaining.cs b/Test/Async/WrappedDependency/DecorationChaining.cs index 57fc8796..c0d749ed 100644 --- a/Test/Async/WrappedDependency/DecorationChaining.cs +++ b/Test/Async/WrappedDependency/DecorationChaining.cs @@ -47,7 +47,7 @@ async ValueTask IValueTaskTypeInitializer.InitializeAsync() } } -[MultiContainer(typeof(Task))] +[CreateFunction(typeof(Task), "CreateDep")] [DecoratorSequenceChoice(typeof(IInterface), typeof(DecoratorA), typeof(DecoratorB))] internal partial class Container { @@ -59,7 +59,7 @@ public class Tests public async Task Test() { using var container = new Container(); - var instance = await container.Create0().ConfigureAwait(false); + var instance = await container.CreateDep().ConfigureAwait(false); Assert.True(instance.IsInitialized); } } \ No newline at end of file diff --git a/Test/Async/WrappedDependency/Func.cs b/Test/Async/WrappedDependency/Func.cs index f2b0f26e..76092ff3 100644 --- a/Test/Async/WrappedDependency/Func.cs +++ b/Test/Async/WrappedDependency/Func.cs @@ -17,7 +17,7 @@ async Task ITaskTypeInitializer.InitializeAsync() } } -[MultiContainer(typeof(Func>))] +[CreateFunction(typeof(Func>), "CreateDep")] internal partial class Container { } @@ -28,7 +28,7 @@ public class Tests public async Task Test() { using var container = new Container(); - var instance = container.Create0(); + var instance = container.CreateDep(); Assert.True((await instance().ConfigureAwait(false)).IsInitialized); } } \ No newline at end of file diff --git a/Test/Async/WrappedDependency/Lazy.cs b/Test/Async/WrappedDependency/Lazy.cs index 108f454b..8561b37e 100644 --- a/Test/Async/WrappedDependency/Lazy.cs +++ b/Test/Async/WrappedDependency/Lazy.cs @@ -18,7 +18,7 @@ async Task ITaskTypeInitializer.InitializeAsync() } } -[MultiContainer(typeof(Lazy>))] +[CreateFunction(typeof(Lazy>), "CreateDep")] internal partial class Container { } @@ -29,7 +29,7 @@ public class Tests public async Task Test() { using var container = new Container(); - var instance = container.Create0(); + var instance = container.CreateDep(); Assert.True((await instance.Value.ConfigureAwait(false)).IsInitialized); } } \ No newline at end of file diff --git a/Test/Async/WrappedDependency/SyncToTask.cs b/Test/Async/WrappedDependency/SyncToTask.cs index b570a3ce..9f24ed63 100644 --- a/Test/Async/WrappedDependency/SyncToTask.cs +++ b/Test/Async/WrappedDependency/SyncToTask.cs @@ -14,7 +14,7 @@ void ITypeInitializer.Initialize() } } -[MultiContainer(typeof(Task))] +[CreateFunction(typeof(Task), "CreateDep")] internal partial class Container { } @@ -25,7 +25,7 @@ public class Tests public async Task Test() { using var container = new Container(); - var instance = await container.Create0().ConfigureAwait(false); + var instance = await container.CreateDep().ConfigureAwait(false); Assert.True(instance.IsInitialized); } } \ No newline at end of file diff --git a/Test/Async/WrappedDependency/SyncToValueTask.cs b/Test/Async/WrappedDependency/SyncToValueTask.cs index a684f297..0c9c6816 100644 --- a/Test/Async/WrappedDependency/SyncToValueTask.cs +++ b/Test/Async/WrappedDependency/SyncToValueTask.cs @@ -15,7 +15,7 @@ void ITypeInitializer.Initialize() } } -[MultiContainer(typeof(ValueTask))] +[CreateFunction(typeof(ValueTask), "CreateDep")] internal partial class Container { } @@ -26,7 +26,7 @@ public class Tests public async Task Test() { using var container = new Container(); - var instance = await container.Create0().ConfigureAwait(false); + var instance = await container.CreateDep().ConfigureAwait(false); Assert.True(instance.IsInitialized); } } \ No newline at end of file diff --git a/Test/Async/WrappedDependency/TaskCollection.cs b/Test/Async/WrappedDependency/TaskCollection.cs index 62f73920..eb971a23 100644 --- a/Test/Async/WrappedDependency/TaskCollection.cs +++ b/Test/Async/WrappedDependency/TaskCollection.cs @@ -47,7 +47,7 @@ internal class DependencyD : IInterface public bool IsInitialized => true; } -[MultiContainer(typeof(IReadOnlyList>))] +[CreateFunction(typeof(IReadOnlyList>), "CreateDep")] internal partial class Container { } @@ -58,7 +58,7 @@ public class Tests public async Task Test() { using var container = new Container(); - var instance = container.Create0(); + var instance = container.CreateDep(); Assert.Equal(4, instance.Count); await Task.WhenAll(instance).ConfigureAwait(false); foreach (var task in instance) diff --git a/Test/Async/WrappedDependency/TaskComposition.cs b/Test/Async/WrappedDependency/TaskComposition.cs index 808377f9..afeb0390 100644 --- a/Test/Async/WrappedDependency/TaskComposition.cs +++ b/Test/Async/WrappedDependency/TaskComposition.cs @@ -66,8 +66,7 @@ public async Task InitializeAsync() public int Count => _composition.Count; } - -[MultiContainer(typeof(Task))] +[CreateFunction(typeof(Task), "CreateDep")] internal partial class Container { } @@ -78,7 +77,7 @@ public class Tests public async Task Test() { using var container = new Container(); - var instance = await container.Create0().ConfigureAwait(false); + var instance = await container.CreateDep().ConfigureAwait(false); Assert.IsType(instance); Assert.Equal(4, ((Composite) instance).Count); Assert.True(instance.IsInitialized); diff --git a/Test/Async/WrappedDependency/TaskToTask.cs b/Test/Async/WrappedDependency/TaskToTask.cs index 6f92f08e..2a58176f 100644 --- a/Test/Async/WrappedDependency/TaskToTask.cs +++ b/Test/Async/WrappedDependency/TaskToTask.cs @@ -15,8 +15,7 @@ async Task ITaskTypeInitializer.InitializeAsync() IsInitialized = true; } } - -[MultiContainer(typeof(Task))] +[CreateFunction(typeof(Task), "CreateDep")] internal partial class Container { } @@ -27,7 +26,7 @@ public class Tests public async Task Test() { using var container = new Container(); - var instance = await container.Create0().ConfigureAwait(false); + var instance = await container.CreateDep().ConfigureAwait(false); Assert.True(instance.IsInitialized); } } \ No newline at end of file diff --git a/Test/Async/WrappedDependency/TaskToValueTask.cs b/Test/Async/WrappedDependency/TaskToValueTask.cs index 89ffa807..098b9f2f 100644 --- a/Test/Async/WrappedDependency/TaskToValueTask.cs +++ b/Test/Async/WrappedDependency/TaskToValueTask.cs @@ -16,7 +16,7 @@ async Task ITaskTypeInitializer.InitializeAsync() } } -[MultiContainer(typeof(ValueTask))] +[CreateFunction(typeof(ValueTask), "CreateDep")] internal partial class Container { } @@ -27,7 +27,7 @@ public class Tests public async Task Test() { using var container = new Container(); - var instance = await container.Create0().ConfigureAwait(false); + var instance = await container.CreateDep().ConfigureAwait(false); Assert.True(instance.IsInitialized); } } \ No newline at end of file diff --git a/Test/Async/WrappedDependency/ValueTaskCollection.cs b/Test/Async/WrappedDependency/ValueTaskCollection.cs index 85bd1057..7c0c9469 100644 --- a/Test/Async/WrappedDependency/ValueTaskCollection.cs +++ b/Test/Async/WrappedDependency/ValueTaskCollection.cs @@ -47,7 +47,7 @@ internal class DependencyD : IInterface public bool IsInitialized => true; } -[MultiContainer(typeof(IReadOnlyList>))] +[CreateFunction(typeof(IReadOnlyList>), "Create0")] internal partial class Container { } diff --git a/Test/Async/WrappedDependency/ValueTaskComposition.cs b/Test/Async/WrappedDependency/ValueTaskComposition.cs index 7e457940..4340d2ec 100644 --- a/Test/Async/WrappedDependency/ValueTaskComposition.cs +++ b/Test/Async/WrappedDependency/ValueTaskComposition.cs @@ -67,7 +67,7 @@ public async Task InitializeAsync() public int Count => _composition.Count; } -[MultiContainer(typeof(ValueTask))] +[CreateFunction(typeof(ValueTask), "Create0")] internal partial class Container { } diff --git a/Test/Async/WrappedDependency/ValueTaskToTask.cs b/Test/Async/WrappedDependency/ValueTaskToTask.cs index 6bf2f256..1fa3becc 100644 --- a/Test/Async/WrappedDependency/ValueTaskToTask.cs +++ b/Test/Async/WrappedDependency/ValueTaskToTask.cs @@ -16,7 +16,7 @@ async ValueTask IValueTaskTypeInitializer.InitializeAsync() } } -[MultiContainer(typeof(Task))] +[CreateFunction(typeof(Task), "Create0")] internal partial class Container { } diff --git a/Test/Async/WrappedDependency/ValueTaskToValueTask.cs b/Test/Async/WrappedDependency/ValueTaskToValueTask.cs index b5449cb3..0eb31139 100644 --- a/Test/Async/WrappedDependency/ValueTaskToValueTask.cs +++ b/Test/Async/WrappedDependency/ValueTaskToValueTask.cs @@ -16,7 +16,7 @@ async ValueTask IValueTaskTypeInitializer.InitializeAsync() } } -[MultiContainer(typeof(ValueTask))] +[CreateFunction(typeof(ValueTask), "Create0")] internal partial class Container { } diff --git a/Test/CompositeTests.cs b/Test/CompositeTests.cs index dd1d4bfe..63ac7138 100644 --- a/Test/CompositeTests.cs +++ b/Test/CompositeTests.cs @@ -31,7 +31,8 @@ public CompositeNormal(IReadOnlyList composites) => public IReadOnlyList Composites { get; } } -[MultiContainer(typeof(ICompositeNormal), typeof(IReadOnlyList))] +[CreateFunction(typeof(ICompositeNormal), "CreateDep")] +[CreateFunction(typeof(IReadOnlyList), "CreateCollection")] internal partial class CompositeNormalContainer { @@ -43,7 +44,7 @@ public partial class CompositeTests public void Normal() { using var container = new CompositeNormalContainer(); - var composite = container.Create0(); + var composite = container.CreateDep(); foreach (var compositeComposite in composite.Composites) { Assert.NotEqual(composite, compositeComposite); @@ -56,7 +57,7 @@ public void Normal() public void NormalList() { using var container = new CompositeNormalContainer(); - var composites = container.Create1(); + var composites = container.CreateCollection(); foreach (var compositeComposite in composites) { var type = compositeComposite.GetType(); @@ -89,7 +90,8 @@ public CompositeContainerInstance(IReadOnlyList com public IReadOnlyList Composites { get; } } -[MultiContainer(typeof(ICompositeContainerInstance), typeof(IReadOnlyList))] +[CreateFunction(typeof(ICompositeContainerInstance), "CreateDep")] +[CreateFunction(typeof(IReadOnlyList), "CreateCollection")] internal partial class CompositeContainerInstanceContainer { @@ -101,14 +103,14 @@ public partial class CompositeTests public void ContainerInstance() { using var container = new CompositeContainerInstanceContainer(); - var composite = container.Create0(); + var composite = container.CreateDep(); foreach (var compositeComposite in composite.Composites) { Assert.NotEqual(composite, compositeComposite); var type = compositeComposite.GetType(); Assert.True(type == typeof(CompositeContainerInstanceBasisA) || type == typeof(CompositeContainerInstanceBasisB)); } - var nextComposite = container.Create0(); + var nextComposite = container.CreateDep(); Assert.Equal(composite, nextComposite); } @@ -116,14 +118,14 @@ public void ContainerInstance() public void ContainerInstanceList() { using var container = new CompositeContainerInstanceContainer(); - var composites = container.Create1(); + var composites = container.CreateCollection(); foreach (var compositeComposite in composites) { var type = compositeComposite.GetType(); Assert.True(type == typeof(CompositeContainerInstanceBasisA) || type == typeof(CompositeContainerInstanceBasisB)); } Assert.Equal(2, composites.Count); - var nextComposites = container.Create1(); + var nextComposites = container.CreateCollection(); Assert.Equal(composites[0], nextComposites[0]); Assert.Equal(composites[1], nextComposites[1]); } @@ -152,7 +154,8 @@ public CompositeMixedScoping(IReadOnlyList composites) = public IReadOnlyList Composites { get; } } -[MultiContainer(typeof(ICompositeMixedScoping), typeof(IReadOnlyList))] +[CreateFunction(typeof(ICompositeMixedScoping), "CreateDep")] +[CreateFunction(typeof(IReadOnlyList), "CreateCollection")] internal partial class CompositeMixedScopingContainer { @@ -164,14 +167,14 @@ public partial class CompositeTests public void MixedScoping() { using var container = new CompositeMixedScopingContainer(); - var composite = container.Create0(); + var composite = container.CreateDep(); foreach (var compositeComposite in composite.Composites) { Assert.NotEqual(composite, compositeComposite); var type = compositeComposite.GetType(); Assert.True(type == typeof(CompositeMixedScopingBasisA) || type == typeof(CompositeMixedScopingBasisB)); } - var nextComposite = container.Create0(); + var nextComposite = container.CreateDep(); Assert.NotEqual(composite, nextComposite); } @@ -179,14 +182,14 @@ public void MixedScoping() public void MixedScopingList() { using var container = new CompositeMixedScopingContainer(); - var composites = container.Create1(); + var composites = container.CreateCollection(); foreach (var compositeComposite in composites) { var type = compositeComposite.GetType(); Assert.True(type == typeof(CompositeMixedScopingBasisA) || type == typeof(CompositeMixedScopingBasisB)); } Assert.Equal(2, composites.Count); - var nextComposites = container.Create1(); + var nextComposites = container.CreateCollection(); Assert.True(composites[0].Equals(nextComposites[0]) && !composites[1].Equals(nextComposites[1]) || composites[1].Equals(nextComposites[1]) && !composites[0].Equals(nextComposites[0])); } @@ -230,7 +233,8 @@ public CompositeScopeRoot(IReadOnlyList composites, ICompos public ICompositeScopeRootDependency Dependency { get; } } -[MultiContainer(typeof(ICompositeScopeRoot), typeof(IReadOnlyList))] +[CreateFunction(typeof(ICompositeScopeRoot), "CreateDep")] +[CreateFunction(typeof(IReadOnlyList), "CreateCollection")] internal partial class CompositeScopeRootContainer { @@ -242,7 +246,7 @@ public partial class CompositeTests public void ScopeRoot() { using var container = new CompositeScopeRootContainer(); - var composite = container.Create0(); + var composite = container.CreateDep(); foreach (var compositeComposite in composite.Composites) { Assert.NotEqual(composite, compositeComposite); @@ -250,7 +254,7 @@ public void ScopeRoot() Assert.True(type == typeof(CompositeScopeRootBasisA) || type == typeof(CompositeScopeRootBasisB)); Assert.Equal(composite.Dependency, compositeComposite.Dependency); } - var next = container.Create0(); + var next = container.CreateDep(); Assert.NotEqual(composite.Dependency, next.Dependency); } @@ -258,7 +262,7 @@ public void ScopeRoot() public void ScopeRootList() { using var container = new CompositeScopeRootContainer(); - var composites = container.Create1(); + var composites = container.CreateCollection(); foreach (var compositeComposite in composites) { var type = compositeComposite.GetType(); @@ -316,7 +320,8 @@ public CompositeDecorated(IReadOnlyList composites) => public ICompositeDecorated Decorated => this; } -[MultiContainer(typeof(ICompositeDecorated), typeof(IReadOnlyList))] +[CreateFunction(typeof(ICompositeDecorated), "CreateDep")] +[CreateFunction(typeof(IReadOnlyList), "CreateCollection")] internal partial class CompositeDecoratedContainer { @@ -328,7 +333,7 @@ public partial class CompositeTests public void Decorated() { using var container = new CompositeDecoratedContainer(); - var composite = container.Create0(); + var composite = container.CreateDep(); Assert.IsType(composite); Assert.IsType(composite.Decorated); foreach (var compositeComposite in composite.Composites) @@ -345,7 +350,7 @@ public void Decorated() public void DecoratedList() { using var container = new CompositeDecoratedContainer(); - var composites = container.Create1(); + var composites = container.CreateCollection(); foreach (var compositeComposite in composites) { Assert.IsType(compositeComposite); diff --git a/Test/ConstructorChoiceTests.cs b/Test/ConstructorChoiceTests.cs index 9e1f111a..59df9570 100644 --- a/Test/ConstructorChoiceTests.cs +++ b/Test/ConstructorChoiceTests.cs @@ -7,7 +7,7 @@ namespace MrMeeseeks.DIE.Test; -[MultiContainer(typeof(DateTime))] +[CreateFunction(typeof(DateTime), "CreateDep")] internal partial class ConstructorChoiceContainer { @@ -19,7 +19,7 @@ public class ImplementationAggregationTests public void ResolveExternalType() { using var container = new ConstructorChoiceContainer(); - var dateTime = container.Create0(); + var dateTime = container.CreateDep(); Assert.Equal(DateTime.MinValue, dateTime); } } \ No newline at end of file diff --git a/Test/ConstructorTests.cs b/Test/ConstructorTests.cs index ae6f15bd..b41d4d9d 100644 --- a/Test/ConstructorTests.cs +++ b/Test/ConstructorTests.cs @@ -17,7 +17,7 @@ internal class ConstructorInit : IConstructorInit public IConstructorInitDependency? Dependency { get; init; } } -[MultiContainer(typeof(IConstructorInit))] +[CreateFunction(typeof(IConstructorInit), "CreateDep")] internal partial class ConstructorInitContainer { } @@ -28,7 +28,7 @@ public class ConstructorsTests public void ResolveInitProperty() { using var container = new ConstructorInitContainer(); - var resolution = container.Create0(); + var resolution = container.CreateDep(); Assert.NotNull(resolution.Dependency); Assert.IsType(resolution.Dependency); } diff --git a/Test/DecoratorTests.cs b/Test/DecoratorTests.cs index 6aa724db..4763cb0b 100644 --- a/Test/DecoratorTests.cs +++ b/Test/DecoratorTests.cs @@ -25,7 +25,7 @@ public DecoratorNormal(IDecoratedNormal decoratedNormal) => public IDecoratedNormal Decorated { get; } } -[MultiContainer(typeof(IDecoratedNormal))] +[CreateFunction(typeof(IDecoratedNormal), "CreateDep")] internal partial class DecoratorNormalContainer { @@ -37,7 +37,7 @@ public partial class DecoratorTests public void Normal() { using var container = new DecoratorNormalContainer(); - var decorated = container.Create0(); + var decorated = container.CreateDep(); Assert.NotEqual(decorated, decorated.Decorated); Assert.IsType(decorated); Assert.IsType(decorated.Decorated); @@ -62,7 +62,7 @@ public DecoratorContainerInstance(IDecoratedContainerInstance decoratedContainer public IDecoratedContainerInstance Decorated { get; } } -[MultiContainer(typeof(IDecoratedContainerInstance))] +[CreateFunction(typeof(IDecoratedContainerInstance), "CreateDep")] internal partial class DecoratorContainerInstanceContainer { @@ -74,12 +74,12 @@ public partial class DecoratorTests public void ContainerInstance() { using var container = new DecoratorContainerInstanceContainer(); - var decorated = container.Create0(); + var decorated = container.CreateDep(); Assert.NotEqual(decorated, decorated.Decorated); Assert.IsType(decorated); Assert.IsType(decorated.Decorated); - var decoratedNextReference = container.Create0(); + var decoratedNextReference = container.CreateDep(); Assert.Equal(decorated, decoratedNextReference); Assert.Equal(decorated.Decorated, decoratedNextReference.Decorated); } @@ -118,7 +118,7 @@ public DecoratorScopeRoot(IDecoratedScopeRoot decorated, IDecoratedScopeRootDepe public IDecoratedScopeRoot Decorated { get; } } -[MultiContainer(typeof(IDecoratedScopeRoot))] +[CreateFunction(typeof(IDecoratedScopeRoot), "CreateDep")] internal partial class DecoratorScopeRootContainer { @@ -130,14 +130,14 @@ public partial class DecoratorTests public void ScopeRoot() { using var container = new DecoratorScopeRootContainer(); - var decorated = container.Create0(); + var decorated = container.CreateDep(); Assert.NotEqual(decorated, decorated.Decorated); Assert.Equal(decorated.Dependency, decorated.Decorated.Dependency); Assert.IsType(decorated); Assert.IsType(decorated.Decorated); // There is yet no way to check scopes externally - var next = container.Create0(); + var next = container.CreateDep(); Assert.NotEqual(decorated, next); Assert.NotEqual(decorated.Dependency, next.Dependency); } @@ -169,7 +169,7 @@ public DecoratorMultiB(IDecoratedMulti decorated) => public IDecoratedMulti Decorated { get; } } -[MultiContainer(typeof(IDecoratedMulti))] +[CreateFunction(typeof(IDecoratedMulti), "CreateDep")] internal partial class DecoratorMultiContainer { @@ -181,7 +181,7 @@ public partial class DecoratorTests public void Multi() { using var container = new DecoratorMultiContainer(); - var decorated = container.Create0(); + var decorated = container.CreateDep(); var decoratedB = decorated; var decoratedA = decorated.Decorated; var decoratedBasis = decoratedA.Decorated; @@ -217,7 +217,7 @@ public DecoratorList(IDecoratedList decorated) => public IDecoratedList Decorated { get; } } -[MultiContainer(typeof(IReadOnlyList))] +[CreateFunction(typeof(IReadOnlyList), "CreateDep")] internal partial class DecoratorListContainer { @@ -229,7 +229,7 @@ public partial class DecoratorTests public void List() { using var container = new DecoratorListContainer(); - var decorated = container.Create0(); + var decorated = container.CreateDep(); var decoratedOfA = decorated[0]; var decoratedOfB = decorated[1]; var decoratedBasisA = decoratedOfA.Decorated; diff --git a/Test/FactoryTests.cs b/Test/FactoryTests.cs index 4739d212..795e8b23 100644 --- a/Test/FactoryTests.cs +++ b/Test/FactoryTests.cs @@ -23,7 +23,9 @@ internal FactoryContainerScope(string yeah) } } -[MultiContainer(typeof(FileInfo), typeof(FactoryContainerTransientScope), typeof(FactoryContainerScope))] +[CreateFunction(typeof(FileInfo), "CreateFileInfo")] +[CreateFunction(typeof(FactoryContainerTransientScope), "CreateFactoryContainerTransientScope")] +[CreateFunction(typeof(FactoryContainerScope), "CreateFactoryContainerScope")] internal partial class FactoryContainer { private string DIE_Path { get; } @@ -50,7 +52,7 @@ public void ResolveExternalType() { var check = @"C:\HelloWorld.txt"; using var container = new FactoryContainer(check); - var fileInfo = container.Create0(); + var fileInfo = container.CreateFileInfo(); Assert.Equal(check, fileInfo.FullName); } @@ -59,7 +61,7 @@ public void ResolveFromFactoryInTransientScope() { var check = @"C:\HelloWorld.txt"; using var container = new FactoryContainer(check); - var transientScope = container.Create1(); + var transientScope = container.CreateFactoryContainerTransientScope(); Assert.Equal(69, transientScope.Number); } @@ -68,7 +70,7 @@ public void ResolveFromFactoryInScope() { var check = @"C:\HelloWorld.txt"; using var container = new FactoryContainer(check); - var scope = container.Create2(); + var scope = container.CreateFactoryContainerScope(); Assert.Equal("Yeah", scope.Yeah); } } \ No newline at end of file diff --git a/Test/Func/Vanilla.cs b/Test/Func/Vanilla.cs index 4a3024f6..931a1a3a 100644 --- a/Test/Func/Vanilla.cs +++ b/Test/Func/Vanilla.cs @@ -7,7 +7,7 @@ namespace MrMeeseeks.DIE.Test.Func.Vanilla; internal class Dependency{} -[MultiContainer(typeof(Func, Dependency>))] +[CreateFunction(typeof(Func, Dependency>), "CreateDep")] internal partial class Container { } @@ -18,6 +18,6 @@ public class Tests public void Test() { using var container = new Container(); - var _ = container.Create0()(DateTime.Now, new List()); + var _ = container.CreateDep()(DateTime.Now, new List()); } } diff --git a/Test/ImplementationAggregationTests.cs b/Test/ImplementationAggregationTests.cs index 18a5a8e0..2a2b4a4b 100644 --- a/Test/ImplementationAggregationTests.cs +++ b/Test/ImplementationAggregationTests.cs @@ -7,7 +7,7 @@ namespace MrMeeseeks.DIE.Test; -[MultiContainer(typeof(Func))] +[CreateFunction(typeof(Func), "CreateDep")] internal partial class ImplementationAggregationContainer { @@ -20,7 +20,7 @@ public void ResolveExternalType() { using var container = new ImplementationAggregationContainer(); var path = @"C:\HelloWorld.txt"; - var fileInfo = container.Create0()(path); + var fileInfo = container.CreateDep()(path); Assert.NotNull(fileInfo); Assert.IsType(fileInfo); Assert.Equal(path, fileInfo.FullName); diff --git a/Test/InstanceTests.cs b/Test/InstanceTests.cs index 51cef6da..48e660e4 100644 --- a/Test/InstanceTests.cs +++ b/Test/InstanceTests.cs @@ -17,8 +17,7 @@ public InstanceClass(string dependency) Dependency = dependency; } } - -[MultiContainer(typeof(IInstanceClass))] +[CreateFunction(typeof(IInstanceClass), "CreateDep")] internal partial class InstanceContainer { private readonly string DIE_Dependency; @@ -33,7 +32,7 @@ public void ResolveExternalType() { var check = "Hello, instance!"; using var container = new InstanceContainer(check); - var instanceClass = container.Create0(); + var instanceClass = container.CreateDep(); Assert.Equal(check, instanceClass.Dependency); } } \ No newline at end of file diff --git a/Test/Lazy/Vanilla.cs b/Test/Lazy/Vanilla.cs index b5bfb8c2..aae08c84 100644 --- a/Test/Lazy/Vanilla.cs +++ b/Test/Lazy/Vanilla.cs @@ -6,7 +6,7 @@ namespace MrMeeseeks.DIE.Test.Lazy.Vanilla; internal class Dependency{} -[MultiContainer(typeof(Lazy))] +[CreateFunction(typeof(Lazy), "CreateDep")] internal partial class Container { } @@ -17,7 +17,7 @@ public class Tests public void Test() { using var container = new Container(); - var lazy = container.Create0(); + var lazy = container.CreateDep(); var _ = lazy.Value; } } diff --git a/Test/PropertyTests.cs b/Test/PropertyTests.cs index 0c277770..94d55ffd 100644 --- a/Test/PropertyTests.cs +++ b/Test/PropertyTests.cs @@ -19,7 +19,7 @@ public PropertyClass(string dependency) } } -[MultiContainer(typeof(IPropertyClass))] +[CreateFunction(typeof(IPropertyClass), "CreateDep")] internal partial class PropertyContainer { private string DIE_Dependency { get; } @@ -34,7 +34,7 @@ public void ResolveExternalType() { var check = "Hello, Property!"; using var container = new PropertyContainer(check); - var propertyClass = container.Create0(); + var propertyClass = container.CreateDep(); Assert.Equal(check, propertyClass.Dependency); } } \ No newline at end of file diff --git a/Test/ScopeSpecificAttributesTestsWithDecorator.cs b/Test/ScopeSpecificAttributesTestsWithDecorator.cs index 64a402b5..6898ecfd 100644 --- a/Test/ScopeSpecificAttributesTestsWithDecorator.cs +++ b/Test/ScopeSpecificAttributesTestsWithDecorator.cs @@ -88,8 +88,11 @@ internal ScopeRoot(IInterface dep) } } - -[MultiContainer(typeof(IInterface), typeof(TransientScopeRoot), typeof(TransientScopeRootSpecific), typeof(ScopeRoot), typeof(ScopeRootSpecific))] +[CreateFunction(typeof(IInterface), "Create0")] +[CreateFunction(typeof(TransientScopeRoot), "Create1")] +[CreateFunction(typeof(TransientScopeRootSpecific), "Create2")] +[CreateFunction(typeof(ScopeRoot), "Create3")] +[CreateFunction(typeof(ScopeRootSpecific), "Create4")] [DecoratorSequenceChoice(typeof(IInterface), typeof(ContainerDecorator))] internal partial class Container { diff --git a/Test/ScopeSpecificAttributesTestsWithImplementationLists.cs b/Test/ScopeSpecificAttributesTestsWithImplementationLists.cs index 81db1486..956364eb 100644 --- a/Test/ScopeSpecificAttributesTestsWithImplementationLists.cs +++ b/Test/ScopeSpecificAttributesTestsWithImplementationLists.cs @@ -26,7 +26,9 @@ internal class Scope : IScopeRoot public IReadOnlyList Dependencies { get; } } -[MultiContainer(typeof(IReadOnlyList), typeof(TransientScope), typeof(Scope))] +[CreateFunction(typeof(IReadOnlyList), "Create0")] +[CreateFunction(typeof(TransientScope), "Create1")] +[CreateFunction(typeof(Scope), "Create2")] internal partial class Container { [FilterImplementationAggregation(typeof(DependencyContainer))] diff --git a/Test/ScopeSpecificAttributesTestsWithImplementations.cs b/Test/ScopeSpecificAttributesTestsWithImplementations.cs index 7e1b2069..7fae0684 100644 --- a/Test/ScopeSpecificAttributesTestsWithImplementations.cs +++ b/Test/ScopeSpecificAttributesTestsWithImplementations.cs @@ -25,7 +25,9 @@ internal class Scope : IScopeRoot public IDependency Dependency { get; } } -[MultiContainer(typeof(IDependency), typeof(TransientScope), typeof(Scope))] +[CreateFunction(typeof(IDependency), "Create0")] +[CreateFunction(typeof(TransientScope), "Create1")] +[CreateFunction(typeof(Scope), "Create2")] [FilterImplementationAggregation(typeof(DependencyScope))] [FilterImplementationAggregation(typeof(DependencyTransientScope))] internal partial class Container diff --git a/Test/SyncTypeInitializationTest.cs b/Test/SyncTypeInitializationTest.cs index d9c24dab..40a8f290 100644 --- a/Test/SyncTypeInitializationTest.cs +++ b/Test/SyncTypeInitializationTest.cs @@ -10,7 +10,7 @@ internal class Dependency : ITypeInitializer void ITypeInitializer.Initialize() => IsInitialized = true; } -[MultiContainer(typeof(Dependency))] +[CreateFunction(typeof(Dependency), "Create0")] internal partial class Container { } diff --git a/Test/TransientScopeInstanceTests.cs b/Test/TransientScopeInstanceTests.cs index b44a9ef1..89c60802 100644 --- a/Test/TransientScopeInstanceTests.cs +++ b/Test/TransientScopeInstanceTests.cs @@ -115,13 +115,11 @@ public void CleanUp() } } - -[MultiContainer( - typeof(ITransientScopeInstanceInner), - typeof(IScopeWithTransientScopeInstance), - typeof(IScopeWithTransientScopeInstanceAbove), - typeof(ITransientScopeWithTransientScopeInstance), - typeof(ITransientScopeWithScopes))] +[CreateFunction(typeof(ITransientScopeInstanceInner), "Create0")] +[CreateFunction(typeof(IScopeWithTransientScopeInstance), "Create1")] +[CreateFunction(typeof(IScopeWithTransientScopeInstanceAbove), "Create2")] +[CreateFunction(typeof(ITransientScopeWithTransientScopeInstance), "Create3")] +[CreateFunction(typeof(ITransientScopeWithScopes), "Create4")] internal partial class TransientScopeInstanceContainer { diff --git a/Test/ValueTupleTests.cs b/Test/ValueTupleTests.cs index 3317c65c..86591d4f 100644 --- a/Test/ValueTupleTests.cs +++ b/Test/ValueTupleTests.cs @@ -33,7 +33,7 @@ public ValueTupleBase( int _25) Dependency { get; } } -[MultiContainer(typeof(IValueTupleBase))] +[CreateFunction(typeof(IValueTupleBase), "CreateDep")] internal partial class ValueTupleContainer { private int _i; @@ -47,7 +47,7 @@ public partial class ValueTupleTests public void ResolveValueTuple() { using var container = new ValueTupleContainer(); - var valueTupleBase = container.Create0(); + var valueTupleBase = container.CreateDep(); Assert.Equal(25, valueTupleBase.Dependency._25); } } @@ -78,7 +78,7 @@ public NonSyntaxValueTupleBase( Dependency { get; } } -[MultiContainer(typeof(INonSyntaxValueTupleBase))] +[CreateFunction(typeof(INonSyntaxValueTupleBase), "CreateDep")] internal partial class NonSyntaxValueTupleContainer { private int _i; @@ -92,7 +92,7 @@ public partial class ValueTupleTests public void ResolveNonSyntaxValueTuple() { using var container = new NonSyntaxValueTupleContainer(); - var nonSyntaxValueTupleBase = container.Create0(); + var nonSyntaxValueTupleBase = container.CreateDep(); Assert.Equal(25, nonSyntaxValueTupleBase.Dependency.Item26); } } @@ -114,7 +114,7 @@ public ValueTuple Dependency { get; } } -[MultiContainer(typeof(INonSyntaxSingleItemValueTupleBase))] +[CreateFunction(typeof(INonSyntaxSingleItemValueTupleBase), "CreateDep")] internal partial class NonSyntaxSingleItemValueTupleContainer { private int _i; @@ -128,7 +128,7 @@ public partial class ValueTupleTests public void ResolveNonSyntaxSingleItemValueTuple() { using var container = new NonSyntaxSingleItemValueTupleContainer(); - var NonSyntaxSingleItemValueTupleBase = container.Create0(); + var NonSyntaxSingleItemValueTupleBase = container.CreateDep(); Assert.Equal(0, NonSyntaxSingleItemValueTupleBase.Dependency.Item1); } } @@ -150,7 +150,7 @@ public ValueTuple Dependency { get; } } -[MultiContainer(typeof(INonSyntaxDoubleItemValueTupleBase))] +[CreateFunction(typeof(INonSyntaxDoubleItemValueTupleBase), "CreateDep")] internal partial class NonSyntaxDoubleItemValueTupleContainer { private int _i; @@ -164,7 +164,7 @@ public partial class ValueTupleTests public void ResolveNonSyntaxDoubleItemValueTuple() { using var container = new NonSyntaxDoubleItemValueTupleContainer(); - var NonSyntaxDoubleItemValueTupleBase = container.Create0(); + var NonSyntaxDoubleItemValueTupleBase = container.CreateDep(); Assert.Equal(1, NonSyntaxDoubleItemValueTupleBase.Dependency.Item2); } } \ No newline at end of file From 9532ca9a9a3af18210aeba8944dbc7dab2368aa6 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Mon, 28 Mar 2022 21:59:40 +0200 Subject: [PATCH 052/162] Implementing Awaitables --- Main/CodeBuilding/RangeCodeBaseBuilder.cs | 46 +++- Main/ExecuteImpl.cs | 6 + .../ContainerResolutionBuilder.cs | 102 +++++--- .../FunctionResolutionBuilder.cs | 243 +++++++++++++----- Main/ResolutionBuilding/IResolutionBuilder.cs | 10 + .../RangeResolutionBaseBuilder.cs | 14 +- .../RangedFunctionResolutionBuilderManager.cs | 2 +- Main/ResolutionBuilding/ResolutionDtos.cs | 4 +- .../ScopeResolutionBuilder.cs | 58 ++--- ...ransientScopeInterfaceResolutionBuilder.cs | 43 +++- .../TransientScopeResolutionBuilder.cs | 58 ++--- Main/ResolutionTreeCreationErrorHarvester.cs | 2 +- Main/ResolutionTreeItem.cs | 72 +++++- Main/SourceGenerator.cs | 2 +- Sample/Context.cs | 9 +- Sample/Program.cs | 4 +- Test/Async/Awaited/FunctionCall.cs | 37 +++ .../TaskTypeInitializerTask.cs} | 2 +- .../Awaited/TaskTypeInitializerValueTask.cs | 33 +++ 19 files changed, 525 insertions(+), 222 deletions(-) create mode 100644 Main/ResolutionBuilding/IResolutionBuilder.cs create mode 100644 Test/Async/Awaited/FunctionCall.cs rename Test/Async/{AwaitedDependency/Dependency.cs => Awaited/TaskTypeInitializerTask.cs} (90%) create mode 100644 Test/Async/Awaited/TaskTypeInitializerValueTask.cs diff --git a/Main/CodeBuilding/RangeCodeBaseBuilder.cs b/Main/CodeBuilding/RangeCodeBaseBuilder.cs index 243661fa..3de3e0d3 100644 --- a/Main/CodeBuilding/RangeCodeBaseBuilder.cs +++ b/Main/CodeBuilding/RangeCodeBaseBuilder.cs @@ -1,3 +1,5 @@ +using MrMeeseeks.DIE.ResolutionBuilding; + namespace MrMeeseeks.DIE.CodeBuilding; internal interface IRangeCodeBaseBuilder @@ -94,7 +96,7 @@ private StringBuilder GenerateResolutionFunction( { var parameter = string.Join(",", resolution.Parameter.Select(r => $"{r.TypeFullName} {r.Reference}")); stringBuilder = stringBuilder - .AppendLine($"{rootResolutionFunction.AccessModifier} {(rootResolutionFunction.IsAsync ? "async " : "")}{resolution.TypeFullName} {resolution.Reference}({parameter})") + .AppendLine($"{rootResolutionFunction.AccessModifier} {(rootResolutionFunction.SynchronicityDecision is SynchronicityDecision.AsyncTask or SynchronicityDecision.AsyncValueTask ? "async " : "")}{resolution.TypeFullName} {resolution.Reference}({parameter})") .AppendLine($"{{") .AppendLine($"if (this.{rootResolutionFunction.DisposalHandling.DisposedPropertyReference}) throw new {WellKnownTypes.ObjectDisposedException}(\"\");"); @@ -110,7 +112,7 @@ private StringBuilder GenerateResolutionFunction( { var parameter = string.Join(",", resolution.Parameter.Select(r => $"{r.TypeFullName} {r.Reference}")); stringBuilder = stringBuilder - .AppendLine($"{(localFunctionResolution.IsAsync ? "async " : "")}{resolution.TypeFullName} {resolution.Reference}({parameter})") + .AppendLine($"{(localFunctionResolution.SynchronicityDecision is SynchronicityDecision.AsyncTask or SynchronicityDecision.AsyncValueTask ? "async " : "")}{resolution.TypeFullName} {resolution.Reference}({parameter})") .AppendLine($"{{") .AppendLine($"if (this.{localFunctionResolution.DisposalHandling.DisposedPropertyReference}) throw new {WellKnownTypes.ObjectDisposedException}(\"\");"); @@ -143,12 +145,25 @@ private static StringBuilder GenerateFields( switch (resolution) { case LazyResolution(var reference, var typeFullName, _): - stringBuilder = stringBuilder - .AppendLine($"{typeFullName} {reference};"); + stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); + break; + case FunctionCallResolution(var reference, _, _, _, _, _) functionCallResolution: + stringBuilder = stringBuilder.AppendLine($"{functionCallResolution.SelectedTypeFullName} {reference};"); break; case DeferringResolvable { Resolvable: {} resolvable}: stringBuilder = GenerateFields(stringBuilder, resolvable); break; + case NewReferenceResolvable(var reference, var resolvable): + stringBuilder = GenerateFields(stringBuilder, resolvable); + stringBuilder = stringBuilder + .AppendLine($"{resolvable.TypeFullName} {reference};"); + break; + case MultiTaskResolution { SelectedResolvable: {} resolvable}: + stringBuilder = GenerateFields(stringBuilder, resolvable); + break; + case MultiSynchronicityFunctionCallResolution { SelectedFunctionCall: {} selectedFunctionCall}: + stringBuilder = GenerateFields(stringBuilder, selectedFunctionCall); + break; case ValueTaskFromWrappedTaskResolution(var resolvable, var reference, var fullName): stringBuilder = GenerateFields(stringBuilder, resolvable); stringBuilder = stringBuilder @@ -255,6 +270,17 @@ private StringBuilder GenerateResolutions( case DeferringResolvable { Resolvable: {} resolvable}: stringBuilder = GenerateResolutions(stringBuilder, resolvable); break; + case MultiTaskResolution { SelectedResolvable: {} resolvable}: + stringBuilder = GenerateResolutions(stringBuilder, resolvable); + break; + case NewReferenceResolvable(var reference, var resolvable): + stringBuilder = GenerateResolutions(stringBuilder, resolvable); + stringBuilder = stringBuilder + .AppendLine($"{reference} = ({resolvable.TypeFullName}) {resolvable.Reference};"); + break; + case MultiSynchronicityFunctionCallResolution { SelectedFunctionCall: {} selectedFunctionCall}: + stringBuilder = GenerateResolutions(stringBuilder, selectedFunctionCall); + break; case LazyResolution(var reference, var typeFullName, var methodGroup): string owner = ""; if (methodGroup.OwnerReference is { } explicitOwner) @@ -262,12 +288,16 @@ private StringBuilder GenerateResolutions( stringBuilder = stringBuilder .AppendLine($"{reference} = new {typeFullName}({owner}{methodGroup.Reference});"); break; - case FunctionCallResolution(var reference, var typeFullName, var functionReference, var functionOwner, var parameters): + case FunctionCallResolution(var reference, _, _, var functionReference, var functionOwner, var parameters) functionCallResolution: string owner2 = ""; if (functionOwner is { } explicitOwner2) owner2 = $"{explicitOwner2}."; - stringBuilder = stringBuilder - .AppendLine($"{reference} = ({typeFullName}){owner2}{functionReference}({string.Join(", ", parameters.Select(p => $"{p.Name}: {p.Reference}"))});"); + if (functionCallResolution.Await) + stringBuilder = stringBuilder + .AppendLine($"{reference} = ({functionCallResolution.SelectedTypeFullName})(await {owner2}{functionReference}({string.Join(", ", parameters.Select(p => $"{p.Name}: {p.Reference}"))}));"); + else + stringBuilder = stringBuilder + .AppendLine($"{reference} = ({functionCallResolution.SelectedTypeFullName}){owner2}{functionReference}({string.Join(", ", parameters.Select(p => $"{p.Name}: {p.Reference}"))});"); break; case ValueTaskFromWrappedTaskResolution(var resolvable, var reference, var fullName): stringBuilder = GenerateResolutions(stringBuilder, resolvable); @@ -444,7 +474,7 @@ private StringBuilder GenerateRangedInstanceFunction(StringBuilder stringBuilder var parameters = string.Join(", ", overload.Parameter.Select(p => $"{p.TypeFullName} {p.Reference}")); stringBuilder = stringBuilder.AppendLine( - $"public {(overload.IsAsync ? "async " : "")}{overload.TypeFullName} {overload.Reference}({parameters})") + $"public {(overload.SynchronicityDecision is SynchronicityDecision.AsyncTask or SynchronicityDecision.AsyncValueTask ? "async " : "")}{overload.TypeFullName} {overload.Reference}({parameters})") .AppendLine($"{{") .AppendLine($"this.{rangedInstanceFunctionGroupResolution.LockReference}.Wait();") .AppendLine($"try") diff --git a/Main/ExecuteImpl.cs b/Main/ExecuteImpl.cs index a203362e..b21cca8d 100644 --- a/Main/ExecuteImpl.cs +++ b/Main/ExecuteImpl.cs @@ -64,6 +64,12 @@ public void Execute() { var containerResolutionBuilder = _containerResolutionBuilderFactory(containerInfo); containerResolutionBuilder.AddCreateResolveFunctions(containerInfo.CreateFunctionData); + + while (containerResolutionBuilder.HasWorkToDo) + { + containerResolutionBuilder.DoWork(); + } + var containerResolution = containerResolutionBuilder.Build(); var errorTreeItems = _resolutionTreeCreationErrorHarvester.Harvest(containerResolution); if (errorTreeItems.Any()) diff --git a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs index a9d66a34..958bfd8f 100644 --- a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs @@ -1,17 +1,14 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration; namespace MrMeeseeks.DIE.ResolutionBuilding; -internal interface IContainerResolutionBuilder : IRangeResolutionBaseBuilder +internal interface IContainerResolutionBuilder : IRangeResolutionBaseBuilder, IResolutionBuilder { void AddCreateResolveFunctions(IReadOnlyList<(INamedTypeSymbol, string)> createFunctionData); - FunctionCallResolution CreateContainerInstanceReferenceResolution( + MultiSynchronicityFunctionCallResolution CreateContainerInstanceReferenceResolution( ForConstructorParameter parameter, string containerReference); - - ContainerResolution Build(); } internal class ContainerResolutionBuilder : RangeResolutionBaseBuilder, IContainerResolutionBuilder, ITransientScopeImplementationResolutionBuilder @@ -62,17 +59,17 @@ public void AddCreateResolveFunctions(IReadOnlyList<(INamedTypeSymbol, string)> _rootResolutions.Add((_createFunctionResolutionBuilderFactory(this, typeSymbol), methodNamePrefix)); } - public FunctionCallResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter, string containerReference) => + public MultiSynchronicityFunctionCallResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter, string containerReference) => CreateRangedInstanceReferenceResolution( parameter, "Container", null, containerReference); - public override FunctionCallResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter) => + public override MultiSynchronicityFunctionCallResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter) => CreateContainerInstanceReferenceResolution(parameter, "this"); - public override FunctionCallResolution CreateTransientScopeInstanceReferenceResolution(ForConstructorParameter parameter) => + public override MultiSynchronicityFunctionCallResolution CreateTransientScopeInstanceReferenceResolution(ForConstructorParameter parameter) => _transientScopeInterfaceResolutionBuilder.CreateTransientScopeInstanceReferenceResolution(parameter, "this"); public override TransientScopeRootResolution CreateTransientScopeRootResolution(IScopeRootParameter parameter, INamedTypeSymbol rootType, @@ -101,6 +98,25 @@ public override ScopeRootResolution CreateScopeRootResolution( disposableCollectionResolution, currentParameters); + public bool HasWorkToDo => + _rootResolutions.Any(r => r.CreateFunction.HasWorkToDo) + || RangedInstanceReferenceResolutions.Values.Any(r => r.HasWorkToDo) + || _scopeManager.HasWorkToDo; + + public void DoWork() + { + while (HasWorkToDo) + { + foreach ((IContainerCreateFunctionResolutionBuilder createFunction, _) in _rootResolutions.Where(r => r.CreateFunction.HasWorkToDo)) + { + createFunction.DoWork(); + } + + DoRangedInstancesWork(); + _scopeManager.DoWork(); + } + } + public ContainerResolution Build() { var rootFunctions = new List(); @@ -115,7 +131,7 @@ public ContainerResolution Build() privateFunctionResolution.Parameter, DisposalHandling, privateFunctionResolution.LocalFunctions, - privateFunctionResolution.IsAsync); + privateFunctionResolution.SynchronicityDecision); rootFunctions.Add(privateRootResolutionFunction); @@ -124,17 +140,21 @@ public ContainerResolution Build() createFunction.ActualReturnType, SymbolEqualityComparer.Default)) { + var call = createFunction.BuildFunctionCall( + Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>(), + "this"); + call.Sync.Await = false; + call.AsyncTask.Await = false; + call.AsyncValueTask.Await = false; var publicSyncResolutionFunction = new RootResolutionFunction( methodNamePrefix, privateRootResolutionFunction.TypeFullName, "public", - createFunction.BuildFunctionCall( - Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>(), - "this"), + call, privateRootResolutionFunction.Parameter, DisposalHandling, Array.Empty(), - false); + SynchronicityDecision.Sync); rootFunctions.Add(publicSyncResolutionFunction); @@ -143,20 +163,24 @@ public ContainerResolution Build() .Construct(createFunction.OriginalReturnType) .FullName(); var wrappedTaskReference = RootReferenceGenerator.Generate(_wellKnownTypes.Task); + var taskCall = createFunction.BuildFunctionCall( + Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>(), + "this"); + taskCall.Sync.Await = false; + taskCall.AsyncTask.Await = false; + taskCall.AsyncValueTask.Await = false; var publicTaskResolutionFunction = new RootResolutionFunction( $"{methodNamePrefix}Async", boundTaskTypeFullName, "public", new TaskFromSyncResolution( - createFunction.BuildFunctionCall( - Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>(), - "this"), + taskCall, wrappedTaskReference, boundTaskTypeFullName), privateRootResolutionFunction.Parameter, DisposalHandling, Array.Empty(), - false); + SynchronicityDecision.Sync); rootFunctions.Add(publicTaskResolutionFunction); @@ -165,20 +189,24 @@ public ContainerResolution Build() .Construct(createFunction.OriginalReturnType) .FullName(); var wrappedValueTaskReference = RootReferenceGenerator.Generate(_wellKnownTypes.Task); + var valueTaskCall = createFunction.BuildFunctionCall( + Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>(), + "this"); + valueTaskCall.Sync.Await = false; + valueTaskCall.AsyncTask.Await = false; + valueTaskCall.AsyncValueTask.Await = false; var publicValueTaskResolutionFunction = new RootResolutionFunction( $"{methodNamePrefix}ValueAsync", boundValueTaskTypeFullName, "public", new ValueTaskFromSyncResolution( - createFunction.BuildFunctionCall( - Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>(), - "this"), + valueTaskCall, wrappedValueTaskReference, boundValueTaskTypeFullName), privateRootResolutionFunction.Parameter, DisposalHandling, Array.Empty(), - false); + SynchronicityDecision.Sync); rootFunctions.Add(publicValueTaskResolutionFunction); } @@ -186,18 +214,21 @@ public ContainerResolution Build() && actual.Equals(_wellKnownTypes.Task1.Construct(createFunction.OriginalReturnType), SymbolEqualityComparer.Default)) { - var wrappedTaskReference = RootReferenceGenerator.Generate(_wellKnownTypes.Task); + var call = createFunction.BuildFunctionCall( + Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>(), + "this"); + call.Sync.Await = false; + call.AsyncTask.Await = false; + call.AsyncValueTask.Await = false; var publicTaskResolutionFunction = new RootResolutionFunction( $"{methodNamePrefix}Async", actual.FullName(), "public", - createFunction.BuildFunctionCall( - Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>(), - "this"), + call, privateRootResolutionFunction.Parameter, DisposalHandling, Array.Empty(), - false); + SynchronicityDecision.Sync); rootFunctions.Add(publicTaskResolutionFunction); @@ -206,31 +237,28 @@ public ContainerResolution Build() .Construct(createFunction.OriginalReturnType) .FullName(); var wrappedValueTaskReference = RootReferenceGenerator.Generate(_wellKnownTypes.Task); + var valueCall = createFunction.BuildFunctionCall( + Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>(), + "this"); + valueCall.Sync.Await = false; + valueCall.AsyncTask.Await = false; + valueCall.AsyncValueTask.Await = false; var publicValueTaskResolutionFunction = new RootResolutionFunction( $"{methodNamePrefix}ValueAsync", boundValueTaskTypeFullName, "public", new ValueTaskFromWrappedTaskResolution( - createFunction.BuildFunctionCall( - Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>(), - "this"), + valueCall, wrappedValueTaskReference, boundValueTaskTypeFullName), privateRootResolutionFunction.Parameter, DisposalHandling, Array.Empty(), - false); + SynchronicityDecision.Sync); rootFunctions.Add(publicValueTaskResolutionFunction); } } - - while (RangedInstanceReferenceResolutions.Values.Any(r => r.HasWorkToDo) - || _scopeManager.HasWorkToDo) - { - DoRangedInstancesWork(); - _scopeManager.DoWork(); - } var (transientScopeResolutions, scopeResolutions) = _scopeManager.Build(); diff --git a/Main/ResolutionBuilding/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/FunctionResolutionBuilder.cs index c96039ee..22d4866e 100644 --- a/Main/ResolutionBuilding/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/FunctionResolutionBuilder.cs @@ -6,21 +6,20 @@ internal enum SynchronicityDecision { Undecided, Sync, - Async + AsyncTask, + AsyncValueTask } -internal interface IFunctionResolutionBuilder +internal interface IFunctionResolutionBuilder : IResolutionBuilder { INamedTypeSymbol OriginalReturnType { get; } INamedTypeSymbol? ActualReturnType { get; } - FunctionCallResolution BuildFunctionCall( + MultiSynchronicityFunctionCallResolution BuildFunctionCall( IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters, string? ownerReference); MethodGroupResolution BuildMethodGroup(); - - FunctionResolution Build(); } internal interface ILocalFunctionResolutionBuilder : IFunctionResolutionBuilder @@ -55,13 +54,15 @@ public LocalFunctionResolutionBuilder( protected override string Name { get; } + protected override Resolvable CreateResolvable() => SwitchType(new SwitchTypeParameter(_returnType, _parameters)).Item1; + public override FunctionResolution Build() { AdjustForSynchronicity(); return new( Name, TypeFullName, - SwitchType(new SwitchTypeParameter(_returnType, _parameters)).Item1, + Resolvable.Value, _parameters.Select(t => t.Resolution).ToList(), _rangeResolutionBaseBuilder.DisposalHandling, LocalFunctions @@ -73,9 +74,9 @@ public override FunctionResolution Build() f.Parameter, f.DisposalHandling, f.LocalFunctions, - f.IsAsync)) + f.SynchronicityDecision)) .ToList(), - IsAsync); + SynchronicityDecision.Value); } } @@ -108,16 +109,17 @@ public ContainerCreateFunctionResolutionBuilder( protected override string Name { get; } + protected override Resolvable CreateResolvable() => SwitchType(new SwitchTypeParameter( + _returnType, + Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>())).Item1; + public override FunctionResolution Build() { - var resolvable = SwitchType(new SwitchTypeParameter( - _returnType, - Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>())).Item1; AdjustForSynchronicity(); return new( Name, TypeFullName, - resolvable, + Resolvable.Value, Array.Empty(), _rangeResolutionBaseBuilder.DisposalHandling, LocalFunctions @@ -129,9 +131,9 @@ public override FunctionResolution Build() f.Parameter, f.DisposalHandling, f.LocalFunctions, - f.IsAsync)) + f.SynchronicityDecision)) .ToList(), - IsAsync); + SynchronicityDecision.Value); } } @@ -164,21 +166,22 @@ public ScopeRootCreateFunctionResolutionBuilder( protected override string Name { get; } + protected override Resolvable CreateResolvable() => _scopeRootParameter switch + { + CreateInterfaceParameter createInterfaceParameter => CreateInterface(createInterfaceParameter).Item1, + SwitchImplementationParameter switchImplementationParameter => SwitchImplementation(switchImplementationParameter).Item1, + SwitchInterfaceAfterScopeRootParameter switchInterfaceAfterScopeRootParameter => SwitchInterfaceAfterScopeRoot(switchInterfaceAfterScopeRootParameter).Item1, + _ => throw new ArgumentOutOfRangeException(nameof(_scopeRootParameter)) + }; + public override FunctionResolution Build() { AdjustForSynchronicity(); - var resolvable = _scopeRootParameter switch - { - CreateInterfaceParameter createInterfaceParameter => CreateInterface(createInterfaceParameter).Item1, - SwitchImplementationParameter switchImplementationParameter => SwitchImplementation(switchImplementationParameter).Item1, - SwitchInterfaceAfterScopeRootParameter switchInterfaceAfterScopeRootParameter => SwitchInterfaceAfterScopeRoot(switchInterfaceAfterScopeRootParameter).Item1, - _ => throw new ArgumentOutOfRangeException(nameof(_scopeRootParameter)) - }; return new( Name, TypeFullName, - resolvable, + Resolvable.Value, Parameters, _rangeResolutionBaseBuilder.DisposalHandling, LocalFunctions @@ -190,9 +193,9 @@ public override FunctionResolution Build() f.Parameter, f.DisposalHandling, f.LocalFunctions, - f.IsAsync)) + f.SynchronicityDecision)) .ToList(), - IsAsync); + SynchronicityDecision.Value); } } @@ -226,15 +229,16 @@ public RangedFunctionResolutionBuilder( protected override string Name { get; } + protected override Resolvable CreateResolvable() => CreateConstructorResolution(_forConstructorParameter).Item1; + public override FunctionResolution Build() { AdjustForSynchronicity(); - var resolvable = CreateConstructorResolution(_forConstructorParameter).Item1; return new( Name, TypeFullName, - resolvable, + Resolvable.Value, _forConstructorParameter.CurrentFuncParameters.Select(t => t.Resolution).ToList(), _rangeResolutionBaseBuilder.DisposalHandling, LocalFunctions @@ -246,9 +250,9 @@ public override FunctionResolution Build() f.Parameter, f.DisposalHandling, f.LocalFunctions, - f.IsAsync)) + f.SynchronicityDecision)) .ToList(), - IsAsync); + SynchronicityDecision.Value); } } @@ -266,14 +270,15 @@ internal abstract class FunctionResolutionBuilder : IFunctionResolutionBuilder protected readonly IList LocalFunctions = new List(); - protected readonly IList PotentialAwaits = new List(); + protected readonly ISet PotentialAwaits = new HashSet(); protected abstract string Name { get; } protected string TypeFullName => ActualReturnType?.FullName() ?? OriginalReturnType.FullName(); + + public Lazy SynchronicityDecision { get; } + protected Lazy Resolvable { get; } protected IReadOnlyList Parameters { get; } - - protected bool IsAsync => PotentialAwaits.Any(pa => pa.Await); public INamedTypeSymbol OriginalReturnType { get; } public INamedTypeSymbol? ActualReturnType { get; protected set; } @@ -302,9 +307,15 @@ internal FunctionResolutionBuilder( Parameters = currentParameters .Select(p => new ParameterResolution(RootReferenceGenerator.Generate(p.Type), TypeFullName)) .ToList(); + + SynchronicityDecision = new(() => + PotentialAwaits.Any(pa => pa.Await) + ? ResolutionBuilding.SynchronicityDecision.AsyncTask + : ResolutionBuilding.SynchronicityDecision.Sync); + Resolvable = new(CreateResolvable); } - protected (Resolvable, ConstructorResolution?) SwitchType(SwitchTypeParameter parameter) + protected (Resolvable, ITaskConsumableResolution?) SwitchType(SwitchTypeParameter parameter) { var (type, currentFuncParameters) = parameter; if (currentFuncParameters.FirstOrDefault(t => SymbolEqualityComparer.Default.Equals(t.Type.OriginalDefinition, type.OriginalDefinition)) is { Type: not null, Resolution: not null } funcParameter) @@ -542,7 +553,7 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup null); } - private (Resolvable, ConstructorResolution?) SwitchTask(SwitchTaskParameter parameter) + private (Resolvable, ITaskConsumableResolution?) SwitchTask(SwitchTaskParameter parameter) { var resolution = parameter.InnerResolution; var boundTaskTypeFullName = _wellKnownTypes @@ -551,7 +562,7 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup .FullName() .Replace("<>", $"<{resolution.Item1.TypeFullName}>"); var wrappedTaskReference = RootReferenceGenerator.Generate(_wellKnownTypes.Task); - if (resolution.Item2 is { } constructorResolution) + if (resolution.Item2 is ConstructorResolution constructorResolution) { if (constructorResolution.Initialization is TaskBaseTypeInitializationResolution taskBaseResolution) taskBaseResolution.Await = false; @@ -571,10 +582,29 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup }; return (taskResolution, resolution.Item2); } + else if (resolution.Item2 is MultiSynchronicityFunctionCallResolution multiSynchronicityFunctionCallResolution) + { + var taskReference = RootReferenceGenerator.Generate("task"); + var taskFullName = multiSynchronicityFunctionCallResolution.AsyncTask.TypeFullName; + multiSynchronicityFunctionCallResolution.Sync.Await = false; + multiSynchronicityFunctionCallResolution.AsyncTask.Await = false; + multiSynchronicityFunctionCallResolution.AsyncValueTask.Await = false; + return (new MultiTaskResolution( + new TaskFromSyncResolution( + multiSynchronicityFunctionCallResolution.Sync, + taskReference, + taskFullName), + new NewReferenceResolvable(taskReference, multiSynchronicityFunctionCallResolution.AsyncTask), + new TaskFromWrappedValueTaskResolution( + multiSynchronicityFunctionCallResolution.AsyncValueTask, + taskReference, + taskFullName), + multiSynchronicityFunctionCallResolution.LazySynchronicityDecision), null); + } return (new TaskFromSyncResolution(resolution.Item1, wrappedTaskReference, boundTaskTypeFullName), resolution.Item2); } - private (Resolvable, ConstructorResolution?) SwitchValueTask(SwitchValueTaskParameter parameter) + private (Resolvable, ITaskConsumableResolution?) SwitchValueTask(SwitchValueTaskParameter parameter) { var resolution = parameter.InnerResolution; var boundValueTaskTypeFullName = _wellKnownTypes @@ -583,7 +613,7 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup .FullName() .Replace("<>", $"<{resolution.Item1.TypeFullName}>"); var wrappedValueTaskReference = RootReferenceGenerator.Generate(_wellKnownTypes.ValueTask); - if (resolution.Item2 is { } constructorResolution) + if (resolution.Item2 is ConstructorResolution constructorResolution) { if (constructorResolution.Initialization is TaskBaseTypeInitializationResolution taskBaseResolution) taskBaseResolution.Await = false; @@ -603,10 +633,29 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup }; return (taskResolution, resolution.Item2); } + else if (resolution.Item2 is MultiSynchronicityFunctionCallResolution multiSynchronicityFunctionCallResolution) + { + var valueTaskReference = RootReferenceGenerator.Generate("valueTask"); + var valueTaskFullName = multiSynchronicityFunctionCallResolution.AsyncValueTask.TypeFullName; + multiSynchronicityFunctionCallResolution.Sync.Await = false; + multiSynchronicityFunctionCallResolution.AsyncTask.Await = false; + multiSynchronicityFunctionCallResolution.AsyncValueTask.Await = false; + return (new MultiTaskResolution( + new ValueTaskFromSyncResolution( + multiSynchronicityFunctionCallResolution.Sync, + valueTaskReference, + valueTaskFullName), + new ValueTaskFromWrappedTaskResolution( + multiSynchronicityFunctionCallResolution.AsyncTask, + valueTaskReference, + valueTaskFullName), + new NewReferenceResolvable(valueTaskReference, multiSynchronicityFunctionCallResolution.AsyncValueTask), + multiSynchronicityFunctionCallResolution.LazySynchronicityDecision), null); + } return (new TaskFromSyncResolution(resolution.Item1, wrappedValueTaskReference, boundValueTaskTypeFullName), resolution.Item2); } - private (Resolvable, ConstructorResolution?) SwitchInterface(SwitchInterfaceParameter parameter) + private (Resolvable, ITaskConsumableResolution?) SwitchInterface(SwitchInterfaceParameter parameter) { var (typeSymbol, currentParameters) = parameter; var interfaceType = (INamedTypeSymbol) typeSymbol; @@ -619,23 +668,28 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup implementations, currentParameters); - return shouldBeScopeRoot switch + var ret = shouldBeScopeRoot switch { ScopeLevel.TransientScope => (_rangeResolutionBaseBuilder.CreateTransientScopeRootResolution( nextParameter, interfaceType, _disposableCollectionResolution, - currentParameters), null), // todo async handling + currentParameters), null), ScopeLevel.Scope => (_rangeResolutionBaseBuilder.CreateScopeRootResolution( nextParameter, interfaceType, _disposableCollectionResolution, - currentParameters), null), // todo async handling + currentParameters), null), _ => SwitchInterfaceAfterScopeRoot(nextParameter) }; + + if (ret.Item1 is IAwaitableResolution awaitableResolution) + PotentialAwaits.Add(awaitableResolution); + + return ret; } - protected (Resolvable, ConstructorResolution?) SwitchInterfaceAfterScopeRoot( + protected (Resolvable, ITaskConsumableResolution?) SwitchInterfaceAfterScopeRoot( SwitchInterfaceAfterScopeRootParameter parameter) { var (interfaceType, implementations, currentParameters) = parameter; @@ -676,7 +730,7 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup currentParameters)); } - private (Resolvable, ConstructorResolution?) SwitchInterfaceForSpecificImplementation( + private (Resolvable, ITaskConsumableResolution?) SwitchInterfaceForSpecificImplementation( SwitchInterfaceForSpecificImplementationParameter parameter) { var (interfaceType, implementationType, currentParameters) = parameter; @@ -686,23 +740,28 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup implementationType, currentParameters); - return _checkTypeProperties.ShouldBeScopeRoot(implementationType) switch + (Resolvable, ITaskConsumableResolution?) ret = _checkTypeProperties.ShouldBeScopeRoot(implementationType) switch { ScopeLevel.TransientScope => (_rangeResolutionBaseBuilder.CreateTransientScopeRootResolution( nextParameter, interfaceType, _disposableCollectionResolution, - currentParameters), null), // todo async handling + currentParameters), null), ScopeLevel.Scope => (_rangeResolutionBaseBuilder.CreateScopeRootResolution( nextParameter, interfaceType, _disposableCollectionResolution, - currentParameters), null), // todo async handling + currentParameters), null), _ => CreateInterface(nextParameter) }; + + if (ret.Item1 is IAwaitableResolution awaitableResolution) + PotentialAwaits.Add(awaitableResolution); + + return ret; } - protected (InterfaceResolution, ConstructorResolution?) CreateInterface(CreateInterfaceParameter parameter) + protected (InterfaceResolution, ITaskConsumableResolution?) CreateInterface(CreateInterfaceParameter parameter) { var (interfaceType, implementationType, currentParameters) = parameter; var shouldBeDecorated = _checkTypeProperties.ShouldBeDecorated(interfaceType); @@ -748,7 +807,7 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup return (currentInterfaceResolution, currentInterfaceResolution.Dependency as ConstructorResolution); } - private (Resolvable, ConstructorResolution?) SwitchClass(SwitchClassParameter parameter) + private (Resolvable, ITaskConsumableResolution?) SwitchClass(SwitchClassParameter parameter) { var (typeSymbol, currentParameters) = parameter; var implementations = _checkTypeProperties @@ -770,23 +829,31 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup implementationType, currentParameters); - return _checkTypeProperties.ShouldBeScopeRoot(implementationType) switch + var ret = _checkTypeProperties.ShouldBeScopeRoot(implementationType) switch { ScopeLevel.TransientScope => (_rangeResolutionBaseBuilder.CreateTransientScopeRootResolution( nextParameter, implementationType, _disposableCollectionResolution, - currentParameters), null), // todo async handling + currentParameters), null), ScopeLevel.Scope => (_rangeResolutionBaseBuilder.CreateScopeRootResolution( nextParameter, implementationType, _disposableCollectionResolution, - currentParameters), null), // todo async handling + currentParameters), null), _ => SwitchImplementation(nextParameter) }; + + if (ret.Item1 is ScopeRootResolution { ScopeRootFunction: IAwaitableResolution awaitableResolution }) + PotentialAwaits.Add(awaitableResolution); + + if (ret.Item1 is TransientScopeRootResolution { ScopeRootFunction: IAwaitableResolution awaitableResolution0 }) + PotentialAwaits.Add(awaitableResolution0); + + return ret; } - protected (Resolvable, ConstructorResolution?) SwitchImplementation(SwitchImplementationParameter parameter) + protected (Resolvable, ITaskConsumableResolution?) SwitchImplementation(SwitchImplementationParameter parameter) { var (implementationType, currentParameters) = parameter; var scopeLevel = parameter switch @@ -810,16 +877,24 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup withDecoration.Decoration), _ => new ForConstructorParameter(implementationType, currentParameters) }; - return scopeLevel switch + + var ret = scopeLevel switch { - ScopeLevel.Container => (_rangeResolutionBaseBuilder.CreateContainerInstanceReferenceResolution(nextParameter), null), // todo async handling - ScopeLevel.TransientScope => (_rangeResolutionBaseBuilder.CreateTransientScopeInstanceReferenceResolution(nextParameter), null), // todo async handling - ScopeLevel.Scope => (_rangeResolutionBaseBuilder.CreateScopeInstanceReferenceResolution(nextParameter), null), // todo async handling + ScopeLevel.Container => (_rangeResolutionBaseBuilder.CreateContainerInstanceReferenceResolution(nextParameter), null), + ScopeLevel.TransientScope => (_rangeResolutionBaseBuilder.CreateTransientScopeInstanceReferenceResolution(nextParameter), null), + ScopeLevel.Scope => (_rangeResolutionBaseBuilder.CreateScopeInstanceReferenceResolution(nextParameter), null), _ => CreateConstructorResolution(nextParameter) }; + + if (ret.Item1 is IAwaitableResolution awaitableResolution) + { + PotentialAwaits.Add(awaitableResolution); + } + + return ret; } - protected (Resolvable, ConstructorResolution?) CreateConstructorResolution(ForConstructorParameter parameter) + protected (Resolvable, ITaskConsumableResolution?) CreateConstructorResolution(ForConstructorParameter parameter) { var (implementationType, currentParameters) = parameter; @@ -880,6 +955,7 @@ false when initializationMethod.ReturnType.Equals(_wellKnownTypes.ValueTask, Sym RootReferenceGenerator.Generate(_wellKnownTypes.ValueTask)), _ => typeInitializationResolution }; + if (typeInitializationResolution is IAwaitableResolution awaitableResolution) { PotentialAwaits.Add(awaitableResolution); @@ -993,12 +1069,10 @@ false when initializationMethod.ReturnType.Equals(_wellKnownTypes.ValueTask, Sym } } - protected void AdjustForSynchronicity() - { - ActualReturnType = IsAsync + protected void AdjustForSynchronicity() => + ActualReturnType = SynchronicityDecision.Value is ResolutionBuilding.SynchronicityDecision.AsyncTask or ResolutionBuilding.SynchronicityDecision.AsyncValueTask ? _wellKnownTypes.Task1.Construct(OriginalReturnType) : OriginalReturnType; - } private static DisposableCollectionResolution? ImplementsIDisposable( INamedTypeSymbol type, @@ -1009,15 +1083,50 @@ protected void AdjustForSynchronicity() ? disposableCollectionResolution : null; - public FunctionCallResolution BuildFunctionCall( - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters, string? ownerReference) => - new(RootReferenceGenerator.Generate("ret"), - TypeFullName, - Name, - ownerReference, - Parameters.Zip(currentParameters, (p, cp) => (p.Reference, cp.Resolution.Reference)).ToList()); + public MultiSynchronicityFunctionCallResolution BuildFunctionCall( + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters, string? ownerReference) + { + var returnReference = RootReferenceGenerator.Generate("ret"); + return new(new(returnReference, + OriginalReturnType.FullName(), + OriginalReturnType.FullName(), + Name, + ownerReference, + Parameters.Zip(currentParameters, (p, cp) => (p.Reference, cp.Resolution.Reference)).ToList()) + { Await = false }, + new(returnReference, + _wellKnownTypes.Task1.Construct(OriginalReturnType).FullName(), + OriginalReturnType.FullName(), + Name, + ownerReference, + Parameters.Zip(currentParameters, (p, cp) => (p.Reference, cp.Resolution.Reference)).ToList()), + new(returnReference, + _wellKnownTypes.ValueTask1.Construct(OriginalReturnType).FullName(), + OriginalReturnType.FullName(), + Name, + ownerReference, + Parameters.Zip(currentParameters, (p, cp) => (p.Reference, cp.Resolution.Reference)).ToList()), + SynchronicityDecision); + } public MethodGroupResolution BuildMethodGroup() => new (Name, TypeFullName, null); + public bool HasWorkToDo => !Resolvable.IsValueCreated + || LocalFunctions.Any(lf => lf.HasWorkToDo); + + protected abstract Resolvable CreateResolvable(); + + public void DoWork() + { + var _ = Resolvable.Value; + while (LocalFunctions.Any(lf => lf.HasWorkToDo)) + { + foreach (var localFunction in LocalFunctions) + { + localFunction.DoWork(); + } + } + } + public abstract FunctionResolution Build(); } \ No newline at end of file diff --git a/Main/ResolutionBuilding/IResolutionBuilder.cs b/Main/ResolutionBuilding/IResolutionBuilder.cs new file mode 100644 index 00000000..39f43029 --- /dev/null +++ b/Main/ResolutionBuilding/IResolutionBuilder.cs @@ -0,0 +1,10 @@ +namespace MrMeeseeks.DIE.ResolutionBuilding; + +public interface IResolutionBuilder +{ + bool HasWorkToDo { get; } + + void DoWork(); + + T Build(); +} \ No newline at end of file diff --git a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs index d145c932..65d34e39 100644 --- a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs +++ b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs @@ -9,13 +9,13 @@ internal interface IRangeResolutionBaseBuilder DisposableCollectionResolution DisposableCollectionResolution { get; } DisposalHandling DisposalHandling { get; } - FunctionCallResolution CreateContainerInstanceReferenceResolution( + MultiSynchronicityFunctionCallResolution CreateContainerInstanceReferenceResolution( ForConstructorParameter parameter); - FunctionCallResolution CreateTransientScopeInstanceReferenceResolution( + MultiSynchronicityFunctionCallResolution CreateTransientScopeInstanceReferenceResolution( ForConstructorParameter parameter); - FunctionCallResolution CreateScopeInstanceReferenceResolution( + MultiSynchronicityFunctionCallResolution CreateScopeInstanceReferenceResolution( ForConstructorParameter parameter); TransientScopeRootResolution CreateTransientScopeRootResolution( @@ -77,11 +77,11 @@ protected RangeResolutionBaseBuilder( RootReferenceGenerator.Generate("disposable")); } - public abstract FunctionCallResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter); + public abstract MultiSynchronicityFunctionCallResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter); - public abstract FunctionCallResolution CreateTransientScopeInstanceReferenceResolution(ForConstructorParameter parameter); + public abstract MultiSynchronicityFunctionCallResolution CreateTransientScopeInstanceReferenceResolution(ForConstructorParameter parameter); - public FunctionCallResolution CreateScopeInstanceReferenceResolution( + public MultiSynchronicityFunctionCallResolution CreateScopeInstanceReferenceResolution( ForConstructorParameter parameter) => CreateRangedInstanceReferenceResolution( parameter, @@ -101,7 +101,7 @@ public abstract ScopeRootResolution CreateScopeRootResolution( DisposableCollectionResolution disposableCollectionResolution, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters); - protected FunctionCallResolution CreateRangedInstanceReferenceResolution( + protected MultiSynchronicityFunctionCallResolution CreateRangedInstanceReferenceResolution( ForConstructorParameter parameter, string label, string? reference, diff --git a/Main/ResolutionBuilding/RangedFunctionResolutionBuilderManager.cs b/Main/ResolutionBuilding/RangedFunctionResolutionBuilderManager.cs index 7c25997c..cb9d545f 100644 --- a/Main/ResolutionBuilding/RangedFunctionResolutionBuilderManager.cs +++ b/Main/ResolutionBuilding/RangedFunctionResolutionBuilderManager.cs @@ -73,7 +73,7 @@ public void DoWork() functionResolution.Parameter, functionResolution.DisposalHandling, functionResolution.LocalFunctions, - false)); // todo async support + SynchronicityDecision.Sync)); // todo async support } } diff --git a/Main/ResolutionBuilding/ResolutionDtos.cs b/Main/ResolutionBuilding/ResolutionDtos.cs index a37acf4e..17929feb 100644 --- a/Main/ResolutionBuilding/ResolutionDtos.cs +++ b/Main/ResolutionBuilding/ResolutionDtos.cs @@ -154,9 +154,9 @@ internal record RangedInstanceResolutionsQueueItem( string Label, string Reference); -internal record SwitchTaskParameter((Resolvable, ConstructorResolution?) InnerResolution) : Parameter; +internal record SwitchTaskParameter((Resolvable, ITaskConsumableResolution?) InnerResolution) : Parameter; -internal record SwitchValueTaskParameter((Resolvable, ConstructorResolution?) InnerResolution) : Parameter; +internal record SwitchValueTaskParameter((Resolvable, ITaskConsumableResolution?) InnerResolution) : Parameter; internal enum TaskType { diff --git a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs index 812e8ff3..4779b0f3 100644 --- a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs @@ -2,10 +2,8 @@ namespace MrMeeseeks.DIE.ResolutionBuilding; -internal interface IScopeResolutionBuilder : IRangeResolutionBaseBuilder +internal interface IScopeResolutionBuilder : IRangeResolutionBaseBuilder, IResolutionBuilder { - bool HasWorkToDo { get; } - ScopeRootResolution AddCreateResolveFunction( IScopeRootParameter parameter, INamedTypeSymbol rootType, @@ -13,10 +11,6 @@ ScopeRootResolution AddCreateResolveFunction( string transientInstanceScopeReference, DisposableCollectionResolution disposableCollectionResolution, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters); - - void DoWork(); - - ScopeResolution Build(); } internal class ScopeResolutionBuilder : RangeResolutionBaseBuilder, IScopeResolutionBuilder @@ -25,15 +19,12 @@ internal class ScopeResolutionBuilder : RangeResolutionBaseBuilder, IScopeResolu private readonly ITransientScopeInterfaceResolutionBuilder _transientScopeInterfaceResolutionBuilder; private readonly IScopeManager _scopeManager; private readonly Func _scopeRootCreateFunctionResolutionBuilderFactory; - private readonly List _rootResolutions = new (); private readonly string _containerReference; private readonly string _containerParameterReference; private readonly string _transientScopeReference; private readonly string _transientScopeParameterReference; private readonly Dictionary _scopeRootFunctionResolutions = new (); - private readonly HashSet<(IScopeRootCreateFunctionResolutionBuilder, string)> _scopeRootFunctionQueuedOverloads = new (); - private readonly Queue _scopeRootFunctionResolutionsQueue = new(); internal ScopeResolutionBuilder( // parameter @@ -67,10 +58,10 @@ internal ScopeResolutionBuilder( _transientScopeParameterReference = RootReferenceGenerator.Generate("transientScope"); } - public override FunctionCallResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter) => + public override MultiSynchronicityFunctionCallResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter) => _containerResolutionBuilder.CreateContainerInstanceReferenceResolution(parameter, _containerReference); - public override FunctionCallResolution CreateTransientScopeInstanceReferenceResolution(ForConstructorParameter parameter) => + public override MultiSynchronicityFunctionCallResolution CreateTransientScopeInstanceReferenceResolution(ForConstructorParameter parameter) => _transientScopeInterfaceResolutionBuilder.CreateTransientScopeInstanceReferenceResolution(parameter, _transientScopeReference); public override TransientScopeRootResolution CreateTransientScopeRootResolution( @@ -102,7 +93,9 @@ public override ScopeRootResolution CreateScopeRootResolution( disposableCollectionResolution, currentParameters); - public bool HasWorkToDo => _scopeRootFunctionResolutionsQueue.Any() || RangedInstanceReferenceResolutions.Values.Any(r => r.HasWorkToDo); + public bool HasWorkToDo => + _scopeRootFunctionResolutions.Values.Any(f => f.HasWorkToDo) + || RangedInstanceReferenceResolutions.Values.Any(r => r.HasWorkToDo); public ScopeRootResolution AddCreateResolveFunction( IScopeRootParameter parameter, @@ -121,13 +114,6 @@ public ScopeRootResolution AddCreateResolveFunction( _scopeRootFunctionResolutions[key] = function; } - var listedParameterTypes = string.Join(",", currentParameters.Select(p => p.Item2.TypeFullName)); - if (!_scopeRootFunctionQueuedOverloads.Contains((function, listedParameterTypes))) - { - _scopeRootFunctionResolutionsQueue.Enqueue(function); - _scopeRootFunctionQueuedOverloads.Add((function, listedParameterTypes)); - } - var scopeRootReference = RootReferenceGenerator.Generate("scopeRoot"); return new ScopeRootResolution( @@ -143,29 +129,29 @@ public void DoWork() { while (HasWorkToDo) { - while (_scopeRootFunctionResolutionsQueue.Any()) + foreach (var functionResolutionBuilder in _scopeRootFunctionResolutions.Values.Where(f => f.HasWorkToDo)) { - var functionResolution = _scopeRootFunctionResolutionsQueue - .Dequeue() - .Build(); - - _rootResolutions.Add(new RootResolutionFunction( - functionResolution.Reference, - functionResolution.TypeFullName, - "internal", - functionResolution.Resolvable, - functionResolution.Parameter, - functionResolution.DisposalHandling, - functionResolution.LocalFunctions, - functionResolution.IsAsync)); + functionResolutionBuilder.DoWork(); } - + DoRangedInstancesWork(); } } public ScopeResolution Build() => - new(_rootResolutions, + new(_scopeRootFunctionResolutions + .Values + .Select(fr => fr.Build()) + .Select(f => new RootResolutionFunction( + f.Reference, + f.TypeFullName, + "internal", + f.Resolvable, + f.Parameter, + f.DisposalHandling, + f.LocalFunctions, + f.SynchronicityDecision)) + .ToList(), DisposalHandling, RangedInstanceReferenceResolutions.Values.Select(b => b.Build()).ToList(), _containerReference, diff --git a/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs b/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs index 73db3921..032b385e 100644 --- a/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs +++ b/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs @@ -3,7 +3,7 @@ namespace MrMeeseeks.DIE.ResolutionBuilding; internal interface ITransientScopeInterfaceResolutionBuilder { void AddImplementation(ITransientScopeImplementationResolutionBuilder implementation); - FunctionCallResolution CreateTransientScopeInstanceReferenceResolution( + MultiSynchronicityFunctionCallResolution CreateTransientScopeInstanceReferenceResolution( ForConstructorParameter parameter, string containerReference); @@ -19,6 +19,8 @@ internal class TransientScopeInterfaceResolutionBuilder : ITransientScopeInterfa new List(); protected readonly IDictionary RangedInstanceReferenceResolutions = new Dictionary(); + + private readonly WellKnownTypes _wellKnownTypes; private readonly Func _rangedFunctionGroupResolutionBuilderFactory; private readonly string _name; @@ -27,8 +29,10 @@ internal class TransientScopeInterfaceResolutionBuilder : ITransientScopeInterfa public TransientScopeInterfaceResolutionBuilder( IReferenceGeneratorFactory referenceGeneratorFactory, + WellKnownTypes wellKnownTypes, Func rangedFunctionGroupResolutionBuilderFactory) { + _wellKnownTypes = wellKnownTypes; _rangedFunctionGroupResolutionBuilderFactory = rangedFunctionGroupResolutionBuilderFactory; _rootReferenceGenerator = referenceGeneratorFactory.Create(); @@ -49,7 +53,7 @@ public void AddImplementation(ITransientScopeImplementationResolutionBuilder imp _implementations.Add(implementation); } - public FunctionCallResolution CreateTransientScopeInstanceReferenceResolution(ForConstructorParameter parameter, string containerReference) => + public MultiSynchronicityFunctionCallResolution CreateTransientScopeInstanceReferenceResolution(ForConstructorParameter parameter, string containerReference) => CreateRangedInstanceReferenceResolution( parameter, "TransientScope", @@ -60,7 +64,7 @@ public FunctionCallResolution CreateTransientScopeInstanceReferenceResolution(Fo _name, _containerAdapterName); - private FunctionCallResolution CreateRangedInstanceReferenceResolution( + private MultiSynchronicityFunctionCallResolution CreateRangedInstanceReferenceResolution( ForConstructorParameter parameter, string label, string owningObjectReference) @@ -97,11 +101,32 @@ private FunctionCallResolution CreateRangedInstanceReferenceResolution( new ParameterResolution(_rootReferenceGenerator.Generate(t.Type), t.Type.FullName())).ToList()); RangedInstanceReferenceResolutions[key] = interfaceDeclaration; } - - return new(_rootReferenceGenerator.Generate("ret"), - interfaceDeclaration.TypeFullName, - interfaceDeclaration.Reference, - owningObjectReference, - interfaceDeclaration.Parameter.Zip(currentParameters, (p, cp) => (p.Reference, cp.Resolution.Reference)).ToList()); + + var returnReference = _rootReferenceGenerator.Generate("ret"); + + return new( + new(returnReference, + interfaceDeclaration.TypeFullName, + interfaceDeclaration.TypeFullName, + interfaceDeclaration.Reference, + owningObjectReference, + interfaceDeclaration.Parameter.Zip(currentParameters, (p, cp) => (p.Reference, cp.Resolution.Reference)) + .ToList()) + { Await = false }, + new(returnReference, + _wellKnownTypes.Task1.Construct(implementationType).FullName(), + interfaceDeclaration.TypeFullName, + interfaceDeclaration.Reference, + owningObjectReference, + interfaceDeclaration.Parameter.Zip(currentParameters, (p, cp) => (p.Reference, cp.Resolution.Reference)) + .ToList()), + new(returnReference, + interfaceDeclaration.TypeFullName, + _wellKnownTypes.ValueTask1.Construct(implementationType).FullName(), + interfaceDeclaration.Reference, + owningObjectReference, + interfaceDeclaration.Parameter.Zip(currentParameters, (p, cp) => (p.Reference, cp.Resolution.Reference)) + .ToList()), + new Lazy(() => SynchronicityDecision.Sync)); // todo solve situation with transient scope instance interface } } \ No newline at end of file diff --git a/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs b/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs index b1e14f7d..d2c053ff 100644 --- a/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs @@ -2,20 +2,14 @@ namespace MrMeeseeks.DIE.ResolutionBuilding; -internal interface ITransientScopeResolutionBuilder : ITransientScopeImplementationResolutionBuilder, IRangeResolutionBaseBuilder +internal interface ITransientScopeResolutionBuilder : ITransientScopeImplementationResolutionBuilder, IRangeResolutionBaseBuilder, IResolutionBuilder { - bool HasWorkToDo { get; } - TransientScopeRootResolution AddCreateResolveFunction( IScopeRootParameter parameter, INamedTypeSymbol rootType, string containerInstanceScopeReference, DisposableCollectionResolution disposableCollectionResolution, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters); - - void DoWork(); - - TransientScopeResolution Build(); } internal class TransientScopeResolutionBuilder : RangeResolutionBaseBuilder, ITransientScopeResolutionBuilder @@ -24,13 +18,10 @@ internal class TransientScopeResolutionBuilder : RangeResolutionBaseBuilder, ITr private readonly ITransientScopeInterfaceResolutionBuilder _transientScopeInterfaceResolutionBuilder; private readonly IScopeManager _scopeManager; private readonly Func _scopeRootCreateFunctionResolutionBuilderFactory; - private readonly List _rootResolutions = new (); private readonly string _containerReference; private readonly string _containerParameterReference; private readonly Dictionary _transientScopeRootFunctionResolutions = new (); - private readonly HashSet<(IScopeRootCreateFunctionResolutionBuilder, string)> _transientScopeRootFunctionQueuedOverloads = new (); - private readonly Queue _transientScopeRootFunctionResolutionsQueue = new(); internal TransientScopeResolutionBuilder( // parameter @@ -62,10 +53,10 @@ internal TransientScopeResolutionBuilder( _containerParameterReference = RootReferenceGenerator.Generate("container"); } - public override FunctionCallResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter) => + public override MultiSynchronicityFunctionCallResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter) => _containerResolutionBuilder.CreateContainerInstanceReferenceResolution(parameter, _containerReference); - public override FunctionCallResolution CreateTransientScopeInstanceReferenceResolution(ForConstructorParameter parameter) => + public override MultiSynchronicityFunctionCallResolution CreateTransientScopeInstanceReferenceResolution(ForConstructorParameter parameter) => _transientScopeInterfaceResolutionBuilder.CreateTransientScopeInstanceReferenceResolution(parameter, "this"); public override TransientScopeRootResolution CreateTransientScopeRootResolution(IScopeRootParameter parameter, INamedTypeSymbol rootType, @@ -94,7 +85,9 @@ public override ScopeRootResolution CreateScopeRootResolution( disposableCollectionResolution, currentParameters); - public bool HasWorkToDo => _transientScopeRootFunctionResolutionsQueue.Any() || RangedInstanceReferenceResolutions.Values.Any(r => r.HasWorkToDo); + public bool HasWorkToDo => + _transientScopeRootFunctionResolutions.Values.Any(f => f.HasWorkToDo) + || RangedInstanceReferenceResolutions.Values.Any(r => r.HasWorkToDo); public TransientScopeRootResolution AddCreateResolveFunction( IScopeRootParameter parameter, @@ -112,13 +105,6 @@ public TransientScopeRootResolution AddCreateResolveFunction( _transientScopeRootFunctionResolutions[key] = function; } - var listedParameterTypes = string.Join(",", currentParameters.Select(p => p.Item2.TypeFullName)); - if (!_transientScopeRootFunctionQueuedOverloads.Contains((function, listedParameterTypes))) - { - _transientScopeRootFunctionResolutionsQueue.Enqueue(function); - _transientScopeRootFunctionQueuedOverloads.Add((function, listedParameterTypes)); - } - var transientScopeRootReference = RootReferenceGenerator.Generate("transientScopeRoot"); return new TransientScopeRootResolution( @@ -133,29 +119,29 @@ public void DoWork() { while (HasWorkToDo) { - while (_transientScopeRootFunctionResolutionsQueue.Any()) + foreach (var functionResolutionBuilder in _transientScopeRootFunctionResolutions.Values.Where(f => f.HasWorkToDo)) { - var functionResolution = _transientScopeRootFunctionResolutionsQueue - .Dequeue() - .Build(); - - _rootResolutions.Add(new RootResolutionFunction( - functionResolution.Reference, - functionResolution.TypeFullName, - "internal", - functionResolution.Resolvable, - functionResolution.Parameter, - functionResolution.DisposalHandling, - functionResolution.LocalFunctions, - functionResolution.IsAsync)); + functionResolutionBuilder.DoWork(); } - + DoRangedInstancesWork(); } } public TransientScopeResolution Build() => - new(_rootResolutions, + new(_transientScopeRootFunctionResolutions + .Values + .Select(f => f.Build()) + .Select(f => new RootResolutionFunction( + f.Reference, + f.TypeFullName, + "internal", + f.Resolvable, + f.Parameter, + f.DisposalHandling, + f.LocalFunctions, + f.SynchronicityDecision)) + .ToList(), DisposalHandling, RangedInstanceReferenceResolutions.Values.Select(b => b.Build()).ToList(), _containerReference, diff --git a/Main/ResolutionTreeCreationErrorHarvester.cs b/Main/ResolutionTreeCreationErrorHarvester.cs index 5e550077..0b52042b 100644 --- a/Main/ResolutionTreeCreationErrorHarvester.cs +++ b/Main/ResolutionTreeCreationErrorHarvester.cs @@ -10,7 +10,7 @@ internal class ResolutionTreeCreationErrorHarvester : IResolutionTreeCreationErr public IReadOnlyList Harvest(ResolutionTreeItem root) { var errorTreeItems = new List(); - Inner(root, errorTreeItems); + //Inner(root, errorTreeItems); // todo error handling return errorTreeItems; static void Inner(ResolutionTreeItem item, ICollection errorTreeItems) diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index 393eadce..fa750554 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -1,4 +1,6 @@ -namespace MrMeeseeks.DIE; +using MrMeeseeks.DIE.ResolutionBuilding; + +namespace MrMeeseeks.DIE; internal abstract record ResolutionTreeItem; @@ -11,6 +13,10 @@ internal record DeferringResolvable() : Resolvable("", "") internal Resolvable? Resolvable { get; set; } } +internal record NewReferenceResolvable( + string Reference, + Resolvable Resolvable) : Resolvable(Reference, Resolvable.TypeFullName); + internal record FunctionResolution( string Reference, string TypeFullName, @@ -18,7 +24,7 @@ internal record FunctionResolution( IReadOnlyList Parameter, DisposalHandling DisposalHandling, IReadOnlyList LocalFunctions, - bool IsAsync) : Resolvable(Reference, TypeFullName); + SynchronicityDecision SynchronicityDecision) : Resolvable(Reference, TypeFullName); internal record RootResolutionFunction( string Reference, @@ -28,8 +34,8 @@ internal record RootResolutionFunction( IReadOnlyList Parameter, DisposalHandling DisposalHandling, IReadOnlyList LocalFunctions, - bool IsAsync) - : FunctionResolution(Reference, TypeFullName, Resolvable, Parameter, DisposalHandling, LocalFunctions, IsAsync); + SynchronicityDecision SynchronicityDecision) + : FunctionResolution(Reference, TypeFullName, Resolvable, Parameter, DisposalHandling, LocalFunctions, SynchronicityDecision); internal record LocalFunctionResolution( string Reference, @@ -38,8 +44,8 @@ internal record LocalFunctionResolution( IReadOnlyList Parameter, DisposalHandling DisposalHandling, IReadOnlyList LocalFunctions, - bool IsAsync) - : FunctionResolution(Reference, TypeFullName, Resolvable, Parameter, DisposalHandling, LocalFunctions, IsAsync); + SynchronicityDecision SynchronicityDecision) + : FunctionResolution(Reference, TypeFullName, Resolvable, Parameter, DisposalHandling, LocalFunctions, SynchronicityDecision); internal record RangedInstanceFunctionResolution( string Reference, @@ -48,8 +54,8 @@ internal record RangedInstanceFunctionResolution( IReadOnlyList Parameter, DisposalHandling DisposalHandling, IReadOnlyList LocalFunctions, - bool IsAsync) - : FunctionResolution(Reference, TypeFullName, Resolvable, Parameter, DisposalHandling, LocalFunctions, IsAsync); + SynchronicityDecision SynchronicityDecision) + : FunctionResolution(Reference, TypeFullName, Resolvable, Parameter, DisposalHandling, LocalFunctions, SynchronicityDecision); internal record RangedInstanceFunctionGroupResolution( string TypeFullName, @@ -86,6 +92,8 @@ internal interface IAwaitableResolution bool Await { get; } } +internal interface ITaskConsumableResolution {} + internal record TaskBaseTypeInitializationResolution( string TypeFullName, string MethodName, @@ -113,7 +121,7 @@ internal record ConstructorResolution( DisposableCollectionResolution? DisposableCollectionResolution, IReadOnlyList<(string Name, Resolvable Dependency)> Parameter, IReadOnlyList<(string Name, Resolvable Dependency)> InitializedProperties, - ITypeInitializationResolution? Initialization) : Resolvable(Reference, TypeFullName); + ITypeInitializationResolution? Initialization) : Resolvable(Reference, TypeFullName), ITaskConsumableResolution; internal record LazyResolution( string Reference, @@ -130,7 +138,7 @@ internal record TransientScopeRootResolution( string TransientScopeTypeFullName, string ContainerInstanceScopeReference, DisposableCollectionResolution DisposableCollectionResolution, - FunctionCallResolution ScopeRootFunction) : Resolvable(ScopeRootFunction.Reference, ScopeRootFunction.TypeFullName); + MultiSynchronicityFunctionCallResolution ScopeRootFunction) : Resolvable(ScopeRootFunction.Reference, ScopeRootFunction.TypeFullName); internal record ScopeRootResolution( string ScopeReference, @@ -138,7 +146,7 @@ internal record ScopeRootResolution( string ContainerInstanceScopeReference, string TransientInstanceScopeReference, DisposableCollectionResolution DisposableCollectionResolution, - FunctionCallResolution ScopeRootFunction) : Resolvable(ScopeRootFunction.Reference, ScopeRootFunction.TypeFullName); + MultiSynchronicityFunctionCallResolution ScopeRootFunction) : Resolvable(ScopeRootFunction.Reference, ScopeRootFunction.Sync.OriginalTypeFullName); internal record ScopeRootFunction( string Reference, @@ -280,10 +288,50 @@ internal record ValueTaskFromWrappedTaskResolution( string Reference, string FullName) : Resolvable(Reference, FullName); +internal record MultiTaskResolution( + Resolvable Sync, + Resolvable AsyncTask, + Resolvable AsyncValueTask, + Lazy LazySynchronicityDecision) : Resolvable(Sync.Reference, "") +{ + internal Resolvable SelectedResolvable => + LazySynchronicityDecision.Value switch + { + SynchronicityDecision.Sync => Sync, + SynchronicityDecision.AsyncTask => AsyncTask, + SynchronicityDecision.AsyncValueTask => AsyncValueTask, + _ => throw new ArgumentException("Synchronicity not decided yet") + }; +} + +internal record MultiSynchronicityFunctionCallResolution( + FunctionCallResolution Sync, + FunctionCallResolution AsyncTask, + FunctionCallResolution AsyncValueTask, + Lazy LazySynchronicityDecision) : Resolvable(Sync.Reference, ""), IAwaitableResolution, ITaskConsumableResolution +{ + internal FunctionCallResolution SelectedFunctionCall => + LazySynchronicityDecision.Value switch + { + SynchronicityDecision.Sync => Sync, + SynchronicityDecision.AsyncTask => AsyncTask, + SynchronicityDecision.AsyncValueTask => AsyncValueTask, + _ => throw new ArgumentException("Synchronicity not decided yet") + }; + + public bool Await => SelectedFunctionCall.Await; +} + internal record FunctionCallResolution( string Reference, string TypeFullName, + string OriginalTypeFullName, string FunctionReference, string? OwnerReference, IReadOnlyList<(string Name, string Reference)> Parameters) - : Resolvable(Reference, TypeFullName); \ No newline at end of file + : Resolvable(Reference, TypeFullName), IAwaitableResolution +{ + public bool Await { get; set; } = true; + + public string SelectedTypeFullName => Await ? OriginalTypeFullName : TypeFullName; +} \ No newline at end of file diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index 6624cd48..874b1bd1 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -42,7 +42,7 @@ IContainerResolutionBuilder ResolutionTreeFactory(IContainerInfo ci) return new ContainerResolutionBuilder( ci, - new TransientScopeInterfaceResolutionBuilder(referenceGeneratorFactory, RangedFunctionGroupResolutionBuilderFactory), + new TransientScopeInterfaceResolutionBuilder(referenceGeneratorFactory, wellKnownTypes, RangedFunctionGroupResolutionBuilderFactory), referenceGeneratorFactory, new CheckTypeProperties(new CurrentlyConsideredTypes(containerTypesFromAttributesList, context)), wellKnownTypes, diff --git a/Sample/Context.cs b/Sample/Context.cs index 96cf4f87..7450f776 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration; using MrMeeseeks.DIE.Sample; -namespace MrMeeseeks.DIE.Test.Async.AwaitedDependency.Dependency; +namespace MrMeeseeks.DIE.Test.Async.Awaited.FunctionCall; internal class Dependency : ITaskTypeInitializer @@ -16,7 +16,12 @@ async Task ITaskTypeInitializer.InitializeAsync() } } -[CreateFunction(typeof(Dependency), "CreateDep")] +internal class ScopeRoot : IScopeRoot +{ + internal ScopeRoot(Dependency dep) {} +} + +[CreateFunction(typeof(Task), "Create")] internal partial class Container { } \ No newline at end of file diff --git a/Sample/Program.cs b/Sample/Program.cs index 1dfb3ebf..319cffa1 100644 --- a/Sample/Program.cs +++ b/Sample/Program.cs @@ -1,5 +1,5 @@ using System; -using MrMeeseeks.DIE.Test.Async.AwaitedDependency.Dependency; +using MrMeeseeks.DIE.Test.Async.Awaited.FunctionCall; internal class Program { @@ -7,6 +7,6 @@ private static void Main() { Console.WriteLine("Hello, world!"); var container = new Container(); - Console.WriteLine(container.CreateDepAsync().ConfigureAwait(false)); + Console.WriteLine(container.CreateAsync()); } } \ No newline at end of file diff --git a/Test/Async/Awaited/FunctionCall.cs b/Test/Async/Awaited/FunctionCall.cs new file mode 100644 index 00000000..0524f851 --- /dev/null +++ b/Test/Async/Awaited/FunctionCall.cs @@ -0,0 +1,37 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Async.Awaited.FunctionCall; + + +internal class Dependency : ITaskTypeInitializer +{ + public bool IsInitialized { get; private set; } + + async Task ITaskTypeInitializer.InitializeAsync() + { + await Task.Delay(500).ConfigureAwait(false); + IsInitialized = true; + } +} + +internal class ScopeRoot : IScopeRoot +{ + internal ScopeRoot(Dependency dep) {} +} + +[CreateFunction(typeof(Task), "Create")] +internal partial class Container +{ +} + +public class Tests +{ + [Fact] + public async Task Test() + { + using var container = new Container(); + var instance = await container.CreateAsync().ConfigureAwait(false); + } +} \ No newline at end of file diff --git a/Test/Async/AwaitedDependency/Dependency.cs b/Test/Async/Awaited/TaskTypeInitializerTask.cs similarity index 90% rename from Test/Async/AwaitedDependency/Dependency.cs rename to Test/Async/Awaited/TaskTypeInitializerTask.cs index 2ac91baf..aa7b0e19 100644 --- a/Test/Async/AwaitedDependency/Dependency.cs +++ b/Test/Async/Awaited/TaskTypeInitializerTask.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration; using Xunit; -namespace MrMeeseeks.DIE.Test.Async.AwaitedDependency.Dependency; +namespace MrMeeseeks.DIE.Test.Async.Awaited.TaskTypeInitializerTask; internal class Dependency : ITaskTypeInitializer diff --git a/Test/Async/Awaited/TaskTypeInitializerValueTask.cs b/Test/Async/Awaited/TaskTypeInitializerValueTask.cs new file mode 100644 index 00000000..f6046bc7 --- /dev/null +++ b/Test/Async/Awaited/TaskTypeInitializerValueTask.cs @@ -0,0 +1,33 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Async.Awaited.TaskTypeInitializerValueTask; + + +internal class Dependency : IValueTaskTypeInitializer +{ + public bool IsInitialized { get; private set; } + + async ValueTask IValueTaskTypeInitializer.InitializeAsync() + { + await Task.Delay(500).ConfigureAwait(false); + IsInitialized = true; + } +} + +[CreateFunction(typeof(Dependency), "CreateDep")] +internal partial class Container +{ +} + +public class Tests +{ + [Fact] + public async Task Test() + { + using var container = new Container(); + var instance = await container.CreateDepAsync().ConfigureAwait(false); + Assert.True(instance.IsInitialized); + } +} \ No newline at end of file From dfd8cbbbab73caf5dbcec3a63e30b1bfc3dc04d1 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Tue, 29 Mar 2022 23:01:08 +0200 Subject: [PATCH 053/162] Fixed consumption of async calls and tests for that --- Main/CodeBuilding/RangeCodeBaseBuilder.cs | 8 +-- .../FunctionResolutionBuilder.cs | 49 ++++++++++++++----- Main/ResolutionTreeItem.cs | 3 +- Sample/Context.cs | 8 ++- Sample/Program.cs | 2 +- ...ionCall.cs => AsyncScopeRootCallAsTask.cs} | 11 +++-- .../Awaited/AsyncScopeRootCallAsValueTask.cs | 42 ++++++++++++++++ .../Awaited/AsyncScopeRootCallAwaited.cs | 42 ++++++++++++++++ 8 files changed, 142 insertions(+), 23 deletions(-) rename Test/Async/Awaited/{FunctionCall.cs => AsyncScopeRootCallAsTask.cs} (67%) create mode 100644 Test/Async/Awaited/AsyncScopeRootCallAsValueTask.cs create mode 100644 Test/Async/Awaited/AsyncScopeRootCallAwaited.cs diff --git a/Main/CodeBuilding/RangeCodeBaseBuilder.cs b/Main/CodeBuilding/RangeCodeBaseBuilder.cs index 3de3e0d3..5eacf8b3 100644 --- a/Main/CodeBuilding/RangeCodeBaseBuilder.cs +++ b/Main/CodeBuilding/RangeCodeBaseBuilder.cs @@ -153,10 +153,10 @@ private static StringBuilder GenerateFields( case DeferringResolvable { Resolvable: {} resolvable}: stringBuilder = GenerateFields(stringBuilder, resolvable); break; - case NewReferenceResolvable(var reference, var resolvable): + case NewReferenceResolvable(var reference, var typeFullName, var resolvable): stringBuilder = GenerateFields(stringBuilder, resolvable); stringBuilder = stringBuilder - .AppendLine($"{resolvable.TypeFullName} {reference};"); + .AppendLine($"{typeFullName} {reference};"); break; case MultiTaskResolution { SelectedResolvable: {} resolvable}: stringBuilder = GenerateFields(stringBuilder, resolvable); @@ -273,10 +273,10 @@ private StringBuilder GenerateResolutions( case MultiTaskResolution { SelectedResolvable: {} resolvable}: stringBuilder = GenerateResolutions(stringBuilder, resolvable); break; - case NewReferenceResolvable(var reference, var resolvable): + case NewReferenceResolvable(var reference, var typeFullName, var resolvable): stringBuilder = GenerateResolutions(stringBuilder, resolvable); stringBuilder = stringBuilder - .AppendLine($"{reference} = ({resolvable.TypeFullName}) {resolvable.Reference};"); + .AppendLine($"{reference} = ({typeFullName}) {resolvable.Reference};"); break; case MultiSynchronicityFunctionCallResolution { SelectedFunctionCall: {} selectedFunctionCall}: stringBuilder = GenerateResolutions(stringBuilder, selectedFunctionCall); diff --git a/Main/ResolutionBuilding/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/FunctionResolutionBuilder.cs index 22d4866e..b45d88b6 100644 --- a/Main/ResolutionBuilding/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/FunctionResolutionBuilder.cs @@ -591,12 +591,12 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup multiSynchronicityFunctionCallResolution.AsyncValueTask.Await = false; return (new MultiTaskResolution( new TaskFromSyncResolution( - multiSynchronicityFunctionCallResolution.Sync, + resolution.Item1, taskReference, taskFullName), - new NewReferenceResolvable(taskReference, multiSynchronicityFunctionCallResolution.AsyncTask), + new NewReferenceResolvable(taskReference, taskFullName, resolution.Item1), new TaskFromWrappedValueTaskResolution( - multiSynchronicityFunctionCallResolution.AsyncValueTask, + resolution.Item1, taskReference, taskFullName), multiSynchronicityFunctionCallResolution.LazySynchronicityDecision), null); @@ -642,14 +642,14 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup multiSynchronicityFunctionCallResolution.AsyncValueTask.Await = false; return (new MultiTaskResolution( new ValueTaskFromSyncResolution( - multiSynchronicityFunctionCallResolution.Sync, + resolution.Item1, valueTaskReference, valueTaskFullName), new ValueTaskFromWrappedTaskResolution( - multiSynchronicityFunctionCallResolution.AsyncTask, + resolution.Item1, valueTaskReference, valueTaskFullName), - new NewReferenceResolvable(valueTaskReference, multiSynchronicityFunctionCallResolution.AsyncValueTask), + new NewReferenceResolvable(valueTaskReference, valueTaskFullName, resolution.Item1), multiSynchronicityFunctionCallResolution.LazySynchronicityDecision), null); } return (new TaskFromSyncResolution(resolution.Item1, wrappedValueTaskReference, boundValueTaskTypeFullName), resolution.Item2); @@ -683,9 +683,18 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup _ => SwitchInterfaceAfterScopeRoot(nextParameter) }; - if (ret.Item1 is IAwaitableResolution awaitableResolution) + if (ret.Item1 is ScopeRootResolution { ScopeRootFunction: IAwaitableResolution awaitableResolution }) PotentialAwaits.Add(awaitableResolution); - + + if (ret.Item1 is TransientScopeRootResolution { ScopeRootFunction: IAwaitableResolution awaitableResolution0 }) + PotentialAwaits.Add(awaitableResolution0); + + if (ret.Item1 is ScopeRootResolution { ScopeRootFunction: ITaskConsumableResolution taskConsumableResolution }) + ret.Item2 = taskConsumableResolution; + + if (ret.Item1 is TransientScopeRootResolution { ScopeRootFunction: ITaskConsumableResolution taskConsumableResolution0 }) + ret.Item2 = taskConsumableResolution0; + return ret; } @@ -755,9 +764,18 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup _ => CreateInterface(nextParameter) }; - if (ret.Item1 is IAwaitableResolution awaitableResolution) + if (ret.Item1 is ScopeRootResolution { ScopeRootFunction: IAwaitableResolution awaitableResolution }) PotentialAwaits.Add(awaitableResolution); - + + if (ret.Item1 is TransientScopeRootResolution { ScopeRootFunction: IAwaitableResolution awaitableResolution0 }) + PotentialAwaits.Add(awaitableResolution0); + + if (ret.Item1 is ScopeRootResolution { ScopeRootFunction: ITaskConsumableResolution taskConsumableResolution }) + ret.Item2 = taskConsumableResolution; + + if (ret.Item1 is TransientScopeRootResolution { ScopeRootFunction: ITaskConsumableResolution taskConsumableResolution0 }) + ret.Item2 = taskConsumableResolution0; + return ret; } @@ -850,6 +868,12 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup if (ret.Item1 is TransientScopeRootResolution { ScopeRootFunction: IAwaitableResolution awaitableResolution0 }) PotentialAwaits.Add(awaitableResolution0); + if (ret.Item1 is ScopeRootResolution { ScopeRootFunction: ITaskConsumableResolution taskConsumableResolution }) + ret.Item2 = taskConsumableResolution; + + if (ret.Item1 is TransientScopeRootResolution { ScopeRootFunction: ITaskConsumableResolution taskConsumableResolution0 }) + ret.Item2 = taskConsumableResolution0; + return ret; } @@ -887,9 +911,10 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup }; if (ret.Item1 is IAwaitableResolution awaitableResolution) - { PotentialAwaits.Add(awaitableResolution); - } + + if (ret.Item2 is null) + ret.Item2 = ret.Item1 as ITaskConsumableResolution; return ret; } diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index fa750554..b1a451d8 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -15,7 +15,8 @@ internal record DeferringResolvable() : Resolvable("", "") internal record NewReferenceResolvable( string Reference, - Resolvable Resolvable) : Resolvable(Reference, Resolvable.TypeFullName); + string TypeFullName, + Resolvable Resolvable) : Resolvable(Reference, TypeFullName); internal record FunctionResolution( string Reference, diff --git a/Sample/Context.cs b/Sample/Context.cs index 7450f776..5a381e79 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration; using MrMeeseeks.DIE.Sample; -namespace MrMeeseeks.DIE.Test.Async.Awaited.FunctionCall; +namespace MrMeeseeks.DIE.Test.Async.Awaited.AsyncFunctionCallAsTask; internal class Dependency : ITaskTypeInitializer @@ -18,7 +18,11 @@ async Task ITaskTypeInitializer.InitializeAsync() internal class ScopeRoot : IScopeRoot { - internal ScopeRoot(Dependency dep) {} + public Dependency Dep { get; } + internal ScopeRoot(Dependency dep) + { + Dep = dep; + } } [CreateFunction(typeof(Task), "Create")] diff --git a/Sample/Program.cs b/Sample/Program.cs index 319cffa1..87deb416 100644 --- a/Sample/Program.cs +++ b/Sample/Program.cs @@ -1,5 +1,5 @@ using System; -using MrMeeseeks.DIE.Test.Async.Awaited.FunctionCall; +using MrMeeseeks.DIE.Test.Async.Awaited.AsyncFunctionCallAsTask; internal class Program { diff --git a/Test/Async/Awaited/FunctionCall.cs b/Test/Async/Awaited/AsyncScopeRootCallAsTask.cs similarity index 67% rename from Test/Async/Awaited/FunctionCall.cs rename to Test/Async/Awaited/AsyncScopeRootCallAsTask.cs index 0524f851..20a763eb 100644 --- a/Test/Async/Awaited/FunctionCall.cs +++ b/Test/Async/Awaited/AsyncScopeRootCallAsTask.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration; using Xunit; -namespace MrMeeseeks.DIE.Test.Async.Awaited.FunctionCall; +namespace MrMeeseeks.DIE.Test.Async.Awaited.AsyncScopeRootCallAsTask; internal class Dependency : ITaskTypeInitializer @@ -18,7 +18,11 @@ async Task ITaskTypeInitializer.InitializeAsync() internal class ScopeRoot : IScopeRoot { - internal ScopeRoot(Dependency dep) {} + public Dependency Dep { get; } + internal ScopeRoot(Dependency dep) + { + Dep = dep; + } } [CreateFunction(typeof(Task), "Create")] @@ -32,6 +36,7 @@ public class Tests public async Task Test() { using var container = new Container(); - var instance = await container.CreateAsync().ConfigureAwait(false); + var root = await container.Create().ConfigureAwait(false); + Assert.True(root.Dep.IsInitialized); } } \ No newline at end of file diff --git a/Test/Async/Awaited/AsyncScopeRootCallAsValueTask.cs b/Test/Async/Awaited/AsyncScopeRootCallAsValueTask.cs new file mode 100644 index 00000000..bc9dd133 --- /dev/null +++ b/Test/Async/Awaited/AsyncScopeRootCallAsValueTask.cs @@ -0,0 +1,42 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Async.Awaited.AsyncScopeRootCallAsValueTask; + + +internal class Dependency : ITaskTypeInitializer +{ + public bool IsInitialized { get; private set; } + + async Task ITaskTypeInitializer.InitializeAsync() + { + await Task.Delay(500).ConfigureAwait(false); + IsInitialized = true; + } +} + +internal class ScopeRoot : IScopeRoot +{ + public Dependency Dep { get; } + internal ScopeRoot(Dependency dep) + { + Dep = dep; + } +} + +[CreateFunction(typeof(ValueTask), "Create")] +internal partial class Container +{ +} + +public class Tests +{ + [Fact] + public async Task Test() + { + using var container = new Container(); + var root = await container.Create().ConfigureAwait(false); + Assert.True(root.Dep.IsInitialized); + } +} \ No newline at end of file diff --git a/Test/Async/Awaited/AsyncScopeRootCallAwaited.cs b/Test/Async/Awaited/AsyncScopeRootCallAwaited.cs new file mode 100644 index 00000000..1e5b45d3 --- /dev/null +++ b/Test/Async/Awaited/AsyncScopeRootCallAwaited.cs @@ -0,0 +1,42 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Async.Awaited.AsyncScopeRootCallAwaited; + + +internal class Dependency : ITaskTypeInitializer +{ + public bool IsInitialized { get; private set; } + + async Task ITaskTypeInitializer.InitializeAsync() + { + await Task.Delay(500).ConfigureAwait(false); + IsInitialized = true; + } +} + +internal class ScopeRoot : IScopeRoot +{ + public Dependency Dep { get; } + internal ScopeRoot(Dependency dep) + { + Dep = dep; + } +} + +[CreateFunction(typeof(ScopeRoot), "Create")] +internal partial class Container +{ +} + +public class Tests +{ + [Fact] + public async Task Test() + { + using var container = new Container(); + var root = await container.CreateAsync().ConfigureAwait(false); + Assert.True(root.Dep.IsInitialized); + } +} \ No newline at end of file From b25adcb2f477da6900e1dd25dcb66a3d9764fad0 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Thu, 31 Mar 2022 23:08:14 +0200 Subject: [PATCH 054/162] Make ValueTask to default return type for functions instead of Task --- .../ContainerResolutionBuilder.cs | 48 +++++++++++++++++++ .../FunctionResolutionBuilder.cs | 11 +++-- .../Async/Awaited/AsyncScopeRootCallAsTask.cs | 2 +- .../Awaited/AsyncScopeRootCallAsValueTask.cs | 2 +- .../Awaited/AsyncScopeRootCallAwaited.cs | 4 +- Test/Async/Awaited/TaskTypeInitializerTask.cs | 2 +- .../Awaited/TaskTypeInitializerValueTask.cs | 2 +- .../WrappedDependency/DecorationChaining.cs | 2 +- Test/Async/WrappedDependency/Func.cs | 2 +- Test/Async/WrappedDependency/Lazy.cs | 2 +- Test/Async/WrappedDependency/SyncToTask.cs | 2 +- .../WrappedDependency/SyncToValueTask.cs | 2 +- .../Async/WrappedDependency/TaskCollection.cs | 2 +- .../WrappedDependency/TaskComposition.cs | 2 +- Test/Async/WrappedDependency/TaskToTask.cs | 2 +- .../WrappedDependency/TaskToValueTask.cs | 2 +- .../WrappedDependency/ValueTaskCollection.cs | 2 +- .../WrappedDependency/ValueTaskComposition.cs | 2 +- .../WrappedDependency/ValueTaskToTask.cs | 2 +- .../WrappedDependency/ValueTaskToValueTask.cs | 2 +- 20 files changed, 74 insertions(+), 23 deletions(-) diff --git a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs index 958bfd8f..02853d77 100644 --- a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs @@ -258,6 +258,54 @@ public ContainerResolution Build() rootFunctions.Add(publicValueTaskResolutionFunction); } + else if (createFunction.ActualReturnType is { } actual1 + && actual1.Equals(_wellKnownTypes.ValueTask1.Construct(createFunction.OriginalReturnType), + SymbolEqualityComparer.Default)) + { + var boundTaskTypeFullName = _wellKnownTypes + .Task1 + .Construct(createFunction.OriginalReturnType) + .FullName(); + var call = createFunction.BuildFunctionCall( + Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>(), + "this"); + call.Sync.Await = false; + call.AsyncTask.Await = false; + call.AsyncValueTask.Await = false; + var wrappedTaskReference = RootReferenceGenerator.Generate(_wellKnownTypes.ValueTask); + var publicTaskResolutionFunction = new RootResolutionFunction( + $"{methodNamePrefix}Async", + boundTaskTypeFullName, + "public", + new TaskFromWrappedValueTaskResolution( + call, + wrappedTaskReference, + boundTaskTypeFullName), + privateRootResolutionFunction.Parameter, + DisposalHandling, + Array.Empty(), + SynchronicityDecision.Sync); + + rootFunctions.Add(publicTaskResolutionFunction); + + var valueCall = createFunction.BuildFunctionCall( + Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>(), + "this"); + valueCall.Sync.Await = false; + valueCall.AsyncTask.Await = false; + valueCall.AsyncValueTask.Await = false; + var publicValueTaskResolutionFunction = new RootResolutionFunction( + $"{methodNamePrefix}ValueAsync", + actual1.FullName(), + "public", + valueCall, + privateRootResolutionFunction.Parameter, + DisposalHandling, + Array.Empty(), + SynchronicityDecision.Sync); + + rootFunctions.Add(publicValueTaskResolutionFunction); + } } var (transientScopeResolutions, scopeResolutions) = _scopeManager.Build(); diff --git a/Main/ResolutionBuilding/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/FunctionResolutionBuilder.cs index b45d88b6..0f0264bd 100644 --- a/Main/ResolutionBuilding/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/FunctionResolutionBuilder.cs @@ -310,7 +310,7 @@ internal FunctionResolutionBuilder( SynchronicityDecision = new(() => PotentialAwaits.Any(pa => pa.Await) - ? ResolutionBuilding.SynchronicityDecision.AsyncTask + ? ResolutionBuilding.SynchronicityDecision.AsyncValueTask : ResolutionBuilding.SynchronicityDecision.Sync); Resolvable = new(CreateResolvable); } @@ -1095,9 +1095,12 @@ false when initializationMethod.ReturnType.Equals(_wellKnownTypes.ValueTask, Sym } protected void AdjustForSynchronicity() => - ActualReturnType = SynchronicityDecision.Value is ResolutionBuilding.SynchronicityDecision.AsyncTask or ResolutionBuilding.SynchronicityDecision.AsyncValueTask - ? _wellKnownTypes.Task1.Construct(OriginalReturnType) - : OriginalReturnType; + ActualReturnType = SynchronicityDecision.Value switch + { + ResolutionBuilding.SynchronicityDecision.AsyncTask => _wellKnownTypes.Task1.Construct(OriginalReturnType), + ResolutionBuilding.SynchronicityDecision.AsyncValueTask => _wellKnownTypes.ValueTask1.Construct(OriginalReturnType), + _ => OriginalReturnType + }; private static DisposableCollectionResolution? ImplementsIDisposable( INamedTypeSymbol type, diff --git a/Test/Async/Awaited/AsyncScopeRootCallAsTask.cs b/Test/Async/Awaited/AsyncScopeRootCallAsTask.cs index 20a763eb..3bbbb2d4 100644 --- a/Test/Async/Awaited/AsyncScopeRootCallAsTask.cs +++ b/Test/Async/Awaited/AsyncScopeRootCallAsTask.cs @@ -33,7 +33,7 @@ internal partial class Container public class Tests { [Fact] - public async Task Test() + public async ValueTask Test() { using var container = new Container(); var root = await container.Create().ConfigureAwait(false); diff --git a/Test/Async/Awaited/AsyncScopeRootCallAsValueTask.cs b/Test/Async/Awaited/AsyncScopeRootCallAsValueTask.cs index bc9dd133..f24bb830 100644 --- a/Test/Async/Awaited/AsyncScopeRootCallAsValueTask.cs +++ b/Test/Async/Awaited/AsyncScopeRootCallAsValueTask.cs @@ -33,7 +33,7 @@ internal partial class Container public class Tests { [Fact] - public async Task Test() + public async ValueTask Test() { using var container = new Container(); var root = await container.Create().ConfigureAwait(false); diff --git a/Test/Async/Awaited/AsyncScopeRootCallAwaited.cs b/Test/Async/Awaited/AsyncScopeRootCallAwaited.cs index 1e5b45d3..2d70df29 100644 --- a/Test/Async/Awaited/AsyncScopeRootCallAwaited.cs +++ b/Test/Async/Awaited/AsyncScopeRootCallAwaited.cs @@ -33,10 +33,10 @@ internal partial class Container public class Tests { [Fact] - public async Task Test() + public async ValueTask Test() { using var container = new Container(); - var root = await container.CreateAsync().ConfigureAwait(false); + var root = await container.CreateValueAsync().ConfigureAwait(false); Assert.True(root.Dep.IsInitialized); } } \ No newline at end of file diff --git a/Test/Async/Awaited/TaskTypeInitializerTask.cs b/Test/Async/Awaited/TaskTypeInitializerTask.cs index aa7b0e19..3a14b3cd 100644 --- a/Test/Async/Awaited/TaskTypeInitializerTask.cs +++ b/Test/Async/Awaited/TaskTypeInitializerTask.cs @@ -24,7 +24,7 @@ internal partial class Container public class Tests { [Fact] - public async Task Test() + public async ValueTask Test() { using var container = new Container(); var instance = await container.CreateDepAsync().ConfigureAwait(false); diff --git a/Test/Async/Awaited/TaskTypeInitializerValueTask.cs b/Test/Async/Awaited/TaskTypeInitializerValueTask.cs index f6046bc7..9f962b54 100644 --- a/Test/Async/Awaited/TaskTypeInitializerValueTask.cs +++ b/Test/Async/Awaited/TaskTypeInitializerValueTask.cs @@ -24,7 +24,7 @@ internal partial class Container public class Tests { [Fact] - public async Task Test() + public async ValueTask Test() { using var container = new Container(); var instance = await container.CreateDepAsync().ConfigureAwait(false); diff --git a/Test/Async/WrappedDependency/DecorationChaining.cs b/Test/Async/WrappedDependency/DecorationChaining.cs index c0d749ed..89a5bd55 100644 --- a/Test/Async/WrappedDependency/DecorationChaining.cs +++ b/Test/Async/WrappedDependency/DecorationChaining.cs @@ -56,7 +56,7 @@ internal partial class Container public class Tests { [Fact] - public async Task Test() + public async ValueTask Test() { using var container = new Container(); var instance = await container.CreateDep().ConfigureAwait(false); diff --git a/Test/Async/WrappedDependency/Func.cs b/Test/Async/WrappedDependency/Func.cs index 76092ff3..c7a42e8b 100644 --- a/Test/Async/WrappedDependency/Func.cs +++ b/Test/Async/WrappedDependency/Func.cs @@ -25,7 +25,7 @@ internal partial class Container public class Tests { [Fact] - public async Task Test() + public async ValueTask Test() { using var container = new Container(); var instance = container.CreateDep(); diff --git a/Test/Async/WrappedDependency/Lazy.cs b/Test/Async/WrappedDependency/Lazy.cs index 8561b37e..b7457489 100644 --- a/Test/Async/WrappedDependency/Lazy.cs +++ b/Test/Async/WrappedDependency/Lazy.cs @@ -26,7 +26,7 @@ internal partial class Container public class Tests { [Fact] - public async Task Test() + public async ValueTask Test() { using var container = new Container(); var instance = container.CreateDep(); diff --git a/Test/Async/WrappedDependency/SyncToTask.cs b/Test/Async/WrappedDependency/SyncToTask.cs index 9f24ed63..e5ab287f 100644 --- a/Test/Async/WrappedDependency/SyncToTask.cs +++ b/Test/Async/WrappedDependency/SyncToTask.cs @@ -22,7 +22,7 @@ internal partial class Container public class Tests { [Fact] - public async Task Test() + public async ValueTask Test() { using var container = new Container(); var instance = await container.CreateDep().ConfigureAwait(false); diff --git a/Test/Async/WrappedDependency/SyncToValueTask.cs b/Test/Async/WrappedDependency/SyncToValueTask.cs index 0c9c6816..3079c17c 100644 --- a/Test/Async/WrappedDependency/SyncToValueTask.cs +++ b/Test/Async/WrappedDependency/SyncToValueTask.cs @@ -23,7 +23,7 @@ internal partial class Container public class Tests { [Fact] - public async Task Test() + public async ValueTask Test() { using var container = new Container(); var instance = await container.CreateDep().ConfigureAwait(false); diff --git a/Test/Async/WrappedDependency/TaskCollection.cs b/Test/Async/WrappedDependency/TaskCollection.cs index eb971a23..52aa56bf 100644 --- a/Test/Async/WrappedDependency/TaskCollection.cs +++ b/Test/Async/WrappedDependency/TaskCollection.cs @@ -55,7 +55,7 @@ internal partial class Container public class Tests { [Fact] - public async Task Test() + public async ValueTask Test() { using var container = new Container(); var instance = container.CreateDep(); diff --git a/Test/Async/WrappedDependency/TaskComposition.cs b/Test/Async/WrappedDependency/TaskComposition.cs index afeb0390..21bdff96 100644 --- a/Test/Async/WrappedDependency/TaskComposition.cs +++ b/Test/Async/WrappedDependency/TaskComposition.cs @@ -74,7 +74,7 @@ internal partial class Container public class Tests { [Fact] - public async Task Test() + public async ValueTask Test() { using var container = new Container(); var instance = await container.CreateDep().ConfigureAwait(false); diff --git a/Test/Async/WrappedDependency/TaskToTask.cs b/Test/Async/WrappedDependency/TaskToTask.cs index 2a58176f..26ffc9b4 100644 --- a/Test/Async/WrappedDependency/TaskToTask.cs +++ b/Test/Async/WrappedDependency/TaskToTask.cs @@ -23,7 +23,7 @@ internal partial class Container public class Tests { [Fact] - public async Task Test() + public async ValueTask Test() { using var container = new Container(); var instance = await container.CreateDep().ConfigureAwait(false); diff --git a/Test/Async/WrappedDependency/TaskToValueTask.cs b/Test/Async/WrappedDependency/TaskToValueTask.cs index 098b9f2f..54ded479 100644 --- a/Test/Async/WrappedDependency/TaskToValueTask.cs +++ b/Test/Async/WrappedDependency/TaskToValueTask.cs @@ -24,7 +24,7 @@ internal partial class Container public class Tests { [Fact] - public async Task Test() + public async ValueTask Test() { using var container = new Container(); var instance = await container.CreateDep().ConfigureAwait(false); diff --git a/Test/Async/WrappedDependency/ValueTaskCollection.cs b/Test/Async/WrappedDependency/ValueTaskCollection.cs index 7c0c9469..d57884d2 100644 --- a/Test/Async/WrappedDependency/ValueTaskCollection.cs +++ b/Test/Async/WrappedDependency/ValueTaskCollection.cs @@ -55,7 +55,7 @@ internal partial class Container public class Tests { [Fact] - public async Task Test() + public async ValueTask Test() { using var container = new Container(); var instance = container.Create0(); diff --git a/Test/Async/WrappedDependency/ValueTaskComposition.cs b/Test/Async/WrappedDependency/ValueTaskComposition.cs index 4340d2ec..f220d469 100644 --- a/Test/Async/WrappedDependency/ValueTaskComposition.cs +++ b/Test/Async/WrappedDependency/ValueTaskComposition.cs @@ -75,7 +75,7 @@ internal partial class Container public class Tests { [Fact] - public async Task Test() + public async ValueTask Test() { using var container = new Container(); var instance = await container.Create0().ConfigureAwait(false); diff --git a/Test/Async/WrappedDependency/ValueTaskToTask.cs b/Test/Async/WrappedDependency/ValueTaskToTask.cs index 1fa3becc..f89a92c0 100644 --- a/Test/Async/WrappedDependency/ValueTaskToTask.cs +++ b/Test/Async/WrappedDependency/ValueTaskToTask.cs @@ -24,7 +24,7 @@ internal partial class Container public class Tests { [Fact] - public async Task Test() + public async ValueTask Test() { using var container = new Container(); var instance = await container.Create0().ConfigureAwait(false); diff --git a/Test/Async/WrappedDependency/ValueTaskToValueTask.cs b/Test/Async/WrappedDependency/ValueTaskToValueTask.cs index 0eb31139..99c651c3 100644 --- a/Test/Async/WrappedDependency/ValueTaskToValueTask.cs +++ b/Test/Async/WrappedDependency/ValueTaskToValueTask.cs @@ -24,7 +24,7 @@ internal partial class Container public class Tests { [Fact] - public async Task Test() + public async ValueTask Test() { using var container = new Container(); var instance = await container.Create0().ConfigureAwait(false); From a3fea7778dcce4d4b7baa4bbe9c6fb4ce90430d9 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Thu, 31 Mar 2022 23:25:26 +0200 Subject: [PATCH 055/162] Adjustments to tests --- Test/Async/Awaited/TaskTypeInitializerTask.cs | 4 ++-- Test/Async/Awaited/TaskTypeInitializerValueTask.cs | 4 ++-- Test/Async/WrappedDependency/DecorationChaining.cs | 4 ++-- Test/Async/WrappedDependency/Func.cs | 4 ++-- Test/Async/WrappedDependency/Lazy.cs | 4 ++-- Test/Async/WrappedDependency/SyncToTask.cs | 4 ++-- Test/Async/WrappedDependency/SyncToValueTask.cs | 4 ++-- Test/Async/WrappedDependency/TaskCollection.cs | 4 ++-- Test/Async/WrappedDependency/TaskComposition.cs | 4 ++-- Test/Async/WrappedDependency/TaskToTask.cs | 4 ++-- Test/Async/WrappedDependency/TaskToValueTask.cs | 4 ++-- Test/Async/WrappedDependency/ValueTaskCollection.cs | 4 ++-- Test/Async/WrappedDependency/ValueTaskComposition.cs | 4 ++-- Test/Async/WrappedDependency/ValueTaskToTask.cs | 4 ++-- Test/Async/WrappedDependency/ValueTaskToValueTask.cs | 4 ++-- Test/ConstructorChoiceTests.cs | 4 ++-- Test/ConstructorTests.cs | 4 ++-- Test/Func/Vanilla.cs | 4 ++-- Test/ImplementationAggregationTests.cs | 4 ++-- Test/InstanceTests.cs | 4 ++-- Test/Lazy/Vanilla.cs | 4 ++-- Test/PropertyTests.cs | 4 ++-- 22 files changed, 44 insertions(+), 44 deletions(-) diff --git a/Test/Async/Awaited/TaskTypeInitializerTask.cs b/Test/Async/Awaited/TaskTypeInitializerTask.cs index 3a14b3cd..a1198c53 100644 --- a/Test/Async/Awaited/TaskTypeInitializerTask.cs +++ b/Test/Async/Awaited/TaskTypeInitializerTask.cs @@ -16,7 +16,7 @@ async Task ITaskTypeInitializer.InitializeAsync() } } -[CreateFunction(typeof(Dependency), "CreateDep")] +[CreateFunction(typeof(Dependency), "Create")] internal partial class Container { } @@ -27,7 +27,7 @@ public class Tests public async ValueTask Test() { using var container = new Container(); - var instance = await container.CreateDepAsync().ConfigureAwait(false); + var instance = await container.CreateAsync().ConfigureAwait(false); Assert.True(instance.IsInitialized); } } \ No newline at end of file diff --git a/Test/Async/Awaited/TaskTypeInitializerValueTask.cs b/Test/Async/Awaited/TaskTypeInitializerValueTask.cs index 9f962b54..e6aed65d 100644 --- a/Test/Async/Awaited/TaskTypeInitializerValueTask.cs +++ b/Test/Async/Awaited/TaskTypeInitializerValueTask.cs @@ -16,7 +16,7 @@ async ValueTask IValueTaskTypeInitializer.InitializeAsync() } } -[CreateFunction(typeof(Dependency), "CreateDep")] +[CreateFunction(typeof(Dependency), "Create")] internal partial class Container { } @@ -27,7 +27,7 @@ public class Tests public async ValueTask Test() { using var container = new Container(); - var instance = await container.CreateDepAsync().ConfigureAwait(false); + var instance = await container.CreateAsync().ConfigureAwait(false); Assert.True(instance.IsInitialized); } } \ No newline at end of file diff --git a/Test/Async/WrappedDependency/DecorationChaining.cs b/Test/Async/WrappedDependency/DecorationChaining.cs index 89a5bd55..779db96d 100644 --- a/Test/Async/WrappedDependency/DecorationChaining.cs +++ b/Test/Async/WrappedDependency/DecorationChaining.cs @@ -47,7 +47,7 @@ async ValueTask IValueTaskTypeInitializer.InitializeAsync() } } -[CreateFunction(typeof(Task), "CreateDep")] +[CreateFunction(typeof(Task), "Create")] [DecoratorSequenceChoice(typeof(IInterface), typeof(DecoratorA), typeof(DecoratorB))] internal partial class Container { @@ -59,7 +59,7 @@ public class Tests public async ValueTask Test() { using var container = new Container(); - var instance = await container.CreateDep().ConfigureAwait(false); + var instance = await container.Create().ConfigureAwait(false); Assert.True(instance.IsInitialized); } } \ No newline at end of file diff --git a/Test/Async/WrappedDependency/Func.cs b/Test/Async/WrappedDependency/Func.cs index c7a42e8b..dd497ad7 100644 --- a/Test/Async/WrappedDependency/Func.cs +++ b/Test/Async/WrappedDependency/Func.cs @@ -17,7 +17,7 @@ async Task ITaskTypeInitializer.InitializeAsync() } } -[CreateFunction(typeof(Func>), "CreateDep")] +[CreateFunction(typeof(Func>), "Create")] internal partial class Container { } @@ -28,7 +28,7 @@ public class Tests public async ValueTask Test() { using var container = new Container(); - var instance = container.CreateDep(); + var instance = container.Create(); Assert.True((await instance().ConfigureAwait(false)).IsInitialized); } } \ No newline at end of file diff --git a/Test/Async/WrappedDependency/Lazy.cs b/Test/Async/WrappedDependency/Lazy.cs index b7457489..e3fccb9d 100644 --- a/Test/Async/WrappedDependency/Lazy.cs +++ b/Test/Async/WrappedDependency/Lazy.cs @@ -18,7 +18,7 @@ async Task ITaskTypeInitializer.InitializeAsync() } } -[CreateFunction(typeof(Lazy>), "CreateDep")] +[CreateFunction(typeof(Lazy>), "Create")] internal partial class Container { } @@ -29,7 +29,7 @@ public class Tests public async ValueTask Test() { using var container = new Container(); - var instance = container.CreateDep(); + var instance = container.Create(); Assert.True((await instance.Value.ConfigureAwait(false)).IsInitialized); } } \ No newline at end of file diff --git a/Test/Async/WrappedDependency/SyncToTask.cs b/Test/Async/WrappedDependency/SyncToTask.cs index e5ab287f..bc25e21a 100644 --- a/Test/Async/WrappedDependency/SyncToTask.cs +++ b/Test/Async/WrappedDependency/SyncToTask.cs @@ -14,7 +14,7 @@ void ITypeInitializer.Initialize() } } -[CreateFunction(typeof(Task), "CreateDep")] +[CreateFunction(typeof(Task), "Create")] internal partial class Container { } @@ -25,7 +25,7 @@ public class Tests public async ValueTask Test() { using var container = new Container(); - var instance = await container.CreateDep().ConfigureAwait(false); + var instance = await container.Create().ConfigureAwait(false); Assert.True(instance.IsInitialized); } } \ No newline at end of file diff --git a/Test/Async/WrappedDependency/SyncToValueTask.cs b/Test/Async/WrappedDependency/SyncToValueTask.cs index 3079c17c..9fea057f 100644 --- a/Test/Async/WrappedDependency/SyncToValueTask.cs +++ b/Test/Async/WrappedDependency/SyncToValueTask.cs @@ -15,7 +15,7 @@ void ITypeInitializer.Initialize() } } -[CreateFunction(typeof(ValueTask), "CreateDep")] +[CreateFunction(typeof(ValueTask), "Create")] internal partial class Container { } @@ -26,7 +26,7 @@ public class Tests public async ValueTask Test() { using var container = new Container(); - var instance = await container.CreateDep().ConfigureAwait(false); + var instance = await container.Create().ConfigureAwait(false); Assert.True(instance.IsInitialized); } } \ No newline at end of file diff --git a/Test/Async/WrappedDependency/TaskCollection.cs b/Test/Async/WrappedDependency/TaskCollection.cs index 52aa56bf..38911e99 100644 --- a/Test/Async/WrappedDependency/TaskCollection.cs +++ b/Test/Async/WrappedDependency/TaskCollection.cs @@ -47,7 +47,7 @@ internal class DependencyD : IInterface public bool IsInitialized => true; } -[CreateFunction(typeof(IReadOnlyList>), "CreateDep")] +[CreateFunction(typeof(IReadOnlyList>), "Create")] internal partial class Container { } @@ -58,7 +58,7 @@ public class Tests public async ValueTask Test() { using var container = new Container(); - var instance = container.CreateDep(); + var instance = container.Create(); Assert.Equal(4, instance.Count); await Task.WhenAll(instance).ConfigureAwait(false); foreach (var task in instance) diff --git a/Test/Async/WrappedDependency/TaskComposition.cs b/Test/Async/WrappedDependency/TaskComposition.cs index 21bdff96..60f3e4a3 100644 --- a/Test/Async/WrappedDependency/TaskComposition.cs +++ b/Test/Async/WrappedDependency/TaskComposition.cs @@ -66,7 +66,7 @@ public async Task InitializeAsync() public int Count => _composition.Count; } -[CreateFunction(typeof(Task), "CreateDep")] +[CreateFunction(typeof(Task), "Create")] internal partial class Container { } @@ -77,7 +77,7 @@ public class Tests public async ValueTask Test() { using var container = new Container(); - var instance = await container.CreateDep().ConfigureAwait(false); + var instance = await container.Create().ConfigureAwait(false); Assert.IsType(instance); Assert.Equal(4, ((Composite) instance).Count); Assert.True(instance.IsInitialized); diff --git a/Test/Async/WrappedDependency/TaskToTask.cs b/Test/Async/WrappedDependency/TaskToTask.cs index 26ffc9b4..6fa4b787 100644 --- a/Test/Async/WrappedDependency/TaskToTask.cs +++ b/Test/Async/WrappedDependency/TaskToTask.cs @@ -15,7 +15,7 @@ async Task ITaskTypeInitializer.InitializeAsync() IsInitialized = true; } } -[CreateFunction(typeof(Task), "CreateDep")] +[CreateFunction(typeof(Task), "Create")] internal partial class Container { } @@ -26,7 +26,7 @@ public class Tests public async ValueTask Test() { using var container = new Container(); - var instance = await container.CreateDep().ConfigureAwait(false); + var instance = await container.Create().ConfigureAwait(false); Assert.True(instance.IsInitialized); } } \ No newline at end of file diff --git a/Test/Async/WrappedDependency/TaskToValueTask.cs b/Test/Async/WrappedDependency/TaskToValueTask.cs index 54ded479..50ab5b7d 100644 --- a/Test/Async/WrappedDependency/TaskToValueTask.cs +++ b/Test/Async/WrappedDependency/TaskToValueTask.cs @@ -16,7 +16,7 @@ async Task ITaskTypeInitializer.InitializeAsync() } } -[CreateFunction(typeof(ValueTask), "CreateDep")] +[CreateFunction(typeof(ValueTask), "Create")] internal partial class Container { } @@ -27,7 +27,7 @@ public class Tests public async ValueTask Test() { using var container = new Container(); - var instance = await container.CreateDep().ConfigureAwait(false); + var instance = await container.Create().ConfigureAwait(false); Assert.True(instance.IsInitialized); } } \ No newline at end of file diff --git a/Test/Async/WrappedDependency/ValueTaskCollection.cs b/Test/Async/WrappedDependency/ValueTaskCollection.cs index d57884d2..5a05f471 100644 --- a/Test/Async/WrappedDependency/ValueTaskCollection.cs +++ b/Test/Async/WrappedDependency/ValueTaskCollection.cs @@ -47,7 +47,7 @@ internal class DependencyD : IInterface public bool IsInitialized => true; } -[CreateFunction(typeof(IReadOnlyList>), "Create0")] +[CreateFunction(typeof(IReadOnlyList>), "Create")] internal partial class Container { } @@ -58,7 +58,7 @@ public class Tests public async ValueTask Test() { using var container = new Container(); - var instance = container.Create0(); + var instance = container.Create(); Assert.Equal(4, instance.Count); foreach (var task in instance) Assert.True((await task.ConfigureAwait(false)).IsInitialized); diff --git a/Test/Async/WrappedDependency/ValueTaskComposition.cs b/Test/Async/WrappedDependency/ValueTaskComposition.cs index f220d469..0ce325d0 100644 --- a/Test/Async/WrappedDependency/ValueTaskComposition.cs +++ b/Test/Async/WrappedDependency/ValueTaskComposition.cs @@ -67,7 +67,7 @@ public async Task InitializeAsync() public int Count => _composition.Count; } -[CreateFunction(typeof(ValueTask), "Create0")] +[CreateFunction(typeof(ValueTask), "Create")] internal partial class Container { } @@ -78,7 +78,7 @@ public class Tests public async ValueTask Test() { using var container = new Container(); - var instance = await container.Create0().ConfigureAwait(false); + var instance = await container.Create().ConfigureAwait(false); Assert.IsType(instance); Assert.Equal(4, ((Composite) instance).Count); Assert.True(instance.IsInitialized); diff --git a/Test/Async/WrappedDependency/ValueTaskToTask.cs b/Test/Async/WrappedDependency/ValueTaskToTask.cs index f89a92c0..43d6efb6 100644 --- a/Test/Async/WrappedDependency/ValueTaskToTask.cs +++ b/Test/Async/WrappedDependency/ValueTaskToTask.cs @@ -16,7 +16,7 @@ async ValueTask IValueTaskTypeInitializer.InitializeAsync() } } -[CreateFunction(typeof(Task), "Create0")] +[CreateFunction(typeof(Task), "Create")] internal partial class Container { } @@ -27,7 +27,7 @@ public class Tests public async ValueTask Test() { using var container = new Container(); - var instance = await container.Create0().ConfigureAwait(false); + var instance = await container.Create().ConfigureAwait(false); Assert.True(instance.IsInitialized); } } \ No newline at end of file diff --git a/Test/Async/WrappedDependency/ValueTaskToValueTask.cs b/Test/Async/WrappedDependency/ValueTaskToValueTask.cs index 99c651c3..4229e442 100644 --- a/Test/Async/WrappedDependency/ValueTaskToValueTask.cs +++ b/Test/Async/WrappedDependency/ValueTaskToValueTask.cs @@ -16,7 +16,7 @@ async ValueTask IValueTaskTypeInitializer.InitializeAsync() } } -[CreateFunction(typeof(ValueTask), "Create0")] +[CreateFunction(typeof(ValueTask), "Create")] internal partial class Container { } @@ -27,7 +27,7 @@ public class Tests public async ValueTask Test() { using var container = new Container(); - var instance = await container.Create0().ConfigureAwait(false); + var instance = await container.Create().ConfigureAwait(false); Assert.True(instance.IsInitialized); } } \ No newline at end of file diff --git a/Test/ConstructorChoiceTests.cs b/Test/ConstructorChoiceTests.cs index 59df9570..72736e54 100644 --- a/Test/ConstructorChoiceTests.cs +++ b/Test/ConstructorChoiceTests.cs @@ -7,7 +7,7 @@ namespace MrMeeseeks.DIE.Test; -[CreateFunction(typeof(DateTime), "CreateDep")] +[CreateFunction(typeof(DateTime), "Create")] internal partial class ConstructorChoiceContainer { @@ -19,7 +19,7 @@ public class ImplementationAggregationTests public void ResolveExternalType() { using var container = new ConstructorChoiceContainer(); - var dateTime = container.CreateDep(); + var dateTime = container.Create(); Assert.Equal(DateTime.MinValue, dateTime); } } \ No newline at end of file diff --git a/Test/ConstructorTests.cs b/Test/ConstructorTests.cs index b41d4d9d..b79ae3b7 100644 --- a/Test/ConstructorTests.cs +++ b/Test/ConstructorTests.cs @@ -17,7 +17,7 @@ internal class ConstructorInit : IConstructorInit public IConstructorInitDependency? Dependency { get; init; } } -[CreateFunction(typeof(IConstructorInit), "CreateDep")] +[CreateFunction(typeof(IConstructorInit), "Create")] internal partial class ConstructorInitContainer { } @@ -28,7 +28,7 @@ public class ConstructorsTests public void ResolveInitProperty() { using var container = new ConstructorInitContainer(); - var resolution = container.CreateDep(); + var resolution = container.Create(); Assert.NotNull(resolution.Dependency); Assert.IsType(resolution.Dependency); } diff --git a/Test/Func/Vanilla.cs b/Test/Func/Vanilla.cs index 931a1a3a..fd934512 100644 --- a/Test/Func/Vanilla.cs +++ b/Test/Func/Vanilla.cs @@ -7,7 +7,7 @@ namespace MrMeeseeks.DIE.Test.Func.Vanilla; internal class Dependency{} -[CreateFunction(typeof(Func, Dependency>), "CreateDep")] +[CreateFunction(typeof(Func, Dependency>), "Create")] internal partial class Container { } @@ -18,6 +18,6 @@ public class Tests public void Test() { using var container = new Container(); - var _ = container.CreateDep()(DateTime.Now, new List()); + var _ = container.Create()(DateTime.Now, new List()); } } diff --git a/Test/ImplementationAggregationTests.cs b/Test/ImplementationAggregationTests.cs index 2a2b4a4b..a6af72f7 100644 --- a/Test/ImplementationAggregationTests.cs +++ b/Test/ImplementationAggregationTests.cs @@ -7,7 +7,7 @@ namespace MrMeeseeks.DIE.Test; -[CreateFunction(typeof(Func), "CreateDep")] +[CreateFunction(typeof(Func), "Create")] internal partial class ImplementationAggregationContainer { @@ -20,7 +20,7 @@ public void ResolveExternalType() { using var container = new ImplementationAggregationContainer(); var path = @"C:\HelloWorld.txt"; - var fileInfo = container.CreateDep()(path); + var fileInfo = container.Create()(path); Assert.NotNull(fileInfo); Assert.IsType(fileInfo); Assert.Equal(path, fileInfo.FullName); diff --git a/Test/InstanceTests.cs b/Test/InstanceTests.cs index 48e660e4..4dc25eeb 100644 --- a/Test/InstanceTests.cs +++ b/Test/InstanceTests.cs @@ -17,7 +17,7 @@ public InstanceClass(string dependency) Dependency = dependency; } } -[CreateFunction(typeof(IInstanceClass), "CreateDep")] +[CreateFunction(typeof(IInstanceClass), "Create")] internal partial class InstanceContainer { private readonly string DIE_Dependency; @@ -32,7 +32,7 @@ public void ResolveExternalType() { var check = "Hello, instance!"; using var container = new InstanceContainer(check); - var instanceClass = container.CreateDep(); + var instanceClass = container.Create(); Assert.Equal(check, instanceClass.Dependency); } } \ No newline at end of file diff --git a/Test/Lazy/Vanilla.cs b/Test/Lazy/Vanilla.cs index aae08c84..338421c7 100644 --- a/Test/Lazy/Vanilla.cs +++ b/Test/Lazy/Vanilla.cs @@ -6,7 +6,7 @@ namespace MrMeeseeks.DIE.Test.Lazy.Vanilla; internal class Dependency{} -[CreateFunction(typeof(Lazy), "CreateDep")] +[CreateFunction(typeof(Lazy), "Create")] internal partial class Container { } @@ -17,7 +17,7 @@ public class Tests public void Test() { using var container = new Container(); - var lazy = container.CreateDep(); + var lazy = container.Create(); var _ = lazy.Value; } } diff --git a/Test/PropertyTests.cs b/Test/PropertyTests.cs index 94d55ffd..7a0f1af0 100644 --- a/Test/PropertyTests.cs +++ b/Test/PropertyTests.cs @@ -19,7 +19,7 @@ public PropertyClass(string dependency) } } -[CreateFunction(typeof(IPropertyClass), "CreateDep")] +[CreateFunction(typeof(IPropertyClass), "Create")] internal partial class PropertyContainer { private string DIE_Dependency { get; } @@ -34,7 +34,7 @@ public void ResolveExternalType() { var check = "Hello, Property!"; using var container = new PropertyContainer(check); - var propertyClass = container.CreateDep(); + var propertyClass = container.Create(); Assert.Equal(check, propertyClass.Dependency); } } \ No newline at end of file From f140d760ef9d3c3ee996e017ce6cefede21d448f Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sat, 2 Apr 2022 15:48:39 +0200 Subject: [PATCH 056/162] Decorators and Composites having at most Scope level --- .../FunctionResolutionBuilder.cs | 14 ++- Sample/Context.cs | 65 +++++++--- Sample/Program.cs | 4 +- .../ScopeDecoratorForContainerDependency.cs | 65 ++++++++++ ...opeDecoratorForTransientScopeDependency.cs | 65 ++++++++++ Test/Decorator/SequenceEdgeCase.cs | 117 ++++++++++++++++++ 6 files changed, 307 insertions(+), 23 deletions(-) create mode 100644 Test/Decorator/ScopeDecoratorForContainerDependency.cs create mode 100644 Test/Decorator/ScopeDecoratorForTransientScopeDependency.cs create mode 100644 Test/Decorator/SequenceEdgeCase.cs diff --git a/Main/ResolutionBuilding/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/FunctionResolutionBuilder.cs index 0f0264bd..fea9cc8a 100644 --- a/Main/ResolutionBuilding/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/FunctionResolutionBuilder.cs @@ -904,10 +904,16 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup var ret = scopeLevel switch { - ScopeLevel.Container => (_rangeResolutionBaseBuilder.CreateContainerInstanceReferenceResolution(nextParameter), null), - ScopeLevel.TransientScope => (_rangeResolutionBaseBuilder.CreateTransientScopeInstanceReferenceResolution(nextParameter), null), - ScopeLevel.Scope => (_rangeResolutionBaseBuilder.CreateScopeInstanceReferenceResolution(nextParameter), null), - _ => CreateConstructorResolution(nextParameter) + >= ScopeLevel.Scope when parameter is SwitchImplementationParameterWithDecoration or SwitchImplementationParameterWithDecoration => + (_rangeResolutionBaseBuilder.CreateScopeInstanceReferenceResolution(nextParameter), null), + ScopeLevel.Container => + (_rangeResolutionBaseBuilder.CreateContainerInstanceReferenceResolution(nextParameter), null), + ScopeLevel.TransientScope => + (_rangeResolutionBaseBuilder.CreateTransientScopeInstanceReferenceResolution(nextParameter), null), + ScopeLevel.Scope => + (_rangeResolutionBaseBuilder.CreateScopeInstanceReferenceResolution(nextParameter), null), + _ => + CreateConstructorResolution(nextParameter) }; if (ret.Item1 is IAwaitableResolution awaitableResolution) diff --git a/Sample/Context.cs b/Sample/Context.cs index 5a381e79..03bb7a7e 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -1,31 +1,62 @@ -using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration; using MrMeeseeks.DIE.Sample; -namespace MrMeeseeks.DIE.Test.Async.Awaited.AsyncFunctionCallAsTask; +namespace MrMeeseeks.DIE.Test.Decorator.SequenceEdgeCase; +internal interface IInterface +{ + IInterface Decorated { get; } +} + +internal class Dependency : IInterface, IContainerInstance +{ + public IInterface Decorated => this; +} -internal class Dependency : ITaskTypeInitializer +internal class DecoratorA : IInterface, IDecorator { - public bool IsInitialized { get; private set; } + public IInterface Decorated { get; } - async Task ITaskTypeInitializer.InitializeAsync() - { - await Task.Delay(500).ConfigureAwait(false); - IsInitialized = true; - } + internal DecoratorA(IInterface decorated) => Decorated = decorated; } -internal class ScopeRoot : IScopeRoot +internal class DecoratorB : IInterface, IDecorator { - public Dependency Dep { get; } - internal ScopeRoot(Dependency dep) - { - Dep = dep; - } + public IInterface Decorated { get; } + + internal DecoratorB(IInterface decorated) => Decorated = decorated; } -[CreateFunction(typeof(Task), "Create")] +internal class ScopeRoot0 : IScopeRoot +{ + public IInterface Decorated { get; } + + internal ScopeRoot0(IInterface decorated) => Decorated = decorated; +} + +internal class ScopeRoot1 : IScopeRoot +{ + public IInterface Decorated { get; } + + internal ScopeRoot1(IInterface decorated) => Decorated = decorated; +} + +[CreateFunction(typeof(ScopeRoot0), "Create0")] +[CreateFunction(typeof(ScopeRoot1), "Create1")] +[DecoratorSequenceChoice(typeof(IInterface), typeof(DecoratorA), typeof(DecoratorB))] internal partial class Container { + [DecoratorSequenceChoice(typeof(IInterface), typeof(DecoratorA), typeof(DecoratorB))] + [CustomScopeForRootTypes(typeof(ScopeRoot0))] + private partial class DIE_Scope_0 + { + + } + + [DecoratorSequenceChoice(typeof(IInterface), typeof(DecoratorA))] + [CustomScopeForRootTypes(typeof(ScopeRoot1))] + private partial class DIE_Scope_1 + { + + } } \ No newline at end of file diff --git a/Sample/Program.cs b/Sample/Program.cs index 87deb416..18bac0cb 100644 --- a/Sample/Program.cs +++ b/Sample/Program.cs @@ -1,5 +1,5 @@ using System; -using MrMeeseeks.DIE.Test.Async.Awaited.AsyncFunctionCallAsTask; +using MrMeeseeks.DIE.Test.Decorator.SequenceEdgeCase; internal class Program { @@ -7,6 +7,6 @@ private static void Main() { Console.WriteLine("Hello, world!"); var container = new Container(); - Console.WriteLine(container.CreateAsync()); + Console.WriteLine(container.Create0Async()); } } \ No newline at end of file diff --git a/Test/Decorator/ScopeDecoratorForContainerDependency.cs b/Test/Decorator/ScopeDecoratorForContainerDependency.cs new file mode 100644 index 00000000..06ba84ff --- /dev/null +++ b/Test/Decorator/ScopeDecoratorForContainerDependency.cs @@ -0,0 +1,65 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Decorator.ScopeDecoratorForContainerDependency; + +internal interface IInterface +{ + IInterface Decorated { get; } +} + +internal class Dependency : IInterface, IContainerInstance +{ + public IInterface Decorated => this; +} + +internal class Decorator : IInterface, IDecorator +{ + public IInterface Decorated { get; } + + internal Decorator(IInterface decorated) => Decorated = decorated; +} + +internal class ScopeRoot : IScopeRoot +{ + public IInterface Decorated { get; } + public IInterface SecondDecorator { get; } + + internal ScopeRoot(IInterface decorated, IInterface secondDecorator) + { + Decorated = decorated; + SecondDecorator = secondDecorator; + } +} + +[CreateFunction(typeof(ScopeRoot), "Create")] +internal partial class Container +{ +} + +public class Tests +{ + [Fact] + public void Test() + { + using var container = new Container(); + + var scopeRoot0 = container.Create(); + var decorator0 = scopeRoot0.Decorated; + var dependency0 = decorator0.Decorated; + + var scopeRoot1 = container.Create(); + var decorator1 = scopeRoot1.Decorated; + var dependency1 = decorator1.Decorated; + + Assert.IsType(decorator0); + Assert.IsType(decorator1); + Assert.IsType(dependency0); + Assert.IsType(dependency1); + + Assert.NotSame(decorator0, decorator1); + Assert.Same(dependency0, dependency1); + Assert.Same(decorator0, scopeRoot0.SecondDecorator); + Assert.Same(decorator1, scopeRoot1.SecondDecorator); + } +} \ No newline at end of file diff --git a/Test/Decorator/ScopeDecoratorForTransientScopeDependency.cs b/Test/Decorator/ScopeDecoratorForTransientScopeDependency.cs new file mode 100644 index 00000000..e028e9ce --- /dev/null +++ b/Test/Decorator/ScopeDecoratorForTransientScopeDependency.cs @@ -0,0 +1,65 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Decorator.ScopeDecoratorForTransientScopeDependency; + +internal interface IInterface +{ + IInterface Decorated { get; } +} + +internal class Dependency : IInterface, ITransientScopeInstance +{ + public IInterface Decorated => this; +} + +internal class Decorator : IInterface, IDecorator +{ + public IInterface Decorated { get; } + + internal Decorator(IInterface decorated) => Decorated = decorated; +} + +internal class ScopeRoot : IScopeRoot +{ + public IInterface Decorated { get; } + public IInterface SecondDecorator { get; } + + internal ScopeRoot(IInterface decorated, IInterface secondDecorator) + { + Decorated = decorated; + SecondDecorator = secondDecorator; + } +} + +[CreateFunction(typeof(ScopeRoot), "Create")] +internal partial class Container +{ +} + +public class Tests +{ + [Fact] + public void Test() + { + using var container = new Container(); + + var scopeRoot0 = container.Create(); + var decorator0 = scopeRoot0.Decorated; + var dependency0 = decorator0.Decorated; + + var scopeRoot1 = container.Create(); + var decorator1 = scopeRoot1.Decorated; + var dependency1 = decorator1.Decorated; + + Assert.IsType(decorator0); + Assert.IsType(decorator1); + Assert.IsType(dependency0); + Assert.IsType(dependency1); + + Assert.NotSame(decorator0, decorator1); + Assert.Same(dependency0, dependency1); + Assert.Same(decorator0, scopeRoot0.SecondDecorator); + Assert.Same(decorator1, scopeRoot1.SecondDecorator); + } +} \ No newline at end of file diff --git a/Test/Decorator/SequenceEdgeCase.cs b/Test/Decorator/SequenceEdgeCase.cs new file mode 100644 index 00000000..e5912901 --- /dev/null +++ b/Test/Decorator/SequenceEdgeCase.cs @@ -0,0 +1,117 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Decorator.SequenceEdgeCase; + +internal interface IInterface +{ + IInterface Decorated { get; } +} + +internal class Dependency : IInterface, IContainerInstance +{ + public IInterface Decorated => this; +} + +internal class DecoratorA : IInterface, IDecorator +{ + public IInterface Decorated { get; } + + internal DecoratorA(IInterface decorated) => Decorated = decorated; +} + +internal class DecoratorB : IInterface, IDecorator +{ + public IInterface Decorated { get; } + + internal DecoratorB(IInterface decorated) => Decorated = decorated; +} + +internal class ScopeRoot0 : IScopeRoot +{ + public IInterface Decorated { get; } + + internal ScopeRoot0(IInterface decorated) => Decorated = decorated; +} + +internal class ScopeRoot1 : IScopeRoot +{ + public IInterface Decorated { get; } + + internal ScopeRoot1(IInterface decorated) => Decorated = decorated; +} + +[CreateFunction(typeof(ScopeRoot0), "Create0")] +[CreateFunction(typeof(ScopeRoot1), "Create1")] +[CreateFunction(typeof(IInterface), "CreateFromContainerAsSanityCheck")] +[DecoratorSequenceChoice(typeof(IInterface))] +internal partial class Container +{ + [DecoratorSequenceChoice(typeof(IInterface), typeof(DecoratorA), typeof(DecoratorB))] + [CustomScopeForRootTypes(typeof(ScopeRoot0))] + private partial class DIE_Scope_0 + { + + } + + [DecoratorSequenceChoice(typeof(IInterface), typeof(DecoratorA))] + [CustomScopeForRootTypes(typeof(ScopeRoot1))] + private partial class DIE_Scope_1 + { + + } +} + +public class Tests +{ + [Fact] + public void Test() + { + using var container0Then1 = new Container(); + + var _0Then1_0_2 = container0Then1.Create0().Decorated; + var _0Then1_0_1 = _0Then1_0_2.Decorated; + var _0Then1_0_0 = _0Then1_0_1.Decorated; + + var _0Then1_1_1 = container0Then1.Create1().Decorated; + var _0Then1_1_0 = _0Then1_1_1.Decorated; + + var _0Then1_SanityCheck = container0Then1.CreateFromContainerAsSanityCheck(); + + Assert.IsType(_0Then1_0_2); + Assert.IsType(_0Then1_0_1); + Assert.IsType(_0Then1_0_0); + + Assert.IsType(_0Then1_1_1); + Assert.IsType(_0Then1_1_0); + + Assert.IsType(_0Then1_SanityCheck); + + Assert.Same(_0Then1_1_0, _0Then1_0_0); + Assert.Same(_0Then1_1_0, _0Then1_SanityCheck); + + + using var container1Then0 = new Container(); + + var _1Then0_1_1 = container1Then0.Create1().Decorated; + var _1Then0_1_0 = _1Then0_1_1.Decorated; + + var _1Then0_0_2 = container1Then0.Create0().Decorated; + var _1Then0_0_1 = _1Then0_0_2.Decorated; + var _1Then0_0_0 = _1Then0_0_1.Decorated; + + var _1Then0_SanityCheck = container1Then0.CreateFromContainerAsSanityCheck(); + + Assert.IsType(_1Then0_0_2); + Assert.IsType(_1Then0_0_1); + Assert.IsType(_1Then0_0_0); + + Assert.IsType(_1Then0_1_1); + Assert.IsType(_1Then0_1_0); + + Assert.IsType(_1Then0_SanityCheck); + + Assert.Same(_1Then0_1_0, _1Then0_0_0); + Assert.Same(_1Then0_1_0, _1Then0_SanityCheck); + } +} \ No newline at end of file From 6bb2d44c9aeaa415e3fe4c27a911d665c3d4764d Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sat, 2 Apr 2022 17:16:57 +0200 Subject: [PATCH 057/162] Refactoring Function resolution building code --- Main/CodeBuilding/RangeCodeBaseBuilder.cs | 1 + .../ContainerResolutionBuilder.cs | 1 + ...ontainerCreateFunctionResolutionBuilder.cs | 58 +++++ .../FunctionResolutionBuilder.cs | 244 +----------------- .../LocalFunctionResolutionBuilder.cs | 59 +++++ .../RangedFunctionResolutionBuilder.cs | 58 +++++ ...copeRootCreateFunctionResolutionBuilder.cs | 63 +++++ .../RangedFunctionResolutionBuilderManager.cs | 2 + .../ScopeResolutionBuilder.cs | 1 + ...ransientScopeInterfaceResolutionBuilder.cs | 2 + .../TransientScopeResolutionBuilder.cs | 1 + Main/ResolutionTreeItem.cs | 1 + Main/SourceGenerator.cs | 1 + 13 files changed, 253 insertions(+), 239 deletions(-) create mode 100644 Main/ResolutionBuilding/Function/ContainerCreateFunctionResolutionBuilder.cs rename Main/ResolutionBuilding/{ => Function}/FunctionResolutionBuilder.cs (82%) create mode 100644 Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs create mode 100644 Main/ResolutionBuilding/Function/RangedFunctionResolutionBuilder.cs create mode 100644 Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs diff --git a/Main/CodeBuilding/RangeCodeBaseBuilder.cs b/Main/CodeBuilding/RangeCodeBaseBuilder.cs index 5eacf8b3..26abb4f4 100644 --- a/Main/CodeBuilding/RangeCodeBaseBuilder.cs +++ b/Main/CodeBuilding/RangeCodeBaseBuilder.cs @@ -1,4 +1,5 @@ using MrMeeseeks.DIE.ResolutionBuilding; +using MrMeeseeks.DIE.ResolutionBuilding.Function; namespace MrMeeseeks.DIE.CodeBuilding; diff --git a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs index 02853d77..e6da694c 100644 --- a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs @@ -1,4 +1,5 @@ using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.ResolutionBuilding.Function; namespace MrMeeseeks.DIE.ResolutionBuilding; diff --git a/Main/ResolutionBuilding/Function/ContainerCreateFunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/ContainerCreateFunctionResolutionBuilder.cs new file mode 100644 index 00000000..d8b7d14b --- /dev/null +++ b/Main/ResolutionBuilding/Function/ContainerCreateFunctionResolutionBuilder.cs @@ -0,0 +1,58 @@ +namespace MrMeeseeks.DIE.ResolutionBuilding.Function; + +internal interface IContainerCreateFunctionResolutionBuilder : IFunctionResolutionBuilder +{ +} + +internal class ContainerCreateFunctionResolutionBuilder : FunctionResolutionBuilder, IContainerCreateFunctionResolutionBuilder +{ + private readonly IRangeResolutionBaseBuilder _rangeResolutionBaseBuilder; + private readonly INamedTypeSymbol _returnType; + + public ContainerCreateFunctionResolutionBuilder( + // parameter + IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, + INamedTypeSymbol returnType, + + + // dependencies + WellKnownTypes wellKnownTypes, + IReferenceGeneratorFactory referenceGeneratorFactory, + Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) + : base(rangeResolutionBaseBuilder, returnType, Array.Empty<(ITypeSymbol, ParameterResolution)>(), wellKnownTypes, referenceGeneratorFactory, localFunctionResolutionBuilderFactory) + { + _rangeResolutionBaseBuilder = rangeResolutionBaseBuilder; + _returnType = returnType; + + Name = RootReferenceGenerator.Generate("Create"); + } + + protected override string Name { get; } + + protected override Resolvable CreateResolvable() => SwitchType(new SwitchTypeParameter( + _returnType, + Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>())).Item1; + + public override FunctionResolution Build() + { + AdjustForSynchronicity(); + return new( + Name, + TypeFullName, + Resolvable.Value, + Array.Empty(), + _rangeResolutionBaseBuilder.DisposalHandling, + LocalFunctions + .Select(lf => lf.Build()) + .Select(f => new LocalFunctionResolution( + f.Reference, + f.TypeFullName, + f.Resolvable, + f.Parameter, + f.DisposalHandling, + f.LocalFunctions, + f.SynchronicityDecision)) + .ToList(), + SynchronicityDecision.Value); + } +} \ No newline at end of file diff --git a/Main/ResolutionBuilding/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs similarity index 82% rename from Main/ResolutionBuilding/FunctionResolutionBuilder.cs rename to Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs index fea9cc8a..a3498882 100644 --- a/Main/ResolutionBuilding/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs @@ -1,6 +1,6 @@ using MrMeeseeks.DIE.Configuration; -namespace MrMeeseeks.DIE.ResolutionBuilding; +namespace MrMeeseeks.DIE.ResolutionBuilding.Function; internal enum SynchronicityDecision { @@ -22,240 +22,6 @@ MultiSynchronicityFunctionCallResolution BuildFunctionCall( MethodGroupResolution BuildMethodGroup(); } -internal interface ILocalFunctionResolutionBuilder : IFunctionResolutionBuilder -{ -} - -internal class LocalFunctionResolutionBuilder : FunctionResolutionBuilder, ILocalFunctionResolutionBuilder -{ - private readonly IRangeResolutionBaseBuilder _rangeResolutionBaseBuilder; - private readonly INamedTypeSymbol _returnType; - private readonly IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> _parameters; - - public LocalFunctionResolutionBuilder( - // parameter - IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, - INamedTypeSymbol returnType, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> parameters, - - - // dependencies - WellKnownTypes wellKnownTypes, - IReferenceGeneratorFactory referenceGeneratorFactory, - Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) - : base(rangeResolutionBaseBuilder, returnType, parameters, wellKnownTypes, referenceGeneratorFactory, localFunctionResolutionBuilderFactory) - { - _rangeResolutionBaseBuilder = rangeResolutionBaseBuilder; - _returnType = returnType; - _parameters = parameters; - - Name = RootReferenceGenerator.Generate("Create", _returnType); - } - - protected override string Name { get; } - - protected override Resolvable CreateResolvable() => SwitchType(new SwitchTypeParameter(_returnType, _parameters)).Item1; - - public override FunctionResolution Build() - { - AdjustForSynchronicity(); - return new( - Name, - TypeFullName, - Resolvable.Value, - _parameters.Select(t => t.Resolution).ToList(), - _rangeResolutionBaseBuilder.DisposalHandling, - LocalFunctions - .Select(lf => lf.Build()) - .Select(f => new LocalFunctionResolution( - f.Reference, - f.TypeFullName, - f.Resolvable, - f.Parameter, - f.DisposalHandling, - f.LocalFunctions, - f.SynchronicityDecision)) - .ToList(), - SynchronicityDecision.Value); - } -} - -internal interface IContainerCreateFunctionResolutionBuilder : IFunctionResolutionBuilder -{ -} - -internal class ContainerCreateFunctionResolutionBuilder : FunctionResolutionBuilder, IContainerCreateFunctionResolutionBuilder -{ - private readonly IRangeResolutionBaseBuilder _rangeResolutionBaseBuilder; - private readonly INamedTypeSymbol _returnType; - - public ContainerCreateFunctionResolutionBuilder( - // parameter - IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, - INamedTypeSymbol returnType, - - - // dependencies - WellKnownTypes wellKnownTypes, - IReferenceGeneratorFactory referenceGeneratorFactory, - Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) - : base(rangeResolutionBaseBuilder, returnType, Array.Empty<(ITypeSymbol, ParameterResolution)>(), wellKnownTypes, referenceGeneratorFactory, localFunctionResolutionBuilderFactory) - { - _rangeResolutionBaseBuilder = rangeResolutionBaseBuilder; - _returnType = returnType; - - Name = RootReferenceGenerator.Generate("Create"); - } - - protected override string Name { get; } - - protected override Resolvable CreateResolvable() => SwitchType(new SwitchTypeParameter( - _returnType, - Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>())).Item1; - - public override FunctionResolution Build() - { - AdjustForSynchronicity(); - return new( - Name, - TypeFullName, - Resolvable.Value, - Array.Empty(), - _rangeResolutionBaseBuilder.DisposalHandling, - LocalFunctions - .Select(lf => lf.Build()) - .Select(f => new LocalFunctionResolution( - f.Reference, - f.TypeFullName, - f.Resolvable, - f.Parameter, - f.DisposalHandling, - f.LocalFunctions, - f.SynchronicityDecision)) - .ToList(), - SynchronicityDecision.Value); - } -} - -internal interface IScopeRootCreateFunctionResolutionBuilder : IFunctionResolutionBuilder -{ -} - -internal class ScopeRootCreateFunctionResolutionBuilder : FunctionResolutionBuilder, IScopeRootCreateFunctionResolutionBuilder -{ - private readonly IRangeResolutionBaseBuilder _rangeResolutionBaseBuilder; - private readonly IScopeRootParameter _scopeRootParameter; - - public ScopeRootCreateFunctionResolutionBuilder( - // parameter - IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, - IScopeRootParameter scopeRootParameter, - - - // dependencies - WellKnownTypes wellKnownTypes, - IReferenceGeneratorFactory referenceGeneratorFactory, - Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) - : base(rangeResolutionBaseBuilder, scopeRootParameter.ReturnType, scopeRootParameter.CurrentParameters, wellKnownTypes, referenceGeneratorFactory, localFunctionResolutionBuilderFactory) - { - _rangeResolutionBaseBuilder = rangeResolutionBaseBuilder; - _scopeRootParameter = scopeRootParameter; - - Name = RootReferenceGenerator.Generate("Create"); - } - - protected override string Name { get; } - - protected override Resolvable CreateResolvable() => _scopeRootParameter switch - { - CreateInterfaceParameter createInterfaceParameter => CreateInterface(createInterfaceParameter).Item1, - SwitchImplementationParameter switchImplementationParameter => SwitchImplementation(switchImplementationParameter).Item1, - SwitchInterfaceAfterScopeRootParameter switchInterfaceAfterScopeRootParameter => SwitchInterfaceAfterScopeRoot(switchInterfaceAfterScopeRootParameter).Item1, - _ => throw new ArgumentOutOfRangeException(nameof(_scopeRootParameter)) - }; - - public override FunctionResolution Build() - { - AdjustForSynchronicity(); - - return new( - Name, - TypeFullName, - Resolvable.Value, - Parameters, - _rangeResolutionBaseBuilder.DisposalHandling, - LocalFunctions - .Select(lf => lf.Build()) - .Select(f => new LocalFunctionResolution( - f.Reference, - f.TypeFullName, - f.Resolvable, - f.Parameter, - f.DisposalHandling, - f.LocalFunctions, - f.SynchronicityDecision)) - .ToList(), - SynchronicityDecision.Value); - } -} - -internal interface IRangedFunctionResolutionBuilder : IFunctionResolutionBuilder -{ -} - -internal class RangedFunctionResolutionBuilder : FunctionResolutionBuilder, IRangedFunctionResolutionBuilder -{ - private readonly IRangeResolutionBaseBuilder _rangeResolutionBaseBuilder; - private readonly ForConstructorParameter _forConstructorParameter; - - public RangedFunctionResolutionBuilder( - // parameter - IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, - string reference, - ForConstructorParameter forConstructorParameter, - - - // dependencies - WellKnownTypes wellKnownTypes, - IReferenceGeneratorFactory referenceGeneratorFactory, - Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) - : base(rangeResolutionBaseBuilder, forConstructorParameter.ImplementationType, forConstructorParameter.CurrentFuncParameters, wellKnownTypes, referenceGeneratorFactory, localFunctionResolutionBuilderFactory) - { - _rangeResolutionBaseBuilder = rangeResolutionBaseBuilder; - _forConstructorParameter = forConstructorParameter; - - Name = reference; - } - - protected override string Name { get; } - - protected override Resolvable CreateResolvable() => CreateConstructorResolution(_forConstructorParameter).Item1; - - public override FunctionResolution Build() - { - AdjustForSynchronicity(); - - return new( - Name, - TypeFullName, - Resolvable.Value, - _forConstructorParameter.CurrentFuncParameters.Select(t => t.Resolution).ToList(), - _rangeResolutionBaseBuilder.DisposalHandling, - LocalFunctions - .Select(lf => lf.Build()) - .Select(f => new LocalFunctionResolution( - f.Reference, - f.TypeFullName, - f.Resolvable, - f.Parameter, - f.DisposalHandling, - f.LocalFunctions, - f.SynchronicityDecision)) - .ToList(), - SynchronicityDecision.Value); - } -} - internal abstract class FunctionResolutionBuilder : IFunctionResolutionBuilder { private readonly IRangeResolutionBaseBuilder _rangeResolutionBaseBuilder; @@ -310,8 +76,8 @@ internal FunctionResolutionBuilder( SynchronicityDecision = new(() => PotentialAwaits.Any(pa => pa.Await) - ? ResolutionBuilding.SynchronicityDecision.AsyncValueTask - : ResolutionBuilding.SynchronicityDecision.Sync); + ? Function.SynchronicityDecision.AsyncValueTask + : Function.SynchronicityDecision.Sync); Resolvable = new(CreateResolvable); } @@ -1103,8 +869,8 @@ false when initializationMethod.ReturnType.Equals(_wellKnownTypes.ValueTask, Sym protected void AdjustForSynchronicity() => ActualReturnType = SynchronicityDecision.Value switch { - ResolutionBuilding.SynchronicityDecision.AsyncTask => _wellKnownTypes.Task1.Construct(OriginalReturnType), - ResolutionBuilding.SynchronicityDecision.AsyncValueTask => _wellKnownTypes.ValueTask1.Construct(OriginalReturnType), + Function.SynchronicityDecision.AsyncTask => _wellKnownTypes.Task1.Construct(OriginalReturnType), + Function.SynchronicityDecision.AsyncValueTask => _wellKnownTypes.ValueTask1.Construct(OriginalReturnType), _ => OriginalReturnType }; diff --git a/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs new file mode 100644 index 00000000..fbff4908 --- /dev/null +++ b/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs @@ -0,0 +1,59 @@ +namespace MrMeeseeks.DIE.ResolutionBuilding.Function; + +internal interface ILocalFunctionResolutionBuilder : IFunctionResolutionBuilder +{ +} + +internal class LocalFunctionResolutionBuilder : FunctionResolutionBuilder, ILocalFunctionResolutionBuilder +{ + private readonly IRangeResolutionBaseBuilder _rangeResolutionBaseBuilder; + private readonly INamedTypeSymbol _returnType; + private readonly IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> _parameters; + + public LocalFunctionResolutionBuilder( + // parameter + IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, + INamedTypeSymbol returnType, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> parameters, + + + // dependencies + WellKnownTypes wellKnownTypes, + IReferenceGeneratorFactory referenceGeneratorFactory, + Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) + : base(rangeResolutionBaseBuilder, returnType, parameters, wellKnownTypes, referenceGeneratorFactory, localFunctionResolutionBuilderFactory) + { + _rangeResolutionBaseBuilder = rangeResolutionBaseBuilder; + _returnType = returnType; + _parameters = parameters; + + Name = RootReferenceGenerator.Generate("Create", _returnType); + } + + protected override string Name { get; } + + protected override Resolvable CreateResolvable() => SwitchType(new SwitchTypeParameter(_returnType, _parameters)).Item1; + + public override FunctionResolution Build() + { + AdjustForSynchronicity(); + return new( + Name, + TypeFullName, + Resolvable.Value, + _parameters.Select(t => t.Resolution).ToList(), + _rangeResolutionBaseBuilder.DisposalHandling, + LocalFunctions + .Select(lf => lf.Build()) + .Select(f => new LocalFunctionResolution( + f.Reference, + f.TypeFullName, + f.Resolvable, + f.Parameter, + f.DisposalHandling, + f.LocalFunctions, + f.SynchronicityDecision)) + .ToList(), + SynchronicityDecision.Value); + } +} \ No newline at end of file diff --git a/Main/ResolutionBuilding/Function/RangedFunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/RangedFunctionResolutionBuilder.cs new file mode 100644 index 00000000..cc4ac105 --- /dev/null +++ b/Main/ResolutionBuilding/Function/RangedFunctionResolutionBuilder.cs @@ -0,0 +1,58 @@ +namespace MrMeeseeks.DIE.ResolutionBuilding.Function; + +internal interface IRangedFunctionResolutionBuilder : IFunctionResolutionBuilder +{ +} + +internal class RangedFunctionResolutionBuilder : FunctionResolutionBuilder, IRangedFunctionResolutionBuilder +{ + private readonly IRangeResolutionBaseBuilder _rangeResolutionBaseBuilder; + private readonly ForConstructorParameter _forConstructorParameter; + + public RangedFunctionResolutionBuilder( + // parameter + IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, + string reference, + ForConstructorParameter forConstructorParameter, + + + // dependencies + WellKnownTypes wellKnownTypes, + IReferenceGeneratorFactory referenceGeneratorFactory, + Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) + : base(rangeResolutionBaseBuilder, forConstructorParameter.ImplementationType, forConstructorParameter.CurrentFuncParameters, wellKnownTypes, referenceGeneratorFactory, localFunctionResolutionBuilderFactory) + { + _rangeResolutionBaseBuilder = rangeResolutionBaseBuilder; + _forConstructorParameter = forConstructorParameter; + + Name = reference; + } + + protected override string Name { get; } + + protected override Resolvable CreateResolvable() => CreateConstructorResolution(_forConstructorParameter).Item1; + + public override FunctionResolution Build() + { + AdjustForSynchronicity(); + + return new( + Name, + TypeFullName, + Resolvable.Value, + _forConstructorParameter.CurrentFuncParameters.Select(t => t.Resolution).ToList(), + _rangeResolutionBaseBuilder.DisposalHandling, + LocalFunctions + .Select(lf => lf.Build()) + .Select(f => new LocalFunctionResolution( + f.Reference, + f.TypeFullName, + f.Resolvable, + f.Parameter, + f.DisposalHandling, + f.LocalFunctions, + f.SynchronicityDecision)) + .ToList(), + SynchronicityDecision.Value); + } +} \ No newline at end of file diff --git a/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs new file mode 100644 index 00000000..6196e496 --- /dev/null +++ b/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs @@ -0,0 +1,63 @@ +namespace MrMeeseeks.DIE.ResolutionBuilding.Function; + +internal interface IScopeRootCreateFunctionResolutionBuilder : IFunctionResolutionBuilder +{ +} + +internal class ScopeRootCreateFunctionResolutionBuilder : FunctionResolutionBuilder, IScopeRootCreateFunctionResolutionBuilder +{ + private readonly IRangeResolutionBaseBuilder _rangeResolutionBaseBuilder; + private readonly IScopeRootParameter _scopeRootParameter; + + public ScopeRootCreateFunctionResolutionBuilder( + // parameter + IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, + IScopeRootParameter scopeRootParameter, + + + // dependencies + WellKnownTypes wellKnownTypes, + IReferenceGeneratorFactory referenceGeneratorFactory, + Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) + : base(rangeResolutionBaseBuilder, scopeRootParameter.ReturnType, scopeRootParameter.CurrentParameters, wellKnownTypes, referenceGeneratorFactory, localFunctionResolutionBuilderFactory) + { + _rangeResolutionBaseBuilder = rangeResolutionBaseBuilder; + _scopeRootParameter = scopeRootParameter; + + Name = RootReferenceGenerator.Generate("Create"); + } + + protected override string Name { get; } + + protected override Resolvable CreateResolvable() => _scopeRootParameter switch + { + CreateInterfaceParameter createInterfaceParameter => CreateInterface(createInterfaceParameter).Item1, + SwitchImplementationParameter switchImplementationParameter => SwitchImplementation(switchImplementationParameter).Item1, + SwitchInterfaceAfterScopeRootParameter switchInterfaceAfterScopeRootParameter => SwitchInterfaceAfterScopeRoot(switchInterfaceAfterScopeRootParameter).Item1, + _ => throw new ArgumentOutOfRangeException(nameof(_scopeRootParameter)) + }; + + public override FunctionResolution Build() + { + AdjustForSynchronicity(); + + return new( + Name, + TypeFullName, + Resolvable.Value, + Parameters, + _rangeResolutionBaseBuilder.DisposalHandling, + LocalFunctions + .Select(lf => lf.Build()) + .Select(f => new LocalFunctionResolution( + f.Reference, + f.TypeFullName, + f.Resolvable, + f.Parameter, + f.DisposalHandling, + f.LocalFunctions, + f.SynchronicityDecision)) + .ToList(), + SynchronicityDecision.Value); + } +} \ No newline at end of file diff --git a/Main/ResolutionBuilding/RangedFunctionResolutionBuilderManager.cs b/Main/ResolutionBuilding/RangedFunctionResolutionBuilderManager.cs index cb9d545f..f4eaf4f7 100644 --- a/Main/ResolutionBuilding/RangedFunctionResolutionBuilderManager.cs +++ b/Main/ResolutionBuilding/RangedFunctionResolutionBuilderManager.cs @@ -1,3 +1,5 @@ +using MrMeeseeks.DIE.ResolutionBuilding.Function; + namespace MrMeeseeks.DIE.ResolutionBuilding; internal interface IRangedFunctionGroupResolutionBuilder diff --git a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs index 4779b0f3..b98ec375 100644 --- a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs @@ -1,4 +1,5 @@ using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.ResolutionBuilding.Function; namespace MrMeeseeks.DIE.ResolutionBuilding; diff --git a/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs b/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs index 032b385e..95b2ad24 100644 --- a/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs +++ b/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs @@ -1,3 +1,5 @@ +using MrMeeseeks.DIE.ResolutionBuilding.Function; + namespace MrMeeseeks.DIE.ResolutionBuilding; internal interface ITransientScopeInterfaceResolutionBuilder diff --git a/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs b/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs index d2c053ff..f3b0cffc 100644 --- a/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs @@ -1,4 +1,5 @@ using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.ResolutionBuilding.Function; namespace MrMeeseeks.DIE.ResolutionBuilding; diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index b1a451d8..187dad89 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -1,4 +1,5 @@ using MrMeeseeks.DIE.ResolutionBuilding; +using MrMeeseeks.DIE.ResolutionBuilding.Function; namespace MrMeeseeks.DIE; diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index 874b1bd1..413d103f 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -1,6 +1,7 @@ using MrMeeseeks.DIE.CodeBuilding; using MrMeeseeks.DIE.Configuration; using MrMeeseeks.DIE.ResolutionBuilding; +using MrMeeseeks.DIE.ResolutionBuilding.Function; namespace MrMeeseeks.DIE; From 44c8814aa85d467da353348193d59b19d2f63d8c Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sun, 3 Apr 2022 15:52:51 +0200 Subject: [PATCH 058/162] Fine tuning for supporting awaits in functions --- Main/CodeBuilding/ContainerCodeBuilder.cs | 21 +- Main/CodeBuilding/RangeCodeBaseBuilder.cs | 12 +- .../ContainerResolutionBuilder.cs | 17 +- ...ontainerCreateFunctionResolutionBuilder.cs | 3 +- .../Function/FunctionResolutionBuilder.cs | 56 ++-- .../LocalFunctionResolutionBuilder.cs | 3 +- .../RangedFunctionGroupResolutionBuilder.cs} | 64 ++--- .../RangedFunctionResolutionBuilder.cs | 3 +- ...copeRootCreateFunctionResolutionBuilder.cs | 3 +- ...entScopeImplementationResolutionBuilder.cs | 5 +- .../RangeResolutionBaseBuilder.cs | 14 +- Main/ResolutionBuilding/ResolutionDtos.cs | 3 +- .../ScopeResolutionBuilder.cs | 6 +- ...ransientScopeInterfaceResolutionBuilder.cs | 42 ++- .../TransientScopeResolutionBuilder.cs | 12 +- Main/ResolutionTreeItem.cs | 5 +- Main/SourceGenerator.cs | 19 +- Sample/Context.cs | 65 +---- Sample/Program.cs | 3 - .../ContainerInstanceFunctionAsTask.cs | 33 +++ .../ContainerInstanceFunctionAsValueTask.cs | 33 +++ .../Awaited/ScopeInstanceFunctionAsTask.cs | 33 +++ .../ScopeInstanceFunctionAsValueTask.cs | 33 +++ .../TransientScopeInstanceFunctionAsTask.cs | 32 +++ ...ansientScopeInstanceFunctionAsValueTask.cs | 32 +++ .../ContainerInstanceFunctionAsTask.cs | 33 +++ .../ContainerInstanceFunctionAsValueTask.cs | 33 +++ .../DecorationChaining.cs | 2 +- .../{WrappedDependency => Wrapped}/Func.cs | 2 +- .../{WrappedDependency => Wrapped}/Lazy.cs | 2 +- .../Wrapped/ScopeInstanceFunctionAsTask.cs | 33 +++ .../ScopeInstanceFunctionAsValueTask.cs | 33 +++ .../SyncToTask.cs | 2 +- .../SyncToValueTask.cs | 3 +- .../TaskCollection.cs | 2 +- .../TaskComposition.cs | 2 +- .../TaskToTask.cs | 2 +- .../TaskToValueTask.cs | 2 +- .../TransientScopeInstanceFunctionAsTask.cs | 32 +++ ...ansientScopeInstanceFunctionAsValueTask.cs | 32 +++ .../ValueTaskCollection.cs | 2 +- .../ValueTaskComposition.cs | 2 +- .../ValueTaskToTask.cs | 2 +- .../ValueTaskToValueTask.cs | 2 +- Test/Decorator/ContainerInstance.cs | 45 ++++ Test/Decorator/List.cs | 56 ++++ Test/Decorator/Multi.cs | 56 ++++ Test/Decorator/Normal.cs | 41 +++ Test/DecoratorTests.cs | 246 ------------------ 49 files changed, 808 insertions(+), 411 deletions(-) rename Main/ResolutionBuilding/{RangedFunctionResolutionBuilderManager.cs => Function/RangedFunctionGroupResolutionBuilder.cs} (56%) create mode 100644 Test/Async/Awaited/ContainerInstanceFunctionAsTask.cs create mode 100644 Test/Async/Awaited/ContainerInstanceFunctionAsValueTask.cs create mode 100644 Test/Async/Awaited/ScopeInstanceFunctionAsTask.cs create mode 100644 Test/Async/Awaited/ScopeInstanceFunctionAsValueTask.cs create mode 100644 Test/Async/Awaited/TransientScopeInstanceFunctionAsTask.cs create mode 100644 Test/Async/Awaited/TransientScopeInstanceFunctionAsValueTask.cs create mode 100644 Test/Async/Wrapped/ContainerInstanceFunctionAsTask.cs create mode 100644 Test/Async/Wrapped/ContainerInstanceFunctionAsValueTask.cs rename Test/Async/{WrappedDependency => Wrapped}/DecorationChaining.cs (95%) rename Test/Async/{WrappedDependency => Wrapped}/Func.cs (92%) rename Test/Async/{WrappedDependency => Wrapped}/Lazy.cs (92%) create mode 100644 Test/Async/Wrapped/ScopeInstanceFunctionAsTask.cs create mode 100644 Test/Async/Wrapped/ScopeInstanceFunctionAsValueTask.cs rename Test/Async/{WrappedDependency => Wrapped}/SyncToTask.cs (90%) rename Test/Async/{WrappedDependency => Wrapped}/SyncToValueTask.cs (85%) rename Test/Async/{WrappedDependency => Wrapped}/TaskCollection.cs (95%) rename Test/Async/{WrappedDependency => Wrapped}/TaskComposition.cs (96%) rename Test/Async/{WrappedDependency => Wrapped}/TaskToTask.cs (91%) rename Test/Async/{WrappedDependency => Wrapped}/TaskToValueTask.cs (91%) create mode 100644 Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask.cs create mode 100644 Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask.cs rename Test/Async/{WrappedDependency => Wrapped}/ValueTaskCollection.cs (95%) rename Test/Async/{WrappedDependency => Wrapped}/ValueTaskComposition.cs (96%) rename Test/Async/{WrappedDependency => Wrapped}/ValueTaskToTask.cs (91%) rename Test/Async/{WrappedDependency => Wrapped}/ValueTaskToValueTask.cs (90%) create mode 100644 Test/Decorator/ContainerInstance.cs create mode 100644 Test/Decorator/List.cs create mode 100644 Test/Decorator/Multi.cs create mode 100644 Test/Decorator/Normal.cs delete mode 100644 Test/DecoratorTests.cs diff --git a/Main/CodeBuilding/ContainerCodeBuilder.cs b/Main/CodeBuilding/ContainerCodeBuilder.cs index 15bae3af..cfd4c48f 100644 --- a/Main/CodeBuilding/ContainerCodeBuilder.cs +++ b/Main/CodeBuilding/ContainerCodeBuilder.cs @@ -1,3 +1,5 @@ +using MrMeeseeks.DIE.ResolutionBuilding.Function; + namespace MrMeeseeks.DIE.CodeBuilding; internal interface IContainerCodeBuilder : IRangeCodeBaseBuilder @@ -15,6 +17,7 @@ internal class ContainerCodeBuilder : RangeCodeBaseBuilder, IContainerCodeBuilde public override StringBuilder Build(StringBuilder stringBuilder) { stringBuilder = stringBuilder + .AppendLine($"#nullable enable") .AppendLine($"namespace {_containerInfo.Namespace}") .AppendLine($"{{") .AppendLine($"partial class {_containerInfo.Name} : {WellKnownTypes.Disposable.FullName()}") @@ -31,7 +34,7 @@ public override StringBuilder Build(StringBuilder stringBuilder) stringBuilder = _containerResolution.TransientScopeInterface.Functions.Aggregate( stringBuilder, (sb, f) => sb.AppendLine( - $"{f.TypeFullName} {f.Reference}({string.Join(", ", f.Parameter.Select(p => $"{p.TypeFullName} {p.Reference}"))});")); + $"{SelectFullName(f)} {f.Reference}({string.Join(", ", f.Parameter.Select(p => $"{p.TypeFullName} {p.Reference}"))});")); stringBuilder = stringBuilder .AppendLine($"}}"); @@ -45,12 +48,12 @@ public override StringBuilder Build(StringBuilder stringBuilder) stringBuilder = _containerResolution.TransientScopeInterface.Functions.Aggregate( stringBuilder, (sb, f) => sb.AppendLine( - $"public {f.TypeFullName} {f.Reference}({string.Join(", ", f.Parameter.Select(p => $"{p.TypeFullName} {p.Reference}"))}) =>") + $"public {SelectFullName(f)} {f.Reference}({string.Join(", ", f.Parameter.Select(p => $"{p.TypeFullName} {p.Reference}"))}) =>") .AppendLine($"_container.{f.Reference}({string.Join(", ", f.Parameter.Select(p => p.Reference))});")); stringBuilder = stringBuilder .AppendLine($"}}") - .AppendLine($"private {_containerResolution.TransientScopeInterface.ContainerAdapterName} _{_containerResolution.TransientScopeAdapterReference};") + .AppendLine($"private {_containerResolution.TransientScopeInterface.ContainerAdapterName}? _{_containerResolution.TransientScopeAdapterReference};") .AppendLine($"private {_containerResolution.TransientScopeInterface.ContainerAdapterName} {_containerResolution.TransientScopeAdapterReference} => _{_containerResolution.TransientScopeAdapterReference} ??= new {_containerResolution.TransientScopeInterface.ContainerAdapterName}(this);"); stringBuilder = _transientScopeCodeBuilders.Aggregate(stringBuilder, (sb, cb) => cb.Build(sb)); @@ -59,7 +62,17 @@ public override StringBuilder Build(StringBuilder stringBuilder) return stringBuilder .AppendLine($"}}") - .AppendLine($"}}"); + .AppendLine($"}}") + .AppendLine($"#nullable disable"); + + string SelectFullName(InterfaceFunctionDeclarationResolution interfaceResolution) => + interfaceResolution.SynchronicityDecision.Value switch + { + SynchronicityDecision.AsyncValueTask => interfaceResolution.ValueTaskTypeFullName, + SynchronicityDecision.AsyncTask => interfaceResolution.TaskTypeFullName, + SynchronicityDecision.Sync => interfaceResolution.TypeFullName, + _ => throw new ArgumentException("Synchronicity not decided for the interface function at time of generating the sources") + }; } public ContainerCodeBuilder( diff --git a/Main/CodeBuilding/RangeCodeBaseBuilder.cs b/Main/CodeBuilding/RangeCodeBaseBuilder.cs index 26abb4f4..c55810c5 100644 --- a/Main/CodeBuilding/RangeCodeBaseBuilder.cs +++ b/Main/CodeBuilding/RangeCodeBaseBuilder.cs @@ -1,4 +1,3 @@ -using MrMeeseeks.DIE.ResolutionBuilding; using MrMeeseeks.DIE.ResolutionBuilding.Function; namespace MrMeeseeks.DIE.CodeBuilding; @@ -466,18 +465,21 @@ private StringBuilder GenerateRangedInstanceFunction(StringBuilder stringBuilder { stringBuilder = stringBuilder .AppendLine( - $"private {rangedInstanceFunctionGroupResolution.TypeFullName} {rangedInstanceFunctionGroupResolution.FieldReference};") + $"private {rangedInstanceFunctionGroupResolution.TypeFullName}? {rangedInstanceFunctionGroupResolution.FieldReference};") .AppendLine( $"private {WellKnownTypes.SemaphoreSlim.FullName()} {rangedInstanceFunctionGroupResolution.LockReference} = new {WellKnownTypes.SemaphoreSlim.FullName()}(1);"); foreach (var overload in rangedInstanceFunctionGroupResolution.Overloads) { + var isAsync = + overload.SynchronicityDecision is SynchronicityDecision.AsyncTask or SynchronicityDecision.AsyncValueTask; var parameters = string.Join(", ", overload.Parameter.Select(p => $"{p.TypeFullName} {p.Reference}")); stringBuilder = stringBuilder.AppendLine( - $"public {(overload.SynchronicityDecision is SynchronicityDecision.AsyncTask or SynchronicityDecision.AsyncValueTask ? "async " : "")}{overload.TypeFullName} {overload.Reference}({parameters})") - .AppendLine($"{{") - .AppendLine($"this.{rangedInstanceFunctionGroupResolution.LockReference}.Wait();") + $"public {(isAsync ? "async " : "")}{overload.TypeFullName} {overload.Reference}({parameters})") + .AppendLine($"{{").AppendLine( + $"if (!object.ReferenceEquals({rangedInstanceFunctionGroupResolution.FieldReference}, null)) return {rangedInstanceFunctionGroupResolution.FieldReference};") + .AppendLine($"{(isAsync ? "await " : "")}this.{rangedInstanceFunctionGroupResolution.LockReference}.Wait{(isAsync ? "Async" : "")}();") .AppendLine($"try") .AppendLine($"{{") .AppendLine( diff --git a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs index e6da694c..8022b3e5 100644 --- a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs @@ -18,6 +18,7 @@ internal class ContainerResolutionBuilder : RangeResolutionBaseBuilder, IContain private readonly ITransientScopeInterfaceResolutionBuilder _transientScopeInterfaceResolutionBuilder; private readonly WellKnownTypes _wellKnownTypes; private readonly Func _createFunctionResolutionBuilderFactory; + private readonly Func _synchronicityDecisionMakerFactory; private readonly List<(IContainerCreateFunctionResolutionBuilder CreateFunction, string MethodNamePrefix)> _rootResolutions = new (); private readonly string _transientScopeAdapterReference; @@ -34,7 +35,8 @@ internal ContainerResolutionBuilder( WellKnownTypes wellKnownTypes, Func scopeManagerFactory, Func createFunctionResolutionBuilderFactory, - Func rangedFunctionGroupResolutionBuilderFactory, + Func rangedFunctionGroupResolutionBuilderFactory, + Func synchronicityDecisionMakerFactory, IUserProvidedScopeElements userProvidedScopeElement) : base( containerInfo.Name, @@ -42,12 +44,14 @@ internal ContainerResolutionBuilder( userProvidedScopeElement, wellKnownTypes, referenceGeneratorFactory, - rangedFunctionGroupResolutionBuilderFactory) + rangedFunctionGroupResolutionBuilderFactory, + synchronicityDecisionMakerFactory) { _containerInfo = containerInfo; _transientScopeInterfaceResolutionBuilder = transientScopeInterfaceResolutionBuilder; _wellKnownTypes = wellKnownTypes; _createFunctionResolutionBuilderFactory = createFunctionResolutionBuilderFactory; + _synchronicityDecisionMakerFactory = synchronicityDecisionMakerFactory; _scopeManager = scopeManagerFactory(this, transientScopeInterfaceResolutionBuilder); transientScopeInterfaceResolutionBuilder.AddImplementation(this); @@ -65,7 +69,8 @@ public MultiSynchronicityFunctionCallResolution CreateContainerInstanceReference parameter, "Container", null, - containerReference); + containerReference, + new (_synchronicityDecisionMakerFactory)); public override MultiSynchronicityFunctionCallResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter) => CreateContainerInstanceReferenceResolution(parameter, "this"); @@ -324,9 +329,11 @@ public ContainerResolution Build() public void EnqueueRangedInstanceResolution( ForConstructorParameter parameter, string label, - string reference) => CreateRangedInstanceReferenceResolution( + string reference, + Lazy synchronicityDecisionMaker) => CreateRangedInstanceReferenceResolution( parameter, label, reference, - "Doesn'tMatter"); + "Doesn't Matter, because for interface", + synchronicityDecisionMaker); } \ No newline at end of file diff --git a/Main/ResolutionBuilding/Function/ContainerCreateFunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/ContainerCreateFunctionResolutionBuilder.cs index d8b7d14b..142cf1ba 100644 --- a/Main/ResolutionBuilding/Function/ContainerCreateFunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/ContainerCreateFunctionResolutionBuilder.cs @@ -13,13 +13,14 @@ public ContainerCreateFunctionResolutionBuilder( // parameter IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, INamedTypeSymbol returnType, + IFunctionResolutionSynchronicityDecisionMaker synchronicityDecisionMaker, // dependencies WellKnownTypes wellKnownTypes, IReferenceGeneratorFactory referenceGeneratorFactory, Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) - : base(rangeResolutionBaseBuilder, returnType, Array.Empty<(ITypeSymbol, ParameterResolution)>(), wellKnownTypes, referenceGeneratorFactory, localFunctionResolutionBuilderFactory) + : base(rangeResolutionBaseBuilder, returnType, Array.Empty<(ITypeSymbol, ParameterResolution)>(), synchronicityDecisionMaker, wellKnownTypes, referenceGeneratorFactory, localFunctionResolutionBuilderFactory) { _rangeResolutionBaseBuilder = rangeResolutionBaseBuilder; _returnType = returnType; diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs index a3498882..2bb010a4 100644 --- a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs @@ -10,6 +10,35 @@ internal enum SynchronicityDecision AsyncValueTask } +internal interface IFunctionResolutionSynchronicityDecisionMaker +{ + Lazy Decision { get; } + + void Register(IAwaitableResolution awaitableResolution); +} + +internal class FunctionResolutionSynchronicityDecisionMaker : IFunctionResolutionSynchronicityDecisionMaker +{ + private readonly ISet _potentialAwaits = new HashSet(); + + public Lazy Decision { get; } + + public FunctionResolutionSynchronicityDecisionMaker() => + Decision = new(() => _potentialAwaits.Any(pa => pa.Await) + ? SynchronicityDecision.AsyncValueTask + : SynchronicityDecision.Sync); + + public void Register(IAwaitableResolution awaitableResolution) + { + if (Decision.IsValueCreated) + { + throw new InvalidOperationException("Registration of awaitable resolution after (!) synchronicity was decided."); + } + + _potentialAwaits.Add(awaitableResolution); + } +} + internal interface IFunctionResolutionBuilder : IResolutionBuilder { INamedTypeSymbol OriginalReturnType { get; } @@ -25,6 +54,7 @@ MultiSynchronicityFunctionCallResolution BuildFunctionCall( internal abstract class FunctionResolutionBuilder : IFunctionResolutionBuilder { private readonly IRangeResolutionBaseBuilder _rangeResolutionBaseBuilder; + private readonly IFunctionResolutionSynchronicityDecisionMaker _synchronicityDecisionMaker; private readonly WellKnownTypes _wellKnownTypes; private readonly Func, ILocalFunctionResolutionBuilder> _localFunctionResolutionBuilderFactory; private readonly ICheckTypeProperties _checkTypeProperties; @@ -35,13 +65,11 @@ internal abstract class FunctionResolutionBuilder : IFunctionResolutionBuilder private readonly IUserProvidedScopeElements _userProvidedScopeElements; protected readonly IList LocalFunctions = new List(); - - protected readonly ISet PotentialAwaits = new HashSet(); protected abstract string Name { get; } protected string TypeFullName => ActualReturnType?.FullName() ?? OriginalReturnType.FullName(); - public Lazy SynchronicityDecision { get; } + public Lazy SynchronicityDecision => _synchronicityDecisionMaker.Decision; protected Lazy Resolvable { get; } protected IReadOnlyList Parameters { get; } @@ -54,6 +82,7 @@ internal FunctionResolutionBuilder( IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, INamedTypeSymbol returnType, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters, + IFunctionResolutionSynchronicityDecisionMaker synchronicityDecisionMaker, // dependencies @@ -63,6 +92,7 @@ internal FunctionResolutionBuilder( { OriginalReturnType = returnType; _rangeResolutionBaseBuilder = rangeResolutionBaseBuilder; + _synchronicityDecisionMaker = synchronicityDecisionMaker; _wellKnownTypes = wellKnownTypes; _localFunctionResolutionBuilderFactory = localFunctionResolutionBuilderFactory; _checkTypeProperties = rangeResolutionBaseBuilder.CheckTypeProperties; @@ -74,10 +104,6 @@ internal FunctionResolutionBuilder( .Select(p => new ParameterResolution(RootReferenceGenerator.Generate(p.Type), TypeFullName)) .ToList(); - SynchronicityDecision = new(() => - PotentialAwaits.Any(pa => pa.Await) - ? Function.SynchronicityDecision.AsyncValueTask - : Function.SynchronicityDecision.Sync); Resolvable = new(CreateResolvable); } @@ -450,10 +476,10 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup }; if (ret.Item1 is ScopeRootResolution { ScopeRootFunction: IAwaitableResolution awaitableResolution }) - PotentialAwaits.Add(awaitableResolution); + _synchronicityDecisionMaker.Register(awaitableResolution); if (ret.Item1 is TransientScopeRootResolution { ScopeRootFunction: IAwaitableResolution awaitableResolution0 }) - PotentialAwaits.Add(awaitableResolution0); + _synchronicityDecisionMaker.Register(awaitableResolution0); if (ret.Item1 is ScopeRootResolution { ScopeRootFunction: ITaskConsumableResolution taskConsumableResolution }) ret.Item2 = taskConsumableResolution; @@ -531,10 +557,10 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup }; if (ret.Item1 is ScopeRootResolution { ScopeRootFunction: IAwaitableResolution awaitableResolution }) - PotentialAwaits.Add(awaitableResolution); + _synchronicityDecisionMaker.Register(awaitableResolution); if (ret.Item1 is TransientScopeRootResolution { ScopeRootFunction: IAwaitableResolution awaitableResolution0 }) - PotentialAwaits.Add(awaitableResolution0); + _synchronicityDecisionMaker.Register(awaitableResolution0); if (ret.Item1 is ScopeRootResolution { ScopeRootFunction: ITaskConsumableResolution taskConsumableResolution }) ret.Item2 = taskConsumableResolution; @@ -629,10 +655,10 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup }; if (ret.Item1 is ScopeRootResolution { ScopeRootFunction: IAwaitableResolution awaitableResolution }) - PotentialAwaits.Add(awaitableResolution); + _synchronicityDecisionMaker.Register(awaitableResolution); if (ret.Item1 is TransientScopeRootResolution { ScopeRootFunction: IAwaitableResolution awaitableResolution0 }) - PotentialAwaits.Add(awaitableResolution0); + _synchronicityDecisionMaker.Register(awaitableResolution0); if (ret.Item1 is ScopeRootResolution { ScopeRootFunction: ITaskConsumableResolution taskConsumableResolution }) ret.Item2 = taskConsumableResolution; @@ -683,7 +709,7 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup }; if (ret.Item1 is IAwaitableResolution awaitableResolution) - PotentialAwaits.Add(awaitableResolution); + _synchronicityDecisionMaker.Register(awaitableResolution); if (ret.Item2 is null) ret.Item2 = ret.Item1 as ITaskConsumableResolution; @@ -755,7 +781,7 @@ false when initializationMethod.ReturnType.Equals(_wellKnownTypes.ValueTask, Sym if (typeInitializationResolution is IAwaitableResolution awaitableResolution) { - PotentialAwaits.Add(awaitableResolution); + _synchronicityDecisionMaker.Register(awaitableResolution); } } diff --git a/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs index fbff4908..0c0700ea 100644 --- a/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs @@ -15,13 +15,14 @@ public LocalFunctionResolutionBuilder( IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, INamedTypeSymbol returnType, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> parameters, + IFunctionResolutionSynchronicityDecisionMaker synchronicityDecisionMaker, // dependencies WellKnownTypes wellKnownTypes, IReferenceGeneratorFactory referenceGeneratorFactory, Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) - : base(rangeResolutionBaseBuilder, returnType, parameters, wellKnownTypes, referenceGeneratorFactory, localFunctionResolutionBuilderFactory) + : base(rangeResolutionBaseBuilder, returnType, parameters, synchronicityDecisionMaker, wellKnownTypes, referenceGeneratorFactory, localFunctionResolutionBuilderFactory) { _rangeResolutionBaseBuilder = rangeResolutionBaseBuilder; _returnType = returnType; diff --git a/Main/ResolutionBuilding/RangedFunctionResolutionBuilderManager.cs b/Main/ResolutionBuilding/Function/RangedFunctionGroupResolutionBuilder.cs similarity index 56% rename from Main/ResolutionBuilding/RangedFunctionResolutionBuilderManager.cs rename to Main/ResolutionBuilding/Function/RangedFunctionGroupResolutionBuilder.cs index f4eaf4f7..70cb38b1 100644 --- a/Main/ResolutionBuilding/RangedFunctionResolutionBuilderManager.cs +++ b/Main/ResolutionBuilding/Function/RangedFunctionGroupResolutionBuilder.cs @@ -1,10 +1,8 @@ -using MrMeeseeks.DIE.ResolutionBuilding.Function; - -namespace MrMeeseeks.DIE.ResolutionBuilding; +namespace MrMeeseeks.DIE.ResolutionBuilding.Function; internal interface IRangedFunctionGroupResolutionBuilder { - IRangedFunctionResolutionBuilder GetInstanceFunction(ForConstructorParameter parameter); + IRangedFunctionResolutionBuilder GetInstanceFunction(ForConstructorParameter parameter, Lazy synchronicityDecisionMaker); bool HasWorkToDo { get; } @@ -16,15 +14,20 @@ internal interface IRangedFunctionGroupResolutionBuilder internal class RangedFunctionGroupResolutionBuilder : IRangedFunctionGroupResolutionBuilder { private readonly IRangeResolutionBaseBuilder _rangeResolutionBaseBuilder; - private readonly Func _rangedFunctionResolutionBuilderFactory; + + private readonly Func< + IRangeResolutionBaseBuilder, + string, + ForConstructorParameter, + IFunctionResolutionSynchronicityDecisionMaker, + IRangedFunctionResolutionBuilder> _rangedFunctionResolutionBuilderFactory; private readonly string _reference; private readonly string _typeFullName; private readonly string _fieldReference; private readonly string _lockReference; private readonly Dictionary _overloads = new(); - private readonly Queue _functionQueue = new(); - private readonly List _overloadResolutions = new(); + private readonly List _functionQueue = new(); internal RangedFunctionGroupResolutionBuilder( // parameter @@ -36,7 +39,7 @@ internal RangedFunctionGroupResolutionBuilder( // dependencies IReferenceGeneratorFactory referenceGeneratorFactory, - Func rangedFunctionResolutionBuilderFactory) + Func rangedFunctionResolutionBuilderFactory) { _rangeResolutionBaseBuilder = rangeResolutionBaseBuilder; _rangedFunctionResolutionBuilderFactory = rangedFunctionResolutionBuilderFactory; @@ -48,43 +51,42 @@ internal RangedFunctionGroupResolutionBuilder( _lockReference = rootReferenceGenerator.Generate($"_{label.ToLower()}InstanceLock{decorationSuffix}"); } - public IRangedFunctionResolutionBuilder GetInstanceFunction(ForConstructorParameter parameter) + public IRangedFunctionResolutionBuilder GetInstanceFunction( + ForConstructorParameter parameter, + Lazy synchronicityDecisionMaker) { var listedParameterTypes = string.Join(",", parameter.CurrentFuncParameters.Select(p => p.Item2.TypeFullName)); if (!_overloads.TryGetValue(listedParameterTypes, out var function)) { - function = _rangedFunctionResolutionBuilderFactory(_rangeResolutionBaseBuilder, _reference, parameter); + function = _rangedFunctionResolutionBuilderFactory(_rangeResolutionBaseBuilder, _reference, parameter, synchronicityDecisionMaker.Value); _overloads[listedParameterTypes] = function; - _functionQueue.Enqueue(function); + _functionQueue.Add(function); } return function; } - public bool HasWorkToDo => _functionQueue.Any(); + public bool HasWorkToDo => _functionQueue.Any(f => f.HasWorkToDo); public void DoWork() { - while (_functionQueue.Any()) - { - var function = _functionQueue.Dequeue(); - var functionResolution = function.Build(); - _overloadResolutions.Add(new RangedInstanceFunctionResolution( - functionResolution.Reference, - functionResolution.TypeFullName, - functionResolution.Resolvable, - functionResolution.Parameter, - functionResolution.DisposalHandling, - functionResolution.LocalFunctions, - SynchronicityDecision.Sync)); // todo async support - } + while (_functionQueue.Any(f => f.HasWorkToDo)) + foreach (var function in _functionQueue.Where(f => f.HasWorkToDo)) + function.DoWork(); } - public RangedInstanceFunctionGroupResolution Build() - { - return new RangedInstanceFunctionGroupResolution( - _typeFullName, - _overloadResolutions, + public RangedInstanceFunctionGroupResolution Build() => + new(_typeFullName, + _functionQueue + .Select(function => function.Build()) + .Select(functionResolution => new RangedInstanceFunctionResolution( + functionResolution.Reference, + functionResolution.TypeFullName, + functionResolution.Resolvable, + functionResolution.Parameter, + functionResolution.DisposalHandling, + functionResolution.LocalFunctions, + functionResolution.SynchronicityDecision)) + .ToList(), _fieldReference, _lockReference); - } } \ No newline at end of file diff --git a/Main/ResolutionBuilding/Function/RangedFunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/RangedFunctionResolutionBuilder.cs index cc4ac105..a64e67e7 100644 --- a/Main/ResolutionBuilding/Function/RangedFunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/RangedFunctionResolutionBuilder.cs @@ -14,13 +14,14 @@ public RangedFunctionResolutionBuilder( IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, string reference, ForConstructorParameter forConstructorParameter, + IFunctionResolutionSynchronicityDecisionMaker synchronicityDecisionMaker, // dependencies WellKnownTypes wellKnownTypes, IReferenceGeneratorFactory referenceGeneratorFactory, Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) - : base(rangeResolutionBaseBuilder, forConstructorParameter.ImplementationType, forConstructorParameter.CurrentFuncParameters, wellKnownTypes, referenceGeneratorFactory, localFunctionResolutionBuilderFactory) + : base(rangeResolutionBaseBuilder, forConstructorParameter.ImplementationType, forConstructorParameter.CurrentFuncParameters, synchronicityDecisionMaker, wellKnownTypes, referenceGeneratorFactory, localFunctionResolutionBuilderFactory) { _rangeResolutionBaseBuilder = rangeResolutionBaseBuilder; _forConstructorParameter = forConstructorParameter; diff --git a/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs index 6196e496..5991cb4b 100644 --- a/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs @@ -13,13 +13,14 @@ public ScopeRootCreateFunctionResolutionBuilder( // parameter IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, IScopeRootParameter scopeRootParameter, + IFunctionResolutionSynchronicityDecisionMaker synchronicityDecisionMaker, // dependencies WellKnownTypes wellKnownTypes, IReferenceGeneratorFactory referenceGeneratorFactory, Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) - : base(rangeResolutionBaseBuilder, scopeRootParameter.ReturnType, scopeRootParameter.CurrentParameters, wellKnownTypes, referenceGeneratorFactory, localFunctionResolutionBuilderFactory) + : base(rangeResolutionBaseBuilder, scopeRootParameter.ReturnType, scopeRootParameter.CurrentParameters, synchronicityDecisionMaker, wellKnownTypes, referenceGeneratorFactory, localFunctionResolutionBuilderFactory) { _rangeResolutionBaseBuilder = rangeResolutionBaseBuilder; _scopeRootParameter = scopeRootParameter; diff --git a/Main/ResolutionBuilding/ITransientScopeImplementationResolutionBuilder.cs b/Main/ResolutionBuilding/ITransientScopeImplementationResolutionBuilder.cs index 60200759..ba4215ba 100644 --- a/Main/ResolutionBuilding/ITransientScopeImplementationResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ITransientScopeImplementationResolutionBuilder.cs @@ -1,3 +1,5 @@ +using MrMeeseeks.DIE.ResolutionBuilding.Function; + namespace MrMeeseeks.DIE.ResolutionBuilding; internal interface ITransientScopeImplementationResolutionBuilder @@ -5,5 +7,6 @@ internal interface ITransientScopeImplementationResolutionBuilder void EnqueueRangedInstanceResolution( ForConstructorParameter parameter, string label, - string reference); + string reference, + Lazy synchronicityDecisionMaker); } \ No newline at end of file diff --git a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs index 65d34e39..d51e217c 100644 --- a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs +++ b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs @@ -1,4 +1,5 @@ using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.ResolutionBuilding.Function; namespace MrMeeseeks.DIE.ResolutionBuilding; @@ -40,6 +41,7 @@ internal abstract class RangeResolutionBaseBuilder : IRangeResolutionBaseBuilder protected readonly WellKnownTypes WellKnownTypes; private readonly Func _rangedFunctionGroupResolutionBuilderFactory; + private readonly Func _synchronicityDecisionMakerFactory; protected readonly IReferenceGenerator RootReferenceGenerator; protected readonly IDictionary RangedInstanceReferenceResolutions = @@ -55,12 +57,14 @@ protected RangeResolutionBaseBuilder( // dependencies WellKnownTypes wellKnownTypes, IReferenceGeneratorFactory referenceGeneratorFactory, - Func rangedFunctionGroupResolutionBuilderFactory) + Func rangedFunctionGroupResolutionBuilderFactory, + Func synchronicityDecisionMakerFactory) { CheckTypeProperties = checkTypeProperties; UserProvidedScopeElements = userProvidedScopeElements; WellKnownTypes = wellKnownTypes; _rangedFunctionGroupResolutionBuilderFactory = rangedFunctionGroupResolutionBuilderFactory; + _synchronicityDecisionMakerFactory = synchronicityDecisionMakerFactory; RootReferenceGenerator = referenceGeneratorFactory.Create(); DisposableCollectionResolution = new DisposableCollectionResolution( @@ -87,7 +91,8 @@ public MultiSynchronicityFunctionCallResolution CreateScopeInstanceReferenceReso parameter, "Scope", null, - "this"); + "this", + new (_synchronicityDecisionMakerFactory)); public abstract TransientScopeRootResolution CreateTransientScopeRootResolution( IScopeRootParameter parameter, @@ -105,7 +110,8 @@ protected MultiSynchronicityFunctionCallResolution CreateRangedInstanceReference ForConstructorParameter parameter, string label, string? reference, - string owningObjectReference) + string owningObjectReference, + Lazy synchronicityDecisionMaker) { var (implementationType, currentParameters) = parameter; InterfaceExtension? interfaceExtension = parameter switch @@ -123,7 +129,7 @@ protected MultiSynchronicityFunctionCallResolution CreateRangedInstanceReference } return functionGroup - .GetInstanceFunction(parameter) + .GetInstanceFunction(parameter, synchronicityDecisionMaker) .BuildFunctionCall(currentParameters, owningObjectReference); } diff --git a/Main/ResolutionBuilding/ResolutionDtos.cs b/Main/ResolutionBuilding/ResolutionDtos.cs index 17929feb..33c13cd5 100644 --- a/Main/ResolutionBuilding/ResolutionDtos.cs +++ b/Main/ResolutionBuilding/ResolutionDtos.cs @@ -152,7 +152,8 @@ internal record ForConstructorParameterWithComposition( internal record RangedInstanceResolutionsQueueItem( ForConstructorParameter Parameter, string Label, - string Reference); + string Reference, + string Key); internal record SwitchTaskParameter((Resolvable, ITaskConsumableResolution?) InnerResolution) : Parameter; diff --git a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs index b98ec375..e4b3c651 100644 --- a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs @@ -40,14 +40,16 @@ internal ScopeResolutionBuilder( WellKnownTypes wellKnownTypes, IReferenceGeneratorFactory referenceGeneratorFactory, Func scopeRootCreateFunctionResolutionBuilderFactory, - Func rangedFunctionGroupResolutionBuilderFactory) + Func rangedFunctionGroupResolutionBuilderFactory, + Func synchronicityDecisionMakerFactory) : base( name, checkTypeProperties, userProvidedScopeElements, wellKnownTypes, referenceGeneratorFactory, - rangedFunctionGroupResolutionBuilderFactory) + rangedFunctionGroupResolutionBuilderFactory, + synchronicityDecisionMakerFactory) { _containerResolutionBuilder = containerResolutionBuilder; _transientScopeInterfaceResolutionBuilder = transientScopeInterfaceResolutionBuilder; diff --git a/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs b/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs index 95b2ad24..cc3ef544 100644 --- a/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs +++ b/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs @@ -19,11 +19,16 @@ internal class TransientScopeInterfaceResolutionBuilder : ITransientScopeInterfa private readonly HashSet _pastQueuedItems = new(); private readonly IList _implementations = new List(); - protected readonly IDictionary RangedInstanceReferenceResolutions = + + private readonly IDictionary _rangedInstanceReferenceResolutions = new Dictionary(); + private readonly IDictionary _synchronicityDecisionMakers = + new Dictionary(); + private readonly WellKnownTypes _wellKnownTypes; private readonly Func _rangedFunctionGroupResolutionBuilderFactory; + private readonly Func _synchronicityDecisionMakerFactory; private readonly string _name; private readonly string _containerAdapterName; @@ -32,10 +37,12 @@ internal class TransientScopeInterfaceResolutionBuilder : ITransientScopeInterfa public TransientScopeInterfaceResolutionBuilder( IReferenceGeneratorFactory referenceGeneratorFactory, WellKnownTypes wellKnownTypes, - Func rangedFunctionGroupResolutionBuilderFactory) + Func rangedFunctionGroupResolutionBuilderFactory, + Func synchronicityDecisionMakerFactory) { _wellKnownTypes = wellKnownTypes; _rangedFunctionGroupResolutionBuilderFactory = rangedFunctionGroupResolutionBuilderFactory; + _synchronicityDecisionMakerFactory = synchronicityDecisionMakerFactory; _rootReferenceGenerator = referenceGeneratorFactory.Create(); _name = _rootReferenceGenerator.Generate("ITransientScope"); @@ -46,11 +53,12 @@ public TransientScopeInterfaceResolutionBuilder( public void AddImplementation(ITransientScopeImplementationResolutionBuilder implementation) { - foreach (var (parameter, label, reference) in _pastQueuedItems) + foreach (var (parameter, label, reference, key) in _pastQueuedItems) implementation.EnqueueRangedInstanceResolution( parameter, label, - reference); + reference, + new (() => _synchronicityDecisionMakers[key])); _implementations.Add(implementation); } @@ -62,7 +70,7 @@ public MultiSynchronicityFunctionCallResolution CreateTransientScopeInstanceRefe containerReference); public TransientScopeInterfaceResolution Build() => new( - RangedInstanceReferenceResolutions.Values.ToList(), + _rangedInstanceReferenceResolutions.Values.ToList(), _name, _containerAdapterName); @@ -79,29 +87,37 @@ private MultiSynchronicityFunctionCallResolution CreateRangedInstanceReferenceRe _ => null }; var key = $"{implementationType.FullName()}{interfaceExtension?.KeySuffix() ?? ""}"; - if (!RangedInstanceReferenceResolutions.TryGetValue(key, out var interfaceDeclaration)) + if (!_rangedInstanceReferenceResolutions.TryGetValue(key, out var interfaceDeclaration)) { var decorationSuffix = interfaceExtension?.RangedNameSuffix() ?? ""; var reference = _rootReferenceGenerator.Generate($"Get{label}Instance", implementationType, decorationSuffix); var queueItem = new RangedInstanceResolutionsQueueItem( parameter, label, - reference); + reference, + key); _pastQueuedItems.Add(queueItem); - + + var synchronicityDecisionMaker = _synchronicityDecisionMakerFactory(); + _synchronicityDecisionMakers[key] = synchronicityDecisionMaker; + foreach (var implementation in _implementations) implementation.EnqueueRangedInstanceResolution( queueItem.Parameter, queueItem.Label, - queueItem.Reference); + queueItem.Reference, + new (() => synchronicityDecisionMaker)); interfaceDeclaration = new InterfaceFunctionDeclarationResolution( reference, implementationType.FullName(), + _wellKnownTypes.Task1.Construct(implementationType).FullName(), + _wellKnownTypes.ValueTask1.Construct(implementationType).FullName(), currentParameters.Select(t => - new ParameterResolution(_rootReferenceGenerator.Generate(t.Type), t.Type.FullName())).ToList()); - RangedInstanceReferenceResolutions[key] = interfaceDeclaration; + new ParameterResolution(_rootReferenceGenerator.Generate(t.Type), t.Type.FullName())).ToList(), + synchronicityDecisionMaker.Decision); + _rangedInstanceReferenceResolutions[key] = interfaceDeclaration; } var returnReference = _rootReferenceGenerator.Generate("ret"); @@ -123,12 +139,12 @@ private MultiSynchronicityFunctionCallResolution CreateRangedInstanceReferenceRe interfaceDeclaration.Parameter.Zip(currentParameters, (p, cp) => (p.Reference, cp.Resolution.Reference)) .ToList()), new(returnReference, - interfaceDeclaration.TypeFullName, _wellKnownTypes.ValueTask1.Construct(implementationType).FullName(), + interfaceDeclaration.TypeFullName, interfaceDeclaration.Reference, owningObjectReference, interfaceDeclaration.Parameter.Zip(currentParameters, (p, cp) => (p.Reference, cp.Resolution.Reference)) .ToList()), - new Lazy(() => SynchronicityDecision.Sync)); // todo solve situation with transient scope instance interface + _synchronicityDecisionMakers[key].Decision); } } \ No newline at end of file diff --git a/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs b/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs index f3b0cffc..e62972ca 100644 --- a/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs @@ -37,14 +37,16 @@ internal TransientScopeResolutionBuilder( WellKnownTypes wellKnownTypes, IReferenceGeneratorFactory referenceGeneratorFactory, Func scopeRootCreateFunctionResolutionBuilderFactory, - Func rangedFunctionGroupResolutionBuilderFactory) + Func rangedFunctionGroupResolutionBuilderFactory, + Func synchronicityDecisionMakerFactory) : base( name, checkTypeProperties, userProvidedScopeElements, wellKnownTypes, referenceGeneratorFactory, - rangedFunctionGroupResolutionBuilderFactory) + rangedFunctionGroupResolutionBuilderFactory, + synchronicityDecisionMakerFactory) { _containerResolutionBuilder = containerResolutionBuilder; _transientScopeInterfaceResolutionBuilder = transientScopeInterfaceResolutionBuilder; @@ -152,9 +154,11 @@ public TransientScopeResolution Build() => public void EnqueueRangedInstanceResolution( ForConstructorParameter parameter, string label, - string reference) => CreateRangedInstanceReferenceResolution( + string reference, + Lazy synchronicityDecisionMaker) => CreateRangedInstanceReferenceResolution( parameter, label, reference, - "Doesn'tMatter"); + "Doesn't Matter, because for interface", + synchronicityDecisionMaker); } \ No newline at end of file diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index 187dad89..79377abb 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -161,7 +161,10 @@ internal record ParameterResolution( internal record InterfaceFunctionDeclarationResolution( string Reference, string TypeFullName, - IReadOnlyList Parameter); + string TaskTypeFullName, + string ValueTaskTypeFullName, + IReadOnlyList Parameter, + Lazy SynchronicityDecision); internal record FuncResolution( string Reference, diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index 413d103f..b12d4980 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -43,13 +43,14 @@ IContainerResolutionBuilder ResolutionTreeFactory(IContainerInfo ci) return new ContainerResolutionBuilder( ci, - new TransientScopeInterfaceResolutionBuilder(referenceGeneratorFactory, wellKnownTypes, RangedFunctionGroupResolutionBuilderFactory), + new TransientScopeInterfaceResolutionBuilder(referenceGeneratorFactory, wellKnownTypes, RangedFunctionGroupResolutionBuilderFactory, FunctionResolutionSynchronicityDecisionMakerFactory), referenceGeneratorFactory, new CheckTypeProperties(new CurrentlyConsideredTypes(containerTypesFromAttributesList, context)), wellKnownTypes, ScopeManagerFactory, ContainerCreateFunctionResolutionBuilderFactory, RangedFunctionGroupResolutionBuilderFactory, + FunctionResolutionSynchronicityDecisionMakerFactory, new UserProvidedScopeElements(ci.ContainerType)); IScopeManager ScopeManagerFactory( @@ -84,7 +85,8 @@ ITransientScopeResolutionBuilder TransientScopeResolutionBuilderFactory( wellKnownTypes, referenceGeneratorFactory, ScopeRootCreateFunctionResolutionBuilderFactory, - RangedFunctionGroupResolutionBuilderFactory); + RangedFunctionGroupResolutionBuilderFactory, + FunctionResolutionSynchronicityDecisionMakerFactory); IScopeResolutionBuilder ScopeResolutionBuilderFactory( string name, IContainerResolutionBuilder containerBuilder, @@ -102,7 +104,8 @@ IScopeResolutionBuilder ScopeResolutionBuilderFactory( wellKnownTypes, referenceGeneratorFactory, ScopeRootCreateFunctionResolutionBuilderFactory, - RangedFunctionGroupResolutionBuilderFactory); + RangedFunctionGroupResolutionBuilderFactory, + FunctionResolutionSynchronicityDecisionMakerFactory); ILocalFunctionResolutionBuilder LocalFunctionResolutionBuilderFactory( IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, @@ -111,6 +114,7 @@ ILocalFunctionResolutionBuilder LocalFunctionResolutionBuilderFactory( rangeResolutionBaseBuilder, returnType, parameters, + FunctionResolutionSynchronicityDecisionMakerFactory(), wellKnownTypes, referenceGeneratorFactory, @@ -121,6 +125,7 @@ IContainerCreateFunctionResolutionBuilder ContainerCreateFunctionResolutionBuild INamedTypeSymbol returnType) => new ContainerCreateFunctionResolutionBuilder( rangeResolutionBaseBuilder, returnType, + FunctionResolutionSynchronicityDecisionMakerFactory(), wellKnownTypes, referenceGeneratorFactory, @@ -131,6 +136,7 @@ IScopeRootCreateFunctionResolutionBuilder ScopeRootCreateFunctionResolutionBuild IScopeRootParameter scopeRootParameter) => new ScopeRootCreateFunctionResolutionBuilder( rangeResolutionBaseBuilder, scopeRootParameter, + FunctionResolutionSynchronicityDecisionMakerFactory(), wellKnownTypes, referenceGeneratorFactory, @@ -139,10 +145,12 @@ IScopeRootCreateFunctionResolutionBuilder ScopeRootCreateFunctionResolutionBuild IRangedFunctionResolutionBuilder RangedFunctionResolutionBuilderFactory( IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, string reference, - ForConstructorParameter forConstructorParameter) => new RangedFunctionResolutionBuilder( + ForConstructorParameter forConstructorParameter, + IFunctionResolutionSynchronicityDecisionMaker synchronicityDecisionMaker) => new RangedFunctionResolutionBuilder( rangeResolutionBaseBuilder, reference, forConstructorParameter, + synchronicityDecisionMaker, wellKnownTypes, referenceGeneratorFactory, @@ -162,6 +170,9 @@ IRangedFunctionGroupResolutionBuilder RangedFunctionGroupResolutionBuilderFactor referenceGeneratorFactory, RangedFunctionResolutionBuilderFactory); + + IFunctionResolutionSynchronicityDecisionMaker FunctionResolutionSynchronicityDecisionMakerFactory() => + new FunctionResolutionSynchronicityDecisionMaker(); } IContainerInfo ContainerInfoFactory(INamedTypeSymbol type) => new ContainerInfo(type, wellKnownTypes); IReferenceGenerator ReferenceGeneratorFactory(int j) => new ReferenceGenerator(j); diff --git a/Sample/Context.cs b/Sample/Context.cs index 03bb7a7e..15c06186 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -1,62 +1,19 @@ -using MrMeeseeks.DIE.Configuration; -using MrMeeseeks.DIE.Sample; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; -namespace MrMeeseeks.DIE.Test.Decorator.SequenceEdgeCase; - -internal interface IInterface -{ - IInterface Decorated { get; } -} - -internal class Dependency : IInterface, IContainerInstance -{ - public IInterface Decorated => this; -} - -internal class DecoratorA : IInterface, IDecorator +namespace MrMeeseeks.DIE.Sample; +internal class Dependency : ITaskTypeInitializer, ITransientScopeInstance { - public IInterface Decorated { get; } + public bool IsInitialized { get; private set; } - internal DecoratorA(IInterface decorated) => Decorated = decorated; -} - -internal class DecoratorB : IInterface, IDecorator -{ - public IInterface Decorated { get; } - - internal DecoratorB(IInterface decorated) => Decorated = decorated; -} - -internal class ScopeRoot0 : IScopeRoot -{ - public IInterface Decorated { get; } - - internal ScopeRoot0(IInterface decorated) => Decorated = decorated; -} - -internal class ScopeRoot1 : IScopeRoot -{ - public IInterface Decorated { get; } - - internal ScopeRoot1(IInterface decorated) => Decorated = decorated; + async Task ITaskTypeInitializer.InitializeAsync() + { + await Task.Delay(500).ConfigureAwait(false); + IsInitialized = true; + } } -[CreateFunction(typeof(ScopeRoot0), "Create0")] -[CreateFunction(typeof(ScopeRoot1), "Create1")] -[DecoratorSequenceChoice(typeof(IInterface), typeof(DecoratorA), typeof(DecoratorB))] +[CreateFunction(typeof(Task), "Create")] internal partial class Container { - [DecoratorSequenceChoice(typeof(IInterface), typeof(DecoratorA), typeof(DecoratorB))] - [CustomScopeForRootTypes(typeof(ScopeRoot0))] - private partial class DIE_Scope_0 - { - - } - - [DecoratorSequenceChoice(typeof(IInterface), typeof(DecoratorA))] - [CustomScopeForRootTypes(typeof(ScopeRoot1))] - private partial class DIE_Scope_1 - { - - } } \ No newline at end of file diff --git a/Sample/Program.cs b/Sample/Program.cs index 18bac0cb..497ea562 100644 --- a/Sample/Program.cs +++ b/Sample/Program.cs @@ -1,12 +1,9 @@ using System; -using MrMeeseeks.DIE.Test.Decorator.SequenceEdgeCase; internal class Program { private static void Main() { Console.WriteLine("Hello, world!"); - var container = new Container(); - Console.WriteLine(container.Create0Async()); } } \ No newline at end of file diff --git a/Test/Async/Awaited/ContainerInstanceFunctionAsTask.cs b/Test/Async/Awaited/ContainerInstanceFunctionAsTask.cs new file mode 100644 index 00000000..bc375411 --- /dev/null +++ b/Test/Async/Awaited/ContainerInstanceFunctionAsTask.cs @@ -0,0 +1,33 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Async.Awaited.ContainerInstanceFunctionAsTask; + + +internal class Dependency : ITaskTypeInitializer, IContainerInstance +{ + public bool IsInitialized { get; private set; } + + async Task ITaskTypeInitializer.InitializeAsync() + { + await Task.Delay(500).ConfigureAwait(false); + IsInitialized = true; + } +} + +[CreateFunction(typeof(Dependency), "Create")] +internal partial class Container +{ +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + using var container = new Container(); + var instance = container.CreateValueAsync(); + Assert.True((await instance.ConfigureAwait(false)).IsInitialized); + } +} \ No newline at end of file diff --git a/Test/Async/Awaited/ContainerInstanceFunctionAsValueTask.cs b/Test/Async/Awaited/ContainerInstanceFunctionAsValueTask.cs new file mode 100644 index 00000000..8c5d993d --- /dev/null +++ b/Test/Async/Awaited/ContainerInstanceFunctionAsValueTask.cs @@ -0,0 +1,33 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Async.Awaited.ContainerInstanceFunctionAsValueTask; + + +internal class Dependency : ITaskTypeInitializer, IContainerInstance +{ + public bool IsInitialized { get; private set; } + + async Task ITaskTypeInitializer.InitializeAsync() + { + await Task.Delay(500).ConfigureAwait(false); + IsInitialized = true; + } +} + +[CreateFunction(typeof(Dependency), "Create")] +internal partial class Container +{ +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + using var container = new Container(); + var instance = container.CreateValueAsync(); + Assert.True((await instance.ConfigureAwait(false)).IsInitialized); + } +} \ No newline at end of file diff --git a/Test/Async/Awaited/ScopeInstanceFunctionAsTask.cs b/Test/Async/Awaited/ScopeInstanceFunctionAsTask.cs new file mode 100644 index 00000000..ebf4d810 --- /dev/null +++ b/Test/Async/Awaited/ScopeInstanceFunctionAsTask.cs @@ -0,0 +1,33 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Async.Awaited.ScopeInstanceFunctionAsTask; + + +internal class Dependency : ITaskTypeInitializer, IScopeInstance +{ + public bool IsInitialized { get; private set; } + + async Task ITaskTypeInitializer.InitializeAsync() + { + await Task.Delay(500).ConfigureAwait(false); + IsInitialized = true; + } +} + +[CreateFunction(typeof(Dependency), "Create")] +internal partial class Container +{ +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + using var container = new Container(); + var instance = container.CreateValueAsync(); + Assert.True((await instance.ConfigureAwait(false)).IsInitialized); + } +} \ No newline at end of file diff --git a/Test/Async/Awaited/ScopeInstanceFunctionAsValueTask.cs b/Test/Async/Awaited/ScopeInstanceFunctionAsValueTask.cs new file mode 100644 index 00000000..eae807cb --- /dev/null +++ b/Test/Async/Awaited/ScopeInstanceFunctionAsValueTask.cs @@ -0,0 +1,33 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Async.Awaited.ScopeInstanceFunctionAsValueTask; + + +internal class Dependency : ITaskTypeInitializer, IScopeInstance +{ + public bool IsInitialized { get; private set; } + + async Task ITaskTypeInitializer.InitializeAsync() + { + await Task.Delay(500).ConfigureAwait(false); + IsInitialized = true; + } +} + +[CreateFunction(typeof(Dependency), "Create")] +internal partial class Container +{ +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + using var container = new Container(); + var instance = container.CreateValueAsync(); + Assert.True((await instance.ConfigureAwait(false)).IsInitialized); + } +} \ No newline at end of file diff --git a/Test/Async/Awaited/TransientScopeInstanceFunctionAsTask.cs b/Test/Async/Awaited/TransientScopeInstanceFunctionAsTask.cs new file mode 100644 index 00000000..f9bc8330 --- /dev/null +++ b/Test/Async/Awaited/TransientScopeInstanceFunctionAsTask.cs @@ -0,0 +1,32 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Async.Awaited.TransientScopeInstanceFunctionAsTask; + +internal class Dependency : ITaskTypeInitializer, ITransientScopeInstance +{ + public bool IsInitialized { get; private set; } + + async Task ITaskTypeInitializer.InitializeAsync() + { + await Task.Delay(500).ConfigureAwait(false); + IsInitialized = true; + } +} + +[CreateFunction(typeof(Dependency), "Create")] +internal partial class Container +{ +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + using var container = new Container(); + var instance = container.CreateValueAsync(); + Assert.True((await instance.ConfigureAwait(false)).IsInitialized); + } +} \ No newline at end of file diff --git a/Test/Async/Awaited/TransientScopeInstanceFunctionAsValueTask.cs b/Test/Async/Awaited/TransientScopeInstanceFunctionAsValueTask.cs new file mode 100644 index 00000000..a4a83c47 --- /dev/null +++ b/Test/Async/Awaited/TransientScopeInstanceFunctionAsValueTask.cs @@ -0,0 +1,32 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Async.Awaited.TransientScopeInstanceFunctionAsValueTask; + +internal class Dependency : ITaskTypeInitializer, ITransientScopeInstance +{ + public bool IsInitialized { get; private set; } + + async Task ITaskTypeInitializer.InitializeAsync() + { + await Task.Delay(500).ConfigureAwait(false); + IsInitialized = true; + } +} + +[CreateFunction(typeof(Dependency), "Create")] +internal partial class Container +{ +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + using var container = new Container(); + var instance = container.CreateValueAsync(); + Assert.True((await instance.ConfigureAwait(false)).IsInitialized); + } +} \ No newline at end of file diff --git a/Test/Async/Wrapped/ContainerInstanceFunctionAsTask.cs b/Test/Async/Wrapped/ContainerInstanceFunctionAsTask.cs new file mode 100644 index 00000000..e638db1e --- /dev/null +++ b/Test/Async/Wrapped/ContainerInstanceFunctionAsTask.cs @@ -0,0 +1,33 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Async.Wrapped.ContainerInstanceFunctionAsTask; + + +internal class Dependency : ITaskTypeInitializer, IContainerInstance +{ + public bool IsInitialized { get; private set; } + + async Task ITaskTypeInitializer.InitializeAsync() + { + await Task.Delay(500).ConfigureAwait(false); + IsInitialized = true; + } +} + +[CreateFunction(typeof(Task), "Create")] +internal partial class Container +{ +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + using var container = new Container(); + var instance = container.Create(); + Assert.True((await instance.ConfigureAwait(false)).IsInitialized); + } +} \ No newline at end of file diff --git a/Test/Async/Wrapped/ContainerInstanceFunctionAsValueTask.cs b/Test/Async/Wrapped/ContainerInstanceFunctionAsValueTask.cs new file mode 100644 index 00000000..cbaba179 --- /dev/null +++ b/Test/Async/Wrapped/ContainerInstanceFunctionAsValueTask.cs @@ -0,0 +1,33 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Async.Wrapped.ContainerInstanceFunctionAsValueTask; + + +internal class Dependency : ITaskTypeInitializer, IContainerInstance +{ + public bool IsInitialized { get; private set; } + + async Task ITaskTypeInitializer.InitializeAsync() + { + await Task.Delay(500).ConfigureAwait(false); + IsInitialized = true; + } +} + +[CreateFunction(typeof(ValueTask), "Create")] +internal partial class Container +{ +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + using var container = new Container(); + var instance = container.Create(); + Assert.True((await instance.ConfigureAwait(false)).IsInitialized); + } +} \ No newline at end of file diff --git a/Test/Async/WrappedDependency/DecorationChaining.cs b/Test/Async/Wrapped/DecorationChaining.cs similarity index 95% rename from Test/Async/WrappedDependency/DecorationChaining.cs rename to Test/Async/Wrapped/DecorationChaining.cs index 779db96d..92a453eb 100644 --- a/Test/Async/WrappedDependency/DecorationChaining.cs +++ b/Test/Async/Wrapped/DecorationChaining.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration; using Xunit; -namespace MrMeeseeks.DIE.Test.Async.WrappedDependency.DecorationChaining; +namespace MrMeeseeks.DIE.Test.Async.Wrapped.DecorationChaining; internal interface IInterface { diff --git a/Test/Async/WrappedDependency/Func.cs b/Test/Async/Wrapped/Func.cs similarity index 92% rename from Test/Async/WrappedDependency/Func.cs rename to Test/Async/Wrapped/Func.cs index dd497ad7..2d3e2df9 100644 --- a/Test/Async/WrappedDependency/Func.cs +++ b/Test/Async/Wrapped/Func.cs @@ -3,7 +3,7 @@ using MrMeeseeks.DIE.Configuration; using Xunit; -namespace MrMeeseeks.DIE.Test.Async.WrappedDependency.Func; +namespace MrMeeseeks.DIE.Test.Async.Wrapped.Func; internal class Dependency : ITaskTypeInitializer diff --git a/Test/Async/WrappedDependency/Lazy.cs b/Test/Async/Wrapped/Lazy.cs similarity index 92% rename from Test/Async/WrappedDependency/Lazy.cs rename to Test/Async/Wrapped/Lazy.cs index e3fccb9d..369d8e8c 100644 --- a/Test/Async/WrappedDependency/Lazy.cs +++ b/Test/Async/Wrapped/Lazy.cs @@ -4,7 +4,7 @@ using MrMeeseeks.DIE.Configuration; using Xunit; -namespace MrMeeseeks.DIE.Test.Async.WrappedDependency.Lazy; +namespace MrMeeseeks.DIE.Test.Async.Wrapped.Lazy; internal class Dependency : ITaskTypeInitializer diff --git a/Test/Async/Wrapped/ScopeInstanceFunctionAsTask.cs b/Test/Async/Wrapped/ScopeInstanceFunctionAsTask.cs new file mode 100644 index 00000000..83e38d25 --- /dev/null +++ b/Test/Async/Wrapped/ScopeInstanceFunctionAsTask.cs @@ -0,0 +1,33 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Async.Wrapped.ScopeInstanceFunctionAsTask; + + +internal class Dependency : ITaskTypeInitializer, IScopeInstance +{ + public bool IsInitialized { get; private set; } + + async Task ITaskTypeInitializer.InitializeAsync() + { + await Task.Delay(500).ConfigureAwait(false); + IsInitialized = true; + } +} + +[CreateFunction(typeof(Task), "Create")] +internal partial class Container +{ +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + using var container = new Container(); + var instance = container.Create(); + Assert.True((await instance.ConfigureAwait(false)).IsInitialized); + } +} \ No newline at end of file diff --git a/Test/Async/Wrapped/ScopeInstanceFunctionAsValueTask.cs b/Test/Async/Wrapped/ScopeInstanceFunctionAsValueTask.cs new file mode 100644 index 00000000..db74cd0c --- /dev/null +++ b/Test/Async/Wrapped/ScopeInstanceFunctionAsValueTask.cs @@ -0,0 +1,33 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Async.Wrapped.ScopeInstanceFunctionAsValueTask; + + +internal class Dependency : ITaskTypeInitializer, IScopeInstance +{ + public bool IsInitialized { get; private set; } + + async Task ITaskTypeInitializer.InitializeAsync() + { + await Task.Delay(500).ConfigureAwait(false); + IsInitialized = true; + } +} + +[CreateFunction(typeof(ValueTask), "Create")] +internal partial class Container +{ +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + using var container = new Container(); + var instance = container.Create(); + Assert.True((await instance.ConfigureAwait(false)).IsInitialized); + } +} \ No newline at end of file diff --git a/Test/Async/WrappedDependency/SyncToTask.cs b/Test/Async/Wrapped/SyncToTask.cs similarity index 90% rename from Test/Async/WrappedDependency/SyncToTask.cs rename to Test/Async/Wrapped/SyncToTask.cs index bc25e21a..d0fea881 100644 --- a/Test/Async/WrappedDependency/SyncToTask.cs +++ b/Test/Async/Wrapped/SyncToTask.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration; using Xunit; -namespace MrMeeseeks.DIE.Test.Async.WrappedDependency.SyncToTask; +namespace MrMeeseeks.DIE.Test.Async.Wrapped.SyncToTask; internal class Dependency : ITypeInitializer { diff --git a/Test/Async/WrappedDependency/SyncToValueTask.cs b/Test/Async/Wrapped/SyncToValueTask.cs similarity index 85% rename from Test/Async/WrappedDependency/SyncToValueTask.cs rename to Test/Async/Wrapped/SyncToValueTask.cs index 9fea057f..2c76f5ba 100644 --- a/Test/Async/WrappedDependency/SyncToValueTask.cs +++ b/Test/Async/Wrapped/SyncToValueTask.cs @@ -1,9 +1,8 @@ -using System.Collections.Generic; using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration; using Xunit; -namespace MrMeeseeks.DIE.Test.Async.WrappedDependency.SyncToValueTask; +namespace MrMeeseeks.DIE.Test.Async.Wrapped.SyncToValueTask; internal class Dependency : ITypeInitializer { diff --git a/Test/Async/WrappedDependency/TaskCollection.cs b/Test/Async/Wrapped/TaskCollection.cs similarity index 95% rename from Test/Async/WrappedDependency/TaskCollection.cs rename to Test/Async/Wrapped/TaskCollection.cs index 38911e99..58d61429 100644 --- a/Test/Async/WrappedDependency/TaskCollection.cs +++ b/Test/Async/Wrapped/TaskCollection.cs @@ -3,7 +3,7 @@ using MrMeeseeks.DIE.Configuration; using Xunit; -namespace MrMeeseeks.DIE.Test.Async.WrappedDependency.TaskCollection; +namespace MrMeeseeks.DIE.Test.Async.Wrapped.TaskCollection; internal interface IInterface { diff --git a/Test/Async/WrappedDependency/TaskComposition.cs b/Test/Async/Wrapped/TaskComposition.cs similarity index 96% rename from Test/Async/WrappedDependency/TaskComposition.cs rename to Test/Async/Wrapped/TaskComposition.cs index 60f3e4a3..b8f64976 100644 --- a/Test/Async/WrappedDependency/TaskComposition.cs +++ b/Test/Async/Wrapped/TaskComposition.cs @@ -3,7 +3,7 @@ using MrMeeseeks.DIE.Configuration; using Xunit; -namespace MrMeeseeks.DIE.Test.Async.WrappedDependency.TaskComposition; +namespace MrMeeseeks.DIE.Test.Async.Wrapped.TaskComposition; internal interface IInterface { diff --git a/Test/Async/WrappedDependency/TaskToTask.cs b/Test/Async/Wrapped/TaskToTask.cs similarity index 91% rename from Test/Async/WrappedDependency/TaskToTask.cs rename to Test/Async/Wrapped/TaskToTask.cs index 6fa4b787..61a5bcf1 100644 --- a/Test/Async/WrappedDependency/TaskToTask.cs +++ b/Test/Async/Wrapped/TaskToTask.cs @@ -3,7 +3,7 @@ using MrMeeseeks.DIE.Configuration; using Xunit; -namespace MrMeeseeks.DIE.Test.Async.WrappedDependency.TaskToTask; +namespace MrMeeseeks.DIE.Test.Async.Wrapped.TaskToTask; internal class Dependency : ITaskTypeInitializer { diff --git a/Test/Async/WrappedDependency/TaskToValueTask.cs b/Test/Async/Wrapped/TaskToValueTask.cs similarity index 91% rename from Test/Async/WrappedDependency/TaskToValueTask.cs rename to Test/Async/Wrapped/TaskToValueTask.cs index 50ab5b7d..f979c96b 100644 --- a/Test/Async/WrappedDependency/TaskToValueTask.cs +++ b/Test/Async/Wrapped/TaskToValueTask.cs @@ -3,7 +3,7 @@ using MrMeeseeks.DIE.Configuration; using Xunit; -namespace MrMeeseeks.DIE.Test.Async.WrappedDependency.TaskToValueTask; +namespace MrMeeseeks.DIE.Test.Async.Wrapped.TaskToValueTask; internal class Dependency : ITaskTypeInitializer { diff --git a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask.cs b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask.cs new file mode 100644 index 00000000..71a4df38 --- /dev/null +++ b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask.cs @@ -0,0 +1,32 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Async.Wrapped.TransientScopeInstanceFunctionAsTask; + +internal class Dependency : ITaskTypeInitializer, ITransientScopeInstance +{ + public bool IsInitialized { get; private set; } + + async Task ITaskTypeInitializer.InitializeAsync() + { + await Task.Delay(500).ConfigureAwait(false); + IsInitialized = true; + } +} + +[CreateFunction(typeof(Task), "Create")] +internal partial class Container +{ +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + using var container = new Container(); + var instance = container.Create(); + Assert.True((await instance.ConfigureAwait(false)).IsInitialized); + } +} \ No newline at end of file diff --git a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask.cs b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask.cs new file mode 100644 index 00000000..245368ab --- /dev/null +++ b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask.cs @@ -0,0 +1,32 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Async.Wrapped.TransientScopeInstanceFunctionAsValueTask; + +internal class Dependency : ITaskTypeInitializer, ITransientScopeInstance +{ + public bool IsInitialized { get; private set; } + + async Task ITaskTypeInitializer.InitializeAsync() + { + await Task.Delay(500).ConfigureAwait(false); + IsInitialized = true; + } +} + +[CreateFunction(typeof(ValueTask), "Create")] +internal partial class Container +{ +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + using var container = new Container(); + var instance = container.Create(); + Assert.True((await instance.ConfigureAwait(false)).IsInitialized); + } +} \ No newline at end of file diff --git a/Test/Async/WrappedDependency/ValueTaskCollection.cs b/Test/Async/Wrapped/ValueTaskCollection.cs similarity index 95% rename from Test/Async/WrappedDependency/ValueTaskCollection.cs rename to Test/Async/Wrapped/ValueTaskCollection.cs index 5a05f471..94e0b00b 100644 --- a/Test/Async/WrappedDependency/ValueTaskCollection.cs +++ b/Test/Async/Wrapped/ValueTaskCollection.cs @@ -3,7 +3,7 @@ using MrMeeseeks.DIE.Configuration; using Xunit; -namespace MrMeeseeks.DIE.Test.Async.WrappedDependency.ValueTaskCollection; +namespace MrMeeseeks.DIE.Test.Async.Wrapped.ValueTaskCollection; internal interface IInterface { diff --git a/Test/Async/WrappedDependency/ValueTaskComposition.cs b/Test/Async/Wrapped/ValueTaskComposition.cs similarity index 96% rename from Test/Async/WrappedDependency/ValueTaskComposition.cs rename to Test/Async/Wrapped/ValueTaskComposition.cs index 0ce325d0..fba71c64 100644 --- a/Test/Async/WrappedDependency/ValueTaskComposition.cs +++ b/Test/Async/Wrapped/ValueTaskComposition.cs @@ -3,7 +3,7 @@ using MrMeeseeks.DIE.Configuration; using Xunit; -namespace MrMeeseeks.DIE.Test.Async.WrappedDependency.ValueTaskComposition; +namespace MrMeeseeks.DIE.Test.Async.Wrapped.ValueTaskComposition; internal interface IInterface { diff --git a/Test/Async/WrappedDependency/ValueTaskToTask.cs b/Test/Async/Wrapped/ValueTaskToTask.cs similarity index 91% rename from Test/Async/WrappedDependency/ValueTaskToTask.cs rename to Test/Async/Wrapped/ValueTaskToTask.cs index 43d6efb6..ee5370b7 100644 --- a/Test/Async/WrappedDependency/ValueTaskToTask.cs +++ b/Test/Async/Wrapped/ValueTaskToTask.cs @@ -3,7 +3,7 @@ using MrMeeseeks.DIE.Configuration; using Xunit; -namespace MrMeeseeks.DIE.Test.Async.WrappedDependency.ValueTaskToTask; +namespace MrMeeseeks.DIE.Test.Async.Wrapped.ValueTaskToTask; internal class Dependency : IValueTaskTypeInitializer { diff --git a/Test/Async/WrappedDependency/ValueTaskToValueTask.cs b/Test/Async/Wrapped/ValueTaskToValueTask.cs similarity index 90% rename from Test/Async/WrappedDependency/ValueTaskToValueTask.cs rename to Test/Async/Wrapped/ValueTaskToValueTask.cs index 4229e442..1612a630 100644 --- a/Test/Async/WrappedDependency/ValueTaskToValueTask.cs +++ b/Test/Async/Wrapped/ValueTaskToValueTask.cs @@ -3,7 +3,7 @@ using MrMeeseeks.DIE.Configuration; using Xunit; -namespace MrMeeseeks.DIE.Test.Async.WrappedDependency.ValueTaskToValueTask; +namespace MrMeeseeks.DIE.Test.Async.Wrapped.ValueTaskToValueTask; internal class Dependency : IValueTaskTypeInitializer { diff --git a/Test/Decorator/ContainerInstance.cs b/Test/Decorator/ContainerInstance.cs new file mode 100644 index 00000000..ffa8c9da --- /dev/null +++ b/Test/Decorator/ContainerInstance.cs @@ -0,0 +1,45 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Decorator.ContainerInstance; + +internal interface IInterface +{ + IInterface Decorated { get; } +} + +internal class Dependency : IInterface, IContainerInstance +{ + public IInterface Decorated => this; +} + +internal class Decorator : IInterface, IDecorator +{ + public Decorator(IInterface decoratedContainerInstance) => + Decorated = decoratedContainerInstance; + + public IInterface Decorated { get; } +} + +[CreateFunction(typeof(IInterface), "Create")] +internal partial class Container +{ + +} + +public class Tests +{ + [Fact] + public void Test() + { + using var container = new Container(); + var decorated = container.Create(); + Assert.NotEqual(decorated, decorated.Decorated); + Assert.IsType(decorated); + Assert.IsType(decorated.Decorated); + + var decoratedNextReference = container.Create(); + Assert.Equal(decorated, decoratedNextReference); + Assert.Equal(decorated.Decorated, decoratedNextReference.Decorated); + } +} \ No newline at end of file diff --git a/Test/Decorator/List.cs b/Test/Decorator/List.cs new file mode 100644 index 00000000..3df164c1 --- /dev/null +++ b/Test/Decorator/List.cs @@ -0,0 +1,56 @@ +using System.Collections.Generic; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Decorator.List; + +internal interface IInterface +{ + IInterface Decorated { get; } +} + +internal class DependencyA : IInterface +{ + public IInterface Decorated => this; +} + +internal class DependencyB : IInterface +{ + public IInterface Decorated => this; +} + +internal class Decorator : IInterface, IDecorator +{ + public Decorator(IInterface decorated) => + Decorated = decorated; + + public IInterface Decorated { get; } +} + +[CreateFunction(typeof(IReadOnlyList), "Create")] +internal partial class Container +{ + +} + +public class Tests +{ + [Fact] + public void Test() + { + using var container = new Container(); + var decorated = container.Create(); + var decoratedOfA = decorated[0]; + var decoratedOfB = decorated[1]; + var decoratedBasisA = decoratedOfA.Decorated; + var decoratedBasisB = decoratedOfB.Decorated; + Assert.NotEqual(decoratedOfA, decoratedBasisA); + Assert.NotEqual(decoratedOfB, decoratedBasisB); + Assert.NotEqual(decoratedOfA, decoratedOfB); + Assert.NotEqual(decoratedBasisA, decoratedBasisB); + Assert.IsType(decoratedOfA); + Assert.IsType(decoratedOfB); + Assert.IsType(decoratedBasisA); + Assert.IsType(decoratedBasisB); + } +} \ No newline at end of file diff --git a/Test/Decorator/Multi.cs b/Test/Decorator/Multi.cs new file mode 100644 index 00000000..89af08d9 --- /dev/null +++ b/Test/Decorator/Multi.cs @@ -0,0 +1,56 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Decorator.Multi; + +internal interface IInterface +{ + IInterface Decorated { get; } +} + +internal class Dependency : IInterface +{ + public IInterface Decorated => this; +} + +internal class DecoratorA : IInterface, IDecorator +{ + public DecoratorA(IInterface decorated) => + Decorated = decorated; + + public IInterface Decorated { get; } +} + +internal class DecoratorB : IInterface, IDecorator +{ + public DecoratorB(IInterface decorated) => + Decorated = decorated; + + public IInterface Decorated { get; } +} + +[CreateFunction(typeof(IInterface), "Create")] +[DecoratorSequenceChoice(typeof(IInterface), typeof(DecoratorA), typeof(DecoratorB))] +internal partial class Container +{ + +} + +public class Tests +{ + [Fact] + public void Test() + { + using var container = new Container(); + var decorated = container.Create(); + var decoratedB = decorated; + var decoratedA = decorated.Decorated; + var decoratedBasis = decoratedA.Decorated; + Assert.NotEqual(decoratedBasis, decoratedA); + Assert.NotEqual(decoratedBasis, decoratedB); + Assert.NotEqual(decoratedA, decoratedB); + Assert.IsType(decoratedBasis); + Assert.IsType(decoratedA); + Assert.IsType(decoratedB); + } +} \ No newline at end of file diff --git a/Test/Decorator/Normal.cs b/Test/Decorator/Normal.cs new file mode 100644 index 00000000..04b64702 --- /dev/null +++ b/Test/Decorator/Normal.cs @@ -0,0 +1,41 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Decorator.Normal; + +internal interface IInterface +{ + IInterface Decorated { get; } +} + +internal class Dependency : IInterface +{ + public IInterface Decorated => this; +} + +internal class Decorator : IInterface, IDecorator +{ + public Decorator(IInterface decoratedNormal) => + Decorated = decoratedNormal; + + public IInterface Decorated { get; } +} + +[CreateFunction(typeof(IInterface), "Create")] +internal partial class Container +{ + +} + +public class Tests +{ + [Fact] + public void Test() + { + using var container = new Container(); + var decorated = container.Create(); + Assert.NotEqual(decorated, decorated.Decorated); + Assert.IsType(decorated); + Assert.IsType(decorated.Decorated); + } +} \ No newline at end of file diff --git a/Test/DecoratorTests.cs b/Test/DecoratorTests.cs deleted file mode 100644 index 4763cb0b..00000000 --- a/Test/DecoratorTests.cs +++ /dev/null @@ -1,246 +0,0 @@ -using System.Collections.Generic; -using MrMeeseeks.DIE.Configuration; -using MrMeeseeks.DIE.Test; -using Xunit; - -[assembly:DecoratorSequenceChoice(typeof(IDecoratedMulti), typeof(DecoratorMultiA), typeof(DecoratorMultiB))] - -namespace MrMeeseeks.DIE.Test; - -internal interface IDecoratedNormal -{ - IDecoratedNormal Decorated { get; } -} - -internal class DecoratorNormalBasis : IDecoratedNormal -{ - public IDecoratedNormal Decorated => this; -} - -internal class DecoratorNormal : IDecoratedNormal, IDecorator -{ - public DecoratorNormal(IDecoratedNormal decoratedNormal) => - Decorated = decoratedNormal; - - public IDecoratedNormal Decorated { get; } -} - -[CreateFunction(typeof(IDecoratedNormal), "CreateDep")] -internal partial class DecoratorNormalContainer -{ - -} - -public partial class DecoratorTests -{ - [Fact] - public void Normal() - { - using var container = new DecoratorNormalContainer(); - var decorated = container.CreateDep(); - Assert.NotEqual(decorated, decorated.Decorated); - Assert.IsType(decorated); - Assert.IsType(decorated.Decorated); - } -} - -internal interface IDecoratedContainerInstance -{ - IDecoratedContainerInstance Decorated { get; } -} - -internal class DecoratorContainerInstanceBasis : IDecoratedContainerInstance, IContainerInstance -{ - public IDecoratedContainerInstance Decorated => this; -} - -internal class DecoratorContainerInstance : IDecoratedContainerInstance, IDecorator -{ - public DecoratorContainerInstance(IDecoratedContainerInstance decoratedContainerInstance) => - Decorated = decoratedContainerInstance; - - public IDecoratedContainerInstance Decorated { get; } -} - -[CreateFunction(typeof(IDecoratedContainerInstance), "CreateDep")] -internal partial class DecoratorContainerInstanceContainer -{ - -} - -public partial class DecoratorTests -{ - [Fact] - public void ContainerInstance() - { - using var container = new DecoratorContainerInstanceContainer(); - var decorated = container.CreateDep(); - Assert.NotEqual(decorated, decorated.Decorated); - Assert.IsType(decorated); - Assert.IsType(decorated.Decorated); - - var decoratedNextReference = container.CreateDep(); - Assert.Equal(decorated, decoratedNextReference); - Assert.Equal(decorated.Decorated, decoratedNextReference.Decorated); - } -} - -internal interface IDecoratedScopeRoot -{ - IDecoratedScopeRootDependency Dependency { get; } - IDecoratedScopeRoot Decorated { get; } -} - -internal interface IDecoratedScopeRootDependency {} - -internal class DecoratedScopeRootDependency : IDecoratedScopeRootDependency, IScopeInstance {} - -internal class DecoratorScopeRootBasis : IDecoratedScopeRoot, IScopeRoot, IScopeInstance -{ - public IDecoratedScopeRootDependency Dependency { get; } - - public IDecoratedScopeRoot Decorated => this; - - public DecoratorScopeRootBasis( - IDecoratedScopeRootDependency dependency) => - Dependency = dependency; -} - -internal class DecoratorScopeRoot : IDecoratedScopeRoot, IDecorator -{ - public DecoratorScopeRoot(IDecoratedScopeRoot decorated, IDecoratedScopeRootDependency dependency) - { - Decorated = decorated; - Dependency = dependency; - } - - public IDecoratedScopeRootDependency Dependency { get; } - public IDecoratedScopeRoot Decorated { get; } -} - -[CreateFunction(typeof(IDecoratedScopeRoot), "CreateDep")] -internal partial class DecoratorScopeRootContainer -{ - -} - -public partial class DecoratorTests -{ - [Fact] - public void ScopeRoot() - { - using var container = new DecoratorScopeRootContainer(); - var decorated = container.CreateDep(); - Assert.NotEqual(decorated, decorated.Decorated); - Assert.Equal(decorated.Dependency, decorated.Decorated.Dependency); - Assert.IsType(decorated); - Assert.IsType(decorated.Decorated); - - // There is yet no way to check scopes externally - var next = container.CreateDep(); - Assert.NotEqual(decorated, next); - Assert.NotEqual(decorated.Dependency, next.Dependency); - } -} - -internal interface IDecoratedMulti -{ - IDecoratedMulti Decorated { get; } -} - -internal class DecoratorMultiBasis : IDecoratedMulti -{ - public IDecoratedMulti Decorated => this; -} - -internal class DecoratorMultiA : IDecoratedMulti, IDecorator -{ - public DecoratorMultiA(IDecoratedMulti decorated) => - Decorated = decorated; - - public IDecoratedMulti Decorated { get; } -} - -internal class DecoratorMultiB : IDecoratedMulti, IDecorator -{ - public DecoratorMultiB(IDecoratedMulti decorated) => - Decorated = decorated; - - public IDecoratedMulti Decorated { get; } -} - -[CreateFunction(typeof(IDecoratedMulti), "CreateDep")] -internal partial class DecoratorMultiContainer -{ - -} - -public partial class DecoratorTests -{ - [Fact] - public void Multi() - { - using var container = new DecoratorMultiContainer(); - var decorated = container.CreateDep(); - var decoratedB = decorated; - var decoratedA = decorated.Decorated; - var decoratedBasis = decoratedA.Decorated; - Assert.NotEqual(decoratedBasis, decoratedA); - Assert.NotEqual(decoratedBasis, decoratedB); - Assert.NotEqual(decoratedA, decoratedB); - Assert.IsType(decoratedBasis); - Assert.IsType(decoratedA); - Assert.IsType(decoratedB); - } -} - -internal interface IDecoratedList -{ - IDecoratedList Decorated { get; } -} - -internal class DecoratedListBasisA : IDecoratedList -{ - public IDecoratedList Decorated => this; -} - -internal class DecoratedListBasisB : IDecoratedList -{ - public IDecoratedList Decorated => this; -} - -internal class DecoratorList : IDecoratedList, IDecorator -{ - public DecoratorList(IDecoratedList decorated) => - Decorated = decorated; - - public IDecoratedList Decorated { get; } -} - -[CreateFunction(typeof(IReadOnlyList), "CreateDep")] -internal partial class DecoratorListContainer -{ - -} - -public partial class DecoratorTests -{ - [Fact] - public void List() - { - using var container = new DecoratorListContainer(); - var decorated = container.CreateDep(); - var decoratedOfA = decorated[0]; - var decoratedOfB = decorated[1]; - var decoratedBasisA = decoratedOfA.Decorated; - var decoratedBasisB = decoratedOfB.Decorated; - Assert.NotEqual(decoratedOfA, decoratedBasisA); - Assert.NotEqual(decoratedOfB, decoratedBasisB); - Assert.NotEqual(decoratedOfA, decoratedOfB); - Assert.NotEqual(decoratedBasisA, decoratedBasisB); - Assert.IsType(decoratedOfA); - Assert.IsType(decoratedOfB); - Assert.IsType(decoratedBasisA); - Assert.IsType(decoratedBasisB); - } -} \ No newline at end of file From 05f10664a180c355943317557e5e655055ab8fdd Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Mon, 4 Apr 2022 23:07:50 +0200 Subject: [PATCH 059/162] Fixing special case combining transient-scoped instances in different transient scopes with different synchronicity --- .../ContainerResolutionBuilder.cs | 2 +- Main/ResolutionBuilding/ResolutionDtos.cs | 2 +- ...ransientScopeInterfaceResolutionBuilder.cs | 16 +++- Sample/Context.cs | 17 +++- ...InstanceFunction_DifferentSynchronicity.cs | 82 +++++++++++++++++++ ...ceFunctionAsTask_DifferentSynchronicity.cs | 82 +++++++++++++++++++ ...ctionAsValueTask_DifferentSynchronicity.cs | 82 +++++++++++++++++++ 7 files changed, 275 insertions(+), 8 deletions(-) create mode 100644 Test/Async/Awaited/TransientScopeInstanceFunction_DifferentSynchronicity.cs create mode 100644 Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask_DifferentSynchronicity.cs create mode 100644 Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask_DifferentSynchronicity.cs diff --git a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs index 8022b3e5..ce6517e0 100644 --- a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs @@ -76,7 +76,7 @@ public override MultiSynchronicityFunctionCallResolution CreateContainerInstance CreateContainerInstanceReferenceResolution(parameter, "this"); public override MultiSynchronicityFunctionCallResolution CreateTransientScopeInstanceReferenceResolution(ForConstructorParameter parameter) => - _transientScopeInterfaceResolutionBuilder.CreateTransientScopeInstanceReferenceResolution(parameter, "this"); + _transientScopeInterfaceResolutionBuilder.CreateTransientScopeInstanceReferenceResolution(parameter, _transientScopeAdapterReference); public override TransientScopeRootResolution CreateTransientScopeRootResolution(IScopeRootParameter parameter, INamedTypeSymbol rootType, DisposableCollectionResolution disposableCollectionResolution, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) => diff --git a/Main/ResolutionBuilding/ResolutionDtos.cs b/Main/ResolutionBuilding/ResolutionDtos.cs index 33c13cd5..49d0ed42 100644 --- a/Main/ResolutionBuilding/ResolutionDtos.cs +++ b/Main/ResolutionBuilding/ResolutionDtos.cs @@ -7,7 +7,7 @@ internal string KeySuffix() => this switch { DecorationInterfaceExtension decoration => $":::{decoration.ImplementationType.FullName()}", - CompositionInterfaceExtension composition => string.Join(":::", composition.ImplementationTypes.Select(i => i.FullName())), + CompositionInterfaceExtension composition => $":::{string.Join(":::", composition.ImplementationTypes.Select(i => i.FullName()))}", _ => throw new ArgumentException() }; diff --git a/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs b/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs index cc3ef544..f37fda73 100644 --- a/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs +++ b/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs @@ -20,6 +20,9 @@ internal class TransientScopeInterfaceResolutionBuilder : ITransientScopeInterfa private readonly IList _implementations = new List(); + private readonly IDictionary _rangedInstanceReferences = + new Dictionary(); + private readonly IDictionary _rangedInstanceReferenceResolutions = new Dictionary(); private readonly IDictionary _synchronicityDecisionMakers = @@ -86,11 +89,18 @@ private MultiSynchronicityFunctionCallResolution CreateRangedInstanceReferenceRe ForConstructorParameterWithDecoration withDecoration => withDecoration.Decoration, _ => null }; - var key = $"{implementationType.FullName()}{interfaceExtension?.KeySuffix() ?? ""}"; - if (!_rangedInstanceReferenceResolutions.TryGetValue(key, out var interfaceDeclaration)) + var referenceKey = $"{implementationType.FullName()}{interfaceExtension?.KeySuffix() ?? ""}"; + if (!_rangedInstanceReferences.TryGetValue(referenceKey, out var reference)) { var decorationSuffix = interfaceExtension?.RangedNameSuffix() ?? ""; - var reference = _rootReferenceGenerator.Generate($"Get{label}Instance", implementationType, decorationSuffix); + reference = + _rootReferenceGenerator.Generate($"Get{label}Instance", implementationType, decorationSuffix); + _rangedInstanceReferences[referenceKey] = reference; + } + + var key = $"{referenceKey}:::{string.Join(":::", currentParameters.Select(p => p.Type.FullName()))}"; + if (!_rangedInstanceReferenceResolutions.TryGetValue(key, out var interfaceDeclaration)) + { var queueItem = new RangedInstanceResolutionsQueueItem( parameter, label, diff --git a/Sample/Context.cs b/Sample/Context.cs index 15c06186..2ad076d5 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -1,8 +1,9 @@ -using System.Threading.Tasks; +using System; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration; namespace MrMeeseeks.DIE.Sample; -internal class Dependency : ITaskTypeInitializer, ITransientScopeInstance +internal class Dependency : ITaskTypeInitializer { public bool IsInitialized { get; private set; } @@ -13,7 +14,17 @@ async Task ITaskTypeInitializer.InitializeAsync() } } -[CreateFunction(typeof(Task), "Create")] +internal class Instance : ITransientScopeInstance +{ + public Dependency Dependency { get; } + + internal Instance(Dependency dependency) => Dependency = dependency; +} + + + +[CreateFunction(typeof(Func>), "CreateWithParameter")] +[CreateFunction(typeof(Func>), "CreateWithoutParameter")] internal partial class Container { } \ No newline at end of file diff --git a/Test/Async/Awaited/TransientScopeInstanceFunction_DifferentSynchronicity.cs b/Test/Async/Awaited/TransientScopeInstanceFunction_DifferentSynchronicity.cs new file mode 100644 index 00000000..a4932e90 --- /dev/null +++ b/Test/Async/Awaited/TransientScopeInstanceFunction_DifferentSynchronicity.cs @@ -0,0 +1,82 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Async.Awaited.TransientScopeInstanceFunction_DifferentSynchronicity; + +internal interface IInterface {} + +internal class DependencyA : IInterface, ITaskTypeInitializer +{ + public bool IsInitialized { get; private set; } + + async Task ITaskTypeInitializer.InitializeAsync() + { + await Task.Delay(500).ConfigureAwait(false); + IsInitialized = true; + } +} + +internal class DependencyB : IInterface +{ +} + +internal class Instance : ITransientScopeInstance +{ + public IInterface Inner { get; } + + public Instance(IInterface inner) + { + Inner = inner; + } +} + +internal class TransientScopeRoot0 : ITransientScopeRoot +{ + public Instance Dependency { get; } + + internal TransientScopeRoot0(Instance dependency) + { + Dependency = dependency; + } +} + +internal class TransientScopeRoot1 : ITransientScopeRoot +{ + internal TransientScopeRoot1(Instance dependency) + { + + } +} + +[FilterImplementationAggregation(typeof(DependencyB))] +[CreateFunction(typeof(TransientScopeRoot0), "Create0")] +[CreateFunction(typeof(TransientScopeRoot1), "Create1")] +internal partial class Container +{ + [CustomScopeForRootTypes(typeof(TransientScopeRoot0))] + private partial class DIE_TransientScope0 + { + + } + + [FilterImplementationAggregation(typeof(DependencyA))] + [ImplementationAggregation(typeof(DependencyB))] + [CustomScopeForRootTypes(typeof(TransientScopeRoot1))] + private partial class DIE_TransientScope1 + { + + } +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + using var container = new Container(); + var instance0 = container.Create0ValueAsync(); + var _ = container.Create1ValueAsync(); + Assert.True((((await instance0.ConfigureAwait(false)).Dependency).Inner as DependencyA)?.IsInitialized); + } +} \ No newline at end of file diff --git a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask_DifferentSynchronicity.cs b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask_DifferentSynchronicity.cs new file mode 100644 index 00000000..58d62cb5 --- /dev/null +++ b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask_DifferentSynchronicity.cs @@ -0,0 +1,82 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Async.Wrapped.TransientScopeInstanceFunctionAsTask_DifferentSynchronicity; + +internal interface IInterface {} + +internal class DependencyA : IInterface, ITaskTypeInitializer +{ + public bool IsInitialized { get; private set; } + + async Task ITaskTypeInitializer.InitializeAsync() + { + await Task.Delay(500).ConfigureAwait(false); + IsInitialized = true; + } +} + +internal class DependencyB : IInterface +{ +} + +internal class Instance : ITransientScopeInstance +{ + public IInterface Inner { get; } + + public Instance(IInterface inner) + { + Inner = inner; + } +} + +internal class TransientScopeRoot0 : ITransientScopeRoot +{ + public Task Dependency { get; } + + internal TransientScopeRoot0(Task dependency) + { + Dependency = dependency; + } +} + +internal class TransientScopeRoot1 : ITransientScopeRoot +{ + internal TransientScopeRoot1(Task dependency) + { + + } +} + +[FilterImplementationAggregation(typeof(DependencyB))] +[CreateFunction(typeof(TransientScopeRoot0), "Create0")] +[CreateFunction(typeof(TransientScopeRoot1), "Create1")] +internal partial class Container +{ + [CustomScopeForRootTypes(typeof(TransientScopeRoot0))] + private partial class DIE_TransientScope0 + { + + } + + [FilterImplementationAggregation(typeof(DependencyA))] + [ImplementationAggregation(typeof(DependencyB))] + [CustomScopeForRootTypes(typeof(TransientScopeRoot1))] + private partial class DIE_TransientScope1 + { + + } +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + using var container = new Container(); + var instance0 = container.Create0(); + var _ = container.Create1(); + Assert.True(((await instance0.Dependency.ConfigureAwait(false)).Inner as DependencyA)?.IsInitialized); + } +} \ No newline at end of file diff --git a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask_DifferentSynchronicity.cs b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask_DifferentSynchronicity.cs new file mode 100644 index 00000000..729dd3f4 --- /dev/null +++ b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask_DifferentSynchronicity.cs @@ -0,0 +1,82 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Async.Wrapped.TransientScopeInstanceFunctionAsValueTask_DifferentSynchronicity; + +internal interface IInterface {} + +internal class DependencyA : IInterface, ITaskTypeInitializer +{ + public bool IsInitialized { get; private set; } + + async Task ITaskTypeInitializer.InitializeAsync() + { + await Task.Delay(500).ConfigureAwait(false); + IsInitialized = true; + } +} + +internal class DependencyB : IInterface +{ +} + +internal class Instance : ITransientScopeInstance +{ + public IInterface Inner { get; } + + public Instance(IInterface inner) + { + Inner = inner; + } +} + +internal class TransientScopeRoot0 : ITransientScopeRoot +{ + public ValueTask Dependency { get; } + + internal TransientScopeRoot0(ValueTask dependency) + { + Dependency = dependency; + } +} + +internal class TransientScopeRoot1 : ITransientScopeRoot +{ + internal TransientScopeRoot1(ValueTask dependency) + { + + } +} + +[FilterImplementationAggregation(typeof(DependencyB))] +[CreateFunction(typeof(TransientScopeRoot0), "Create0")] +[CreateFunction(typeof(TransientScopeRoot1), "Create1")] +internal partial class Container +{ + [CustomScopeForRootTypes(typeof(TransientScopeRoot0))] + private partial class DIE_TransientScope0 + { + + } + + [FilterImplementationAggregation(typeof(DependencyA))] + [ImplementationAggregation(typeof(DependencyB))] + [CustomScopeForRootTypes(typeof(TransientScopeRoot1))] + private partial class DIE_TransientScope1 + { + + } +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + using var container = new Container(); + var instance0 = container.Create0(); + var _ = container.Create1(); + Assert.True(((await instance0.Dependency.ConfigureAwait(false)).Inner as DependencyA)?.IsInitialized); + } +} \ No newline at end of file From 4419533cb34c937dabba2869778543f7d2edf3de Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sat, 16 Apr 2022 10:38:24 +0200 Subject: [PATCH 060/162] Async support: Disposal --- Main/CodeBuilding/ContainerCodeBuilder.cs | 49 +++++- Main/CodeBuilding/RangeCodeBaseBuilder.cs | 166 +++++++++++++----- Main/CodeBuilding/ScopeCodeBuilder.cs | 17 +- .../CodeBuilding/TransientScopeCodeBuilder.cs | 29 ++- Main/Configuration/Attributes.cs | 24 +++ Main/Configuration/CheckTypeProperties.cs | 28 ++- .../Configuration/CurrentlyConsideredTypes.cs | 17 +- Main/Configuration/TypesFromAttributes.cs | 12 ++ .../ContainerResolutionBuilder.cs | 31 ++-- ...ontainerCreateFunctionResolutionBuilder.cs | 2 - .../Function/FunctionResolutionBuilder.cs | 42 ++--- .../LocalFunctionResolutionBuilder.cs | 2 - .../RangedFunctionGroupResolutionBuilder.cs | 1 - .../RangedFunctionResolutionBuilder.cs | 2 - ...copeRootCreateFunctionResolutionBuilder.cs | 2 - .../RangeResolutionBaseBuilder.cs | 35 ++-- .../ScopeResolutionBuilder.cs | 12 +- .../TransientScopeResolutionBuilder.cs | 17 +- Main/ResolutionTreeItem.cs | 47 +++-- Main/SourceGenerator.cs | 4 +- Main/WellKnownTypes.cs | 51 +++++- Sample/Context.cs | 88 ++++++++-- .../Async/Awaited/AsyncScopeRootCallAsTask.cs | 2 +- .../Awaited/AsyncScopeRootCallAsValueTask.cs | 2 +- .../Awaited/AsyncScopeRootCallAwaited.cs | 2 +- .../ContainerInstanceFunctionAsTask.cs | 2 +- .../ContainerInstanceFunctionAsValueTask.cs | 2 +- .../Awaited/ScopeInstanceFunctionAsTask.cs | 2 +- .../ScopeInstanceFunctionAsValueTask.cs | 2 +- Test/Async/Awaited/TaskTypeInitializerTask.cs | 2 +- .../Awaited/TaskTypeInitializerValueTask.cs | 2 +- .../TransientScopeInstanceFunctionAsTask.cs | 2 +- ...ansientScopeInstanceFunctionAsValueTask.cs | 2 +- ...InstanceFunction_DifferentSynchronicity.cs | 2 +- .../ContainerInstanceFunctionAsTask.cs | 2 +- .../ContainerInstanceFunctionAsValueTask.cs | 2 +- Test/Async/Wrapped/DecorationChaining.cs | 2 +- Test/Async/Wrapped/Func.cs | 2 +- Test/Async/Wrapped/Lazy.cs | 2 +- .../Wrapped/ScopeInstanceFunctionAsTask.cs | 2 +- .../ScopeInstanceFunctionAsValueTask.cs | 2 +- Test/Async/Wrapped/SyncToTask.cs | 2 +- Test/Async/Wrapped/SyncToValueTask.cs | 2 +- Test/Async/Wrapped/TaskCollection.cs | 2 +- Test/Async/Wrapped/TaskComposition.cs | 2 +- Test/Async/Wrapped/TaskToTask.cs | 2 +- Test/Async/Wrapped/TaskToValueTask.cs | 2 +- .../TransientScopeInstanceFunctionAsTask.cs | 2 +- ...ceFunctionAsTask_DifferentSynchronicity.cs | 2 +- ...ansientScopeInstanceFunctionAsValueTask.cs | 2 +- ...ctionAsValueTask_DifferentSynchronicity.cs | 2 +- Test/Async/Wrapped/ValueTaskCollection.cs | 2 +- Test/Async/Wrapped/ValueTaskComposition.cs | 2 +- Test/Async/Wrapped/ValueTaskToTask.cs | 2 +- Test/Async/Wrapped/ValueTaskToValueTask.cs | 2 +- Test/CompositeTests.cs | 20 +-- Test/ConstructorChoiceTests.cs | 2 +- Test/ConstructorTests.cs | 2 +- Test/Decorator/ContainerInstance.cs | 2 +- Test/Decorator/List.cs | 2 +- Test/Decorator/Multi.cs | 2 +- Test/Decorator/Normal.cs | 2 +- .../ScopeDecoratorForContainerDependency.cs | 2 +- ...opeDecoratorForTransientScopeDependency.cs | 2 +- Test/Decorator/SequenceEdgeCase.cs | 4 +- Test/Disposal/Async/Normal.cs | 36 ++++ Test/Disposal/Sync/Normal.cs | 34 ++++ Test/FactoryTests.cs | 6 +- Test/Func/Vanilla.cs | 2 +- Test/ImplementationAggregationTests.cs | 2 +- Test/InstanceTests.cs | 2 +- Test/Lazy/Vanilla.cs | 2 +- Test/PropertyTests.cs | 2 +- ...opeSpecificAttributesTestsWithDecorator.cs | 10 +- ...cAttributesTestsWithImplementationLists.cs | 6 +- ...cificAttributesTestsWithImplementations.cs | 6 +- Test/SyncTypeInitializationTest.cs | 2 +- Test/TransientScopeInstanceTests.cs | 1 + Test/ValueTupleTests.cs | 8 +- 79 files changed, 648 insertions(+), 255 deletions(-) create mode 100644 Test/Disposal/Async/Normal.cs create mode 100644 Test/Disposal/Sync/Normal.cs diff --git a/Main/CodeBuilding/ContainerCodeBuilder.cs b/Main/CodeBuilding/ContainerCodeBuilder.cs index cfd4c48f..55c89305 100644 --- a/Main/CodeBuilding/ContainerCodeBuilder.cs +++ b/Main/CodeBuilding/ContainerCodeBuilder.cs @@ -1,3 +1,4 @@ +using MrMeeseeks.DIE.Configuration; using MrMeeseeks.DIE.ResolutionBuilding.Function; namespace MrMeeseeks.DIE.CodeBuilding; @@ -14,13 +15,59 @@ internal class ContainerCodeBuilder : RangeCodeBaseBuilder, IContainerCodeBuilde private readonly IReadOnlyList _transientScopeCodeBuilders; private readonly IReadOnlyList _scopeCodeBuilders; + protected override StringBuilder GenerateDisposalFunction_TransientScopeDictionary(StringBuilder stringBuilder) + { + if (_containerResolution.DisposalType is DisposalType.None) + return stringBuilder; + + var dictionaryTypeName = _containerResolution.DisposalType is DisposalType.Async + ? WellKnownTypes.ConcurrentDictionaryOfAsyncDisposable.FullName() + : WellKnownTypes.ConcurrentDictionaryOfSyncDisposable.FullName(); + + stringBuilder.AppendLine( + $"private {dictionaryTypeName} {_containerResolution.TransientScopeDisposalReference} = new {dictionaryTypeName}();"); + + return stringBuilder; + } + + protected override StringBuilder GenerateDisposalFunction_TransientScopeDisposal(StringBuilder stringBuilder) + { + if (_containerResolution.DisposalType is DisposalType.None) + return stringBuilder; + + var elementName = _containerResolution.TransientScopeDisposalElement; + + var asyncSuffix = _containerResolution.DisposalType is DisposalType.Async ? "Async" : ""; + var awaitPrefix = _containerResolution.DisposalType is DisposalType.Async ? "await " : ""; + + stringBuilder + .AppendLine($"while ({_containerResolution.TransientScopeDisposalReference}.Count > 0)") + .AppendLine($"{{") + .AppendLine($"var {elementName} = global::System.Linq.Enumerable.FirstOrDefault({_containerResolution.TransientScopeDisposalReference}.Keys);") + .AppendLine($"if ({elementName} is not null && {_containerResolution.TransientScopeDisposalReference}.TryRemove({elementName}, out _))") + .AppendLine($"{{") + .AppendLine($"{awaitPrefix}{elementName}.Dispose{asyncSuffix}();") + .AppendLine($"}}") + .AppendLine($"}}") + .AppendLine($"{_containerResolution.TransientScopeDisposalReference}.Clear();"); + + return stringBuilder; + } + public override StringBuilder Build(StringBuilder stringBuilder) { + var disposableImplementation = _containerResolution.DisposalType switch + { + DisposalType.Sync => $" : {WellKnownTypes.Disposable.FullName()}", + DisposalType.Async => $" : {WellKnownTypes.AsyncDisposable.FullName()}", + _ => "" + }; + stringBuilder = stringBuilder .AppendLine($"#nullable enable") .AppendLine($"namespace {_containerInfo.Namespace}") .AppendLine($"{{") - .AppendLine($"partial class {_containerInfo.Name} : {WellKnownTypes.Disposable.FullName()}") + .AppendLine($"partial class {_containerInfo.Name}{disposableImplementation}") .AppendLine($"{{"); stringBuilder = GenerateResolutionRange( diff --git a/Main/CodeBuilding/RangeCodeBaseBuilder.cs b/Main/CodeBuilding/RangeCodeBaseBuilder.cs index c55810c5..842611db 100644 --- a/Main/CodeBuilding/RangeCodeBaseBuilder.cs +++ b/Main/CodeBuilding/RangeCodeBaseBuilder.cs @@ -1,3 +1,4 @@ +using MrMeeseeks.DIE.Configuration; using MrMeeseeks.DIE.ResolutionBuilding.Function; namespace MrMeeseeks.DIE.CodeBuilding; @@ -12,7 +13,6 @@ internal abstract class RangeCodeBaseBuilder : IRangeCodeBaseBuilder private readonly RangeResolution _rangeResolution; private readonly ContainerResolution _containerResolution; protected readonly WellKnownTypes WellKnownTypes; - private bool _isDisposalHandlingRequired; internal RangeCodeBaseBuilder( RangeResolution rangeResolution, @@ -32,35 +32,89 @@ protected StringBuilder GenerateResolutionRange( stringBuilder = rangeResolution.RootResolutions.Aggregate(stringBuilder, GenerateResolutionFunction); - return GenerateContainerDisposalFunction( + return GenerateDisposalFunction( stringBuilder, rangeResolution); } - private StringBuilder GenerateContainerDisposalFunction( + protected abstract StringBuilder GenerateDisposalFunction_TransientScopeDictionary(StringBuilder stringBuilder); + + protected abstract StringBuilder GenerateDisposalFunction_TransientScopeDisposal(StringBuilder stringBuilder); + + private StringBuilder GenerateDisposalFunction( StringBuilder stringBuilder, RangeResolution rangeResolution) { - var disposalHandling = rangeResolution.DisposalHandling; - stringBuilder = stringBuilder - .AppendLine($"private {disposalHandling.DisposableCollection.TypeFullName} {disposalHandling.DisposableCollection.Reference} = new {disposalHandling.DisposableCollection.TypeFullName}();") - .AppendLine($"private int {disposalHandling.DisposedFieldReference} = 0;") - .AppendLine($"private bool {disposalHandling.DisposedPropertyReference} => {disposalHandling.DisposedFieldReference} != 0;") - .AppendLine($"public void Dispose()") - .AppendLine($"{{") - .AppendLine($"var {disposalHandling.DisposedLocalReference} = global::System.Threading.Interlocked.Exchange(ref this.{disposalHandling.DisposedFieldReference}, 1);") - .AppendLine($"if ({disposalHandling.DisposedLocalReference} != 0) return;"); - - if (_isDisposalHandlingRequired) + + if (_containerResolution.DisposalType != DisposalType.None) { + var returnType = _containerResolution.DisposalType switch + { + DisposalType.Async => $"async {WellKnownTypes.ValueTask.FullName()}", + _ => "void" + }; + + var asyncSuffix = _containerResolution.DisposalType switch + { + DisposalType.Async => "Async", + _ => "" + }; + + var awaitPrefix = _containerResolution.DisposalType switch + { + DisposalType.Async => "await ", + _ => "" + }; + + stringBuilder = GenerateDisposalFunction_TransientScopeDictionary(stringBuilder); + + var disposalHandling = rangeResolution.DisposalHandling; + if (_containerResolution.DisposalType == DisposalType.Async) + { + stringBuilder = stringBuilder.AppendLine( + $"private {disposalHandling.AsyncDisposableCollection.TypeFullName} {disposalHandling.AsyncDisposableCollection.Reference} = new {disposalHandling.AsyncDisposableCollection.TypeFullName}();"); + } + + stringBuilder = stringBuilder + .AppendLine($"private {disposalHandling.SyncDisposableCollection.TypeFullName} {disposalHandling.SyncDisposableCollection.Reference} = new {disposalHandling.SyncDisposableCollection.TypeFullName}();") + .AppendLine($"private int {disposalHandling.DisposedFieldReference} = 0;") + .AppendLine($"private bool {disposalHandling.DisposedPropertyReference} => {disposalHandling.DisposedFieldReference} != 0;") + .AppendLine($"public {returnType} Dispose{asyncSuffix}()") + .AppendLine($"{{") + .AppendLine($"var {disposalHandling.DisposedLocalReference} = global::System.Threading.Interlocked.Exchange(ref this.{disposalHandling.DisposedFieldReference}, 1);") + .AppendLine($"if ({disposalHandling.DisposedLocalReference} != 0) return;"); + stringBuilder = rangeResolution.RangedInstanceFunctionGroups.Aggregate( stringBuilder, - (current, containerInstanceResolution) => current.AppendLine($"this.{containerInstanceResolution.LockReference}.Wait();")); + (current, containerInstanceResolution) => current.AppendLine($"{awaitPrefix}this.{containerInstanceResolution.LockReference}.Wait{asyncSuffix}();")); stringBuilder = stringBuilder .AppendLine($"try") - .AppendLine($"{{") - .AppendLine($"foreach(var {disposalHandling.DisposableLocalReference} in {disposalHandling.DisposableCollection.Reference})") + .AppendLine($"{{"); + + stringBuilder = GenerateDisposalFunction_TransientScopeDisposal(stringBuilder); + + if (_containerResolution.DisposalType == DisposalType.Async) + { + stringBuilder = stringBuilder + .AppendLine( + $"foreach(var {disposalHandling.DisposableLocalReference} in {disposalHandling.AsyncDisposableCollection.Reference})") + .AppendLine($"{{") + .AppendLine($"try") + .AppendLine($"{{") + .AppendLine($"await {disposalHandling.DisposableLocalReference}.DisposeAsync();") + .AppendLine($"}}") + .AppendLine($"catch({WellKnownTypes.Exception.FullName()})") + .AppendLine($"{{") + .AppendLine( + $"// catch and ignore exceptions of individual disposals so the other disposals are triggered") + .AppendLine($"}}") + .AppendLine($"}}") + .AppendLine($"{disposalHandling.AsyncDisposableCollection.Reference}.Clear();"); + } + + stringBuilder = stringBuilder + .AppendLine($"foreach(var {disposalHandling.DisposableLocalReference} in {disposalHandling.SyncDisposableCollection.Reference})") .AppendLine($"{{") .AppendLine($"try") .AppendLine($"{{") @@ -71,6 +125,7 @@ private StringBuilder GenerateContainerDisposalFunction( .AppendLine($"// catch and ignore exceptions of individual disposals so the other disposals are triggered") .AppendLine($"}}") .AppendLine($"}}") + .AppendLine($"{disposalHandling.SyncDisposableCollection.Reference}.Clear();") .AppendLine($"}}") .AppendLine($"finally") .AppendLine($"{{"); @@ -84,8 +139,7 @@ private StringBuilder GenerateContainerDisposalFunction( .AppendLine($"}}"); } - return stringBuilder - .AppendLine($"}}"); + return stringBuilder; } private StringBuilder GenerateResolutionFunction( @@ -97,8 +151,10 @@ private StringBuilder GenerateResolutionFunction( var parameter = string.Join(",", resolution.Parameter.Select(r => $"{r.TypeFullName} {r.Reference}")); stringBuilder = stringBuilder .AppendLine($"{rootResolutionFunction.AccessModifier} {(rootResolutionFunction.SynchronicityDecision is SynchronicityDecision.AsyncTask or SynchronicityDecision.AsyncValueTask ? "async " : "")}{resolution.TypeFullName} {resolution.Reference}({parameter})") - .AppendLine($"{{") - .AppendLine($"if (this.{rootResolutionFunction.DisposalHandling.DisposedPropertyReference}) throw new {WellKnownTypes.ObjectDisposedException}(\"\");"); + .AppendLine($"{{"); + if (_containerResolution.DisposalType != DisposalType.None) + stringBuilder = stringBuilder + .AppendLine($"if (this.{_rangeResolution.DisposalHandling.DisposedPropertyReference}) throw new {WellKnownTypes.ObjectDisposedException}(\"\");"); stringBuilder = GenerateResolutionFunctionContent(stringBuilder, resolution.Resolvable) .AppendLine($"return {resolution.Resolvable.Reference};"); @@ -113,8 +169,10 @@ private StringBuilder GenerateResolutionFunction( var parameter = string.Join(",", resolution.Parameter.Select(r => $"{r.TypeFullName} {r.Reference}")); stringBuilder = stringBuilder .AppendLine($"{(localFunctionResolution.SynchronicityDecision is SynchronicityDecision.AsyncTask or SynchronicityDecision.AsyncValueTask ? "async " : "")}{resolution.TypeFullName} {resolution.Reference}({parameter})") - .AppendLine($"{{") - .AppendLine($"if (this.{localFunctionResolution.DisposalHandling.DisposedPropertyReference}) throw new {WellKnownTypes.ObjectDisposedException}(\"\");"); + .AppendLine($"{{"); + if (_containerResolution.DisposalType != DisposalType.None) + stringBuilder = stringBuilder + .AppendLine($"if (this.{_rangeResolution.DisposalHandling.DisposedPropertyReference}) throw new {WellKnownTypes.ObjectDisposedException}(\"\");"); stringBuilder = GenerateResolutionFunctionContent(stringBuilder, resolution.Resolvable) .AppendLine($"return {resolution.Resolvable.Reference};"); @@ -204,17 +262,20 @@ private static StringBuilder GenerateFields( stringBuilder = stringBuilder .AppendLine($"{valueTaskFullName} {valueTaskReference};"); break; - case TransientScopeRootResolution(var transientScopeReference, var transientScopeTypeFullName, _, _, var functionCallResolution): + case TransientScopeRootResolution(var transientScopeReference, var transientScopeTypeFullName, _, var functionCallResolution): stringBuilder = stringBuilder.AppendLine($"{transientScopeTypeFullName} {transientScopeReference};"); stringBuilder = GenerateFields(stringBuilder, functionCallResolution); break; - case ScopeRootResolution(var scopeReference, var scopeTypeFullName, _, _, _, var functionCallResolution): + case ScopeRootResolution(var scopeReference, var scopeTypeFullName, _, _, var functionCallResolution): stringBuilder = stringBuilder.AppendLine($"{scopeTypeFullName} {scopeReference};"); stringBuilder = GenerateFields(stringBuilder, functionCallResolution); break; case TransientScopeAsDisposableResolution(var reference, var typeFullName): stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); break; + case TransientScopeAsAsyncDisposableResolution(var reference, var typeFullName): + stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); + break; case InterfaceResolution(var reference, var typeFullName, Resolvable resolutionBase): stringBuilder = GenerateFields(stringBuilder, resolutionBase); stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); @@ -373,19 +434,28 @@ private StringBuilder GenerateResolutions( stringBuilder = GenerateResolutions(stringBuilder, wrappedResolvable); stringBuilder = stringBuilder.AppendLine($"{valueTaskReference} = {WellKnownTypes.ValueTask.FullName()}.FromResult({wrappedResolvable.Reference});"); break; - case TransientScopeRootResolution(var transientScopeReference, var transientScopeTypeFullName, var containerInstanceScopeReference, var (_, _, _, _, _, _), var createFunctionCall): + case TransientScopeRootResolution(var transientScopeReference, var transientScopeTypeFullName, var containerInstanceScopeReference, var createFunctionCall): stringBuilder = stringBuilder - .AppendLine($"{transientScopeReference} = new {transientScopeTypeFullName}({containerInstanceScopeReference});") - .AppendLine($"{_rangeResolution.ContainerReference}.{_containerResolution.DisposalHandling.DisposableCollection.Reference}.Add(({WellKnownTypes.Disposable.FullName()}) {transientScopeReference});"); + .AppendLine($"{transientScopeReference} = new {transientScopeTypeFullName}({containerInstanceScopeReference});"); + if (_containerResolution.DisposalType is not DisposalType.None) + { + var disposalType = _containerResolution.DisposalType is DisposalType.Async + ? WellKnownTypes.AsyncDisposable.FullName() + : WellKnownTypes.Disposable.FullName(); + stringBuilder = stringBuilder + .AppendLine($"{_rangeResolution.ContainerReference}.{_containerResolution.TransientScopeDisposalReference}[{transientScopeReference}] = ({disposalType}) {transientScopeReference};"); + } + stringBuilder = GenerateResolutions(stringBuilder, createFunctionCall); - _isDisposalHandlingRequired = true; break; - case ScopeRootResolution(var scopeReference, var scopeTypeFullName, var containerInstanceScopeReference, var transientInstanceScopeReference, var (disposableCollectionReference, _, _, _, _, _), var createFunctionCall): + case ScopeRootResolution(var scopeReference, var scopeTypeFullName, var containerInstanceScopeReference, var transientInstanceScopeReference, var createFunctionCall): stringBuilder = stringBuilder - .AppendLine($"{scopeReference} = new {scopeTypeFullName}({containerInstanceScopeReference}, {transientInstanceScopeReference});") - .AppendLine($"{disposableCollectionReference}.Add(({WellKnownTypes.Disposable.FullName()}) {scopeReference});"); + .AppendLine($"{scopeReference} = new {scopeTypeFullName}({containerInstanceScopeReference}, {transientInstanceScopeReference});"); + if (_containerResolution.DisposalType is DisposalType.Async) + stringBuilder = stringBuilder.AppendLine($"{_rangeResolution.DisposalHandling.AsyncDisposableCollection.Reference}.Add(({WellKnownTypes.AsyncDisposable.FullName()}) {scopeReference});"); + if (_containerResolution.DisposalType is DisposalType.Sync) + stringBuilder = stringBuilder.AppendLine($"{_rangeResolution.DisposalHandling.SyncDisposableCollection.Reference}.Add(({WellKnownTypes.Disposable.FullName()}) {scopeReference});"); stringBuilder = GenerateResolutions(stringBuilder, createFunctionCall); - _isDisposalHandlingRequired = true; break; case InterfaceResolution(var reference, var typeFullName, Resolvable resolutionBase): stringBuilder = GenerateResolutions(stringBuilder, resolutionBase); @@ -393,9 +463,16 @@ private StringBuilder GenerateResolutions( $"{reference} = ({typeFullName}) {resolutionBase.Reference};"); break; case TransientScopeAsDisposableResolution(var reference, var typeFullName): + if (_containerResolution.DisposalType is not DisposalType.Sync) + throw new Exception(); + stringBuilder = stringBuilder.AppendLine($"{reference} = ({typeFullName}) this;"); + break; + case TransientScopeAsAsyncDisposableResolution(var reference, var typeFullName): + if (_containerResolution.DisposalType is not DisposalType.Async) + throw new Exception(); stringBuilder = stringBuilder.AppendLine($"{reference} = ({typeFullName}) this;"); break; - case ConstructorResolution(var reference, var typeFullName, var disposableCollectionResolution, var parameters, var initializedProperties, var initialization): + case ConstructorResolution(var reference, var typeFullName, var disposalType, var parameters, var initializedProperties, var initialization): stringBuilder = parameters.Aggregate(stringBuilder, (builder, tuple) => GenerateResolutions(builder, tuple.Dependency)); stringBuilder = initializedProperties.Aggregate(stringBuilder, @@ -407,11 +484,15 @@ private StringBuilder GenerateResolutions( : ""; stringBuilder = stringBuilder.AppendLine( $"{reference} = new {typeFullName}({constructorParameter}){objectInitializerParameter};"); - if (disposableCollectionResolution is {}) + if (disposalType is not DisposalType.None) { - stringBuilder = stringBuilder.AppendLine( - $"{disposableCollectionResolution.Reference}.Add(({WellKnownTypes.Disposable.FullName()}) {reference});"); - _isDisposalHandlingRequired = true; + var interfaceType = disposalType is DisposalType.Sync + ? WellKnownTypes.Disposable.FullName() + : WellKnownTypes.AsyncDisposable.FullName(); + var disposableCollectionReference = disposalType is DisposalType.Sync + ? _rangeResolution.DisposalHandling.SyncDisposableCollection.Reference + : _rangeResolution.DisposalHandling.AsyncDisposableCollection.Reference; + stringBuilder = stringBuilder.AppendLine($"{disposableCollectionReference}.Add(({interfaceType}) {reference});"); } if (initialization is {} init) @@ -481,9 +562,12 @@ private StringBuilder GenerateRangedInstanceFunction(StringBuilder stringBuilder $"if (!object.ReferenceEquals({rangedInstanceFunctionGroupResolution.FieldReference}, null)) return {rangedInstanceFunctionGroupResolution.FieldReference};") .AppendLine($"{(isAsync ? "await " : "")}this.{rangedInstanceFunctionGroupResolution.LockReference}.Wait{(isAsync ? "Async" : "")}();") .AppendLine($"try") - .AppendLine($"{{") - .AppendLine( - $"if (this.{overload.DisposalHandling.DisposedPropertyReference}) throw new {WellKnownTypes.ObjectDisposedException}(nameof({overload.DisposalHandling.RangeName}));") + .AppendLine($"{{"); + if (_containerResolution.DisposalType != DisposalType.None) + stringBuilder = stringBuilder + .AppendLine( + $"if (this.{_rangeResolution.DisposalHandling.DisposedPropertyReference}) throw new {WellKnownTypes.ObjectDisposedException}(nameof({_rangeResolution.DisposalHandling.RangeName}));"); + stringBuilder = stringBuilder .AppendLine( $"if (!object.ReferenceEquals({rangedInstanceFunctionGroupResolution.FieldReference}, null)) return {rangedInstanceFunctionGroupResolution.FieldReference};"); diff --git a/Main/CodeBuilding/ScopeCodeBuilder.cs b/Main/CodeBuilding/ScopeCodeBuilder.cs index 2193c752..7b47ec53 100644 --- a/Main/CodeBuilding/ScopeCodeBuilder.cs +++ b/Main/CodeBuilding/ScopeCodeBuilder.cs @@ -1,3 +1,5 @@ +using MrMeeseeks.DIE.Configuration; + namespace MrMeeseeks.DIE.CodeBuilding; internal interface IScopeCodeBuilder : IRangeCodeBaseBuilder @@ -10,15 +12,27 @@ internal class ScopeCodeBuilder : RangeCodeBaseBuilder, IScopeCodeBuilder private readonly IContainerInfo _containerInfo; private readonly ScopeResolution _scopeResolution; private readonly TransientScopeInterfaceResolution _transientScopeInterfaceResolution; + private readonly ContainerResolution _containerResolution; + + protected override StringBuilder GenerateDisposalFunction_TransientScopeDictionary(StringBuilder stringBuilder) => stringBuilder; + + protected override StringBuilder GenerateDisposalFunction_TransientScopeDisposal(StringBuilder stringBuilder) => stringBuilder; public override StringBuilder Build(StringBuilder stringBuilder) { if (!_scopeResolution.RootResolutions.Any() && !_scopeResolution.RangedInstanceFunctionGroups.Any()) return stringBuilder; + var disposableImplementation = _containerResolution.DisposalType switch + { + DisposalType.Sync => $" : {WellKnownTypes.Disposable.FullName()}", + DisposalType.Async => $" : {WellKnownTypes.AsyncDisposable.FullName()}", + _ => "" + }; + stringBuilder = stringBuilder .AppendLine( - $"private partial class {_scopeResolution.Name} : {WellKnownTypes.Disposable.FullName()}") + $"private partial class {_scopeResolution.Name}{disposableImplementation}") .AppendLine($"{{") .AppendLine($"private readonly {_containerInfo.FullName} {_scopeResolution.ContainerReference};") .AppendLine($"private readonly {_transientScopeInterfaceResolution.Name} {_scopeResolution.TransientScopeReference};") @@ -54,5 +68,6 @@ public ScopeCodeBuilder( _containerInfo = containerInfo; _scopeResolution = scopeResolution; _transientScopeInterfaceResolution = transientScopeInterfaceResolution; + _containerResolution = containerResolution; } } \ No newline at end of file diff --git a/Main/CodeBuilding/TransientScopeCodeBuilder.cs b/Main/CodeBuilding/TransientScopeCodeBuilder.cs index fbfe8e29..4d28bbef 100644 --- a/Main/CodeBuilding/TransientScopeCodeBuilder.cs +++ b/Main/CodeBuilding/TransientScopeCodeBuilder.cs @@ -1,3 +1,5 @@ +using MrMeeseeks.DIE.Configuration; + namespace MrMeeseeks.DIE.CodeBuilding; internal interface ITransientScopeCodeBuilder : IRangeCodeBaseBuilder @@ -11,14 +13,37 @@ internal class TransientScopeCodeBuilder : RangeCodeBaseBuilder, ITransientScope private readonly TransientScopeResolution _transientScopeResolution; private readonly ContainerResolution _containerResolution; + protected override StringBuilder GenerateDisposalFunction_TransientScopeDictionary(StringBuilder stringBuilder) => stringBuilder; + + protected override StringBuilder GenerateDisposalFunction_TransientScopeDisposal(StringBuilder stringBuilder) + { + if (_containerResolution.DisposalType is DisposalType.None) + return stringBuilder; + + var disposalType = _containerResolution.DisposalType is DisposalType.Async + ? WellKnownTypes.AsyncDisposable.FullName() + : WellKnownTypes.Disposable.FullName(); + + stringBuilder + .AppendLine($"{_transientScopeResolution.ContainerReference}.{_containerResolution.TransientScopeDisposalReference}.TryRemove(({disposalType}) this, out _);"); + + return stringBuilder; + } + public override StringBuilder Build(StringBuilder stringBuilder) { if (!_transientScopeResolution.RootResolutions.Any() && !_transientScopeResolution.RangedInstanceFunctionGroups.Any()) return stringBuilder; + var disposableImplementation = _containerResolution.DisposalType switch + { + DisposalType.Sync => $", {WellKnownTypes.Disposable.FullName()}", + DisposalType.Async => $", {WellKnownTypes.AsyncDisposable.FullName()}", + _ => "" + }; + stringBuilder = stringBuilder - .AppendLine( - $"private partial class {_transientScopeResolution.Name} : {_containerResolution.TransientScopeInterface.Name}, {WellKnownTypes.Disposable.FullName()}") + .AppendLine($"private partial class {_transientScopeResolution.Name} : {_containerResolution.TransientScopeInterface.Name}{disposableImplementation}") .AppendLine($"{{") .AppendLine($"private readonly {_containerInfo.FullName} {_transientScopeResolution.ContainerReference};") .AppendLine($"internal {_transientScopeResolution.Name}(") diff --git a/Main/Configuration/Attributes.cs b/Main/Configuration/Attributes.cs index ee754284..81737a1e 100644 --- a/Main/Configuration/Attributes.cs +++ b/Main/Configuration/Attributes.cs @@ -50,6 +50,30 @@ public class FilterTransientAggregationAttribute : Attribute public FilterTransientAggregationAttribute(params Type[] types) {} } +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] +public class SyncTransientAggregationAttribute : Attribute +{ + public SyncTransientAggregationAttribute(params Type[] types) {} +} + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class FilterSyncTransientAggregationAttribute : Attribute +{ + public FilterSyncTransientAggregationAttribute(params Type[] types) {} +} + +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] +public class AsyncTransientAggregationAttribute : Attribute +{ + public AsyncTransientAggregationAttribute(params Type[] types) {} +} + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class FilterAsyncTransientAggregationAttribute : Attribute +{ + public FilterAsyncTransientAggregationAttribute(params Type[] types) {} +} + [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class ContainerInstanceAggregationAttribute : Attribute { diff --git a/Main/Configuration/CheckTypeProperties.cs b/Main/Configuration/CheckTypeProperties.cs index 02207e41..54b93c3b 100644 --- a/Main/Configuration/CheckTypeProperties.cs +++ b/Main/Configuration/CheckTypeProperties.cs @@ -8,9 +8,16 @@ internal enum ScopeLevel Container } +internal enum DisposalType +{ + None, + Sync, + Async +} + internal interface ICheckTypeProperties { - bool ShouldBeManaged(INamedTypeSymbol implementationType); + DisposalType ShouldDisposalBeManaged(INamedTypeSymbol implementationType); ScopeLevel ShouldBeScopeRoot(INamedTypeSymbol implementationType); bool ShouldBeComposite(INamedTypeSymbol interfaceType); ScopeLevel GetScopeLevelFor(INamedTypeSymbol implementationType); @@ -27,14 +34,29 @@ internal interface ICheckTypeProperties internal class CheckTypeProperties : ICheckTypeProperties { private readonly ICurrentlyConsideredTypes _currentlyConsideredTypes; + private readonly WellKnownTypes _wellKnownTypes; internal CheckTypeProperties( - ICurrentlyConsideredTypes currentlyConsideredTypes) + ICurrentlyConsideredTypes currentlyConsideredTypes, + WellKnownTypes wellKnownTypes) { _currentlyConsideredTypes = currentlyConsideredTypes; + _wellKnownTypes = wellKnownTypes; + } + + public DisposalType ShouldDisposalBeManaged(INamedTypeSymbol implementationType) + { + if (implementationType.AllInterfaces.Contains(_wellKnownTypes.AsyncDisposable) + && !_currentlyConsideredTypes.AsyncTransientTypes.Contains(implementationType)) + return DisposalType.Async; + + if (implementationType.AllInterfaces.Contains(_wellKnownTypes.Disposable) + && !_currentlyConsideredTypes.SyncTransientTypes.Contains(implementationType)) + return DisposalType.Sync; + + return DisposalType.None; } - public bool ShouldBeManaged(INamedTypeSymbol implementationType) => !_currentlyConsideredTypes.TransientTypes.Contains(implementationType); public ScopeLevel ShouldBeScopeRoot(INamedTypeSymbol implementationType) { if (_currentlyConsideredTypes.TransientScopeRootTypes.Contains(implementationType)) return ScopeLevel.TransientScope; diff --git a/Main/Configuration/CurrentlyConsideredTypes.cs b/Main/Configuration/CurrentlyConsideredTypes.cs index 197c4ae6..547b301e 100644 --- a/Main/Configuration/CurrentlyConsideredTypes.cs +++ b/Main/Configuration/CurrentlyConsideredTypes.cs @@ -4,7 +4,8 @@ namespace MrMeeseeks.DIE.Configuration; internal interface ICurrentlyConsideredTypes { - IImmutableSet TransientTypes { get; } + IImmutableSet SyncTransientTypes { get; } + IImmutableSet AsyncTransientTypes { get; } IImmutableSet ContainerInstanceTypes { get; } IImmutableSet TransientScopeInstanceTypes { get; } IImmutableSet ScopeInstanceTypes { get; } @@ -54,7 +55,12 @@ public CurrentlyConsideredTypes( .Concat(spiedImplementations)); } - TransientTypes = GetSetOfTypesWithProperties(t => t.Transient, t => t.FilterTransient); + SyncTransientTypes = GetSetOfTypesWithProperties( + t => t.SyncTransient.Concat(t.Transient).ToList(), + t => t.FilterSyncTransient.Concat(t.FilterTransient).ToList()); + AsyncTransientTypes = GetSetOfTypesWithProperties( + t => t.AsyncTransient.Concat(t.Transient).ToList(), + t => t.FilterAsyncTransient.Concat(t.FilterTransient).ToList()); ContainerInstanceTypes = GetSetOfTypesWithProperties(t => t.ContainerInstance, t => t.FilterContainerInstance); TransientScopeInstanceTypes = GetSetOfTypesWithProperties(t => t.TransientScopeInstance, t => t.FilterTransientScopeInstance); ScopeInstanceTypes = GetSetOfTypesWithProperties(t => t.ScopeInstance, t => t.FilterScopeInstance); @@ -193,8 +199,8 @@ public CurrentlyConsideredTypes( ImplementationToInitializer = initializers; IImmutableSet GetSetOfTypesWithProperties( - Func> propertyGivingTypesGetter, - Func> filteredPropertyGivingTypesGetter) + Func> propertyGivingTypesGetter, + Func> filteredPropertyGivingTypesGetter) { var ret = ImmutableHashSet.Empty; foreach (var types in typesFromAttributes) @@ -232,7 +238,8 @@ IEnumerable AllDerivedTypes(INamedTypeSymbol type) } } - public IImmutableSet TransientTypes { get; } + public IImmutableSet SyncTransientTypes { get; } + public IImmutableSet AsyncTransientTypes { get; } public IImmutableSet ContainerInstanceTypes { get; } public IImmutableSet TransientScopeInstanceTypes { get; } public IImmutableSet ScopeInstanceTypes { get; } diff --git a/Main/Configuration/TypesFromAttributes.cs b/Main/Configuration/TypesFromAttributes.cs index df777fdb..3449dfff 100644 --- a/Main/Configuration/TypesFromAttributes.cs +++ b/Main/Configuration/TypesFromAttributes.cs @@ -5,6 +5,8 @@ internal interface ITypesFromAttributes IReadOnlyList Spy { get; } IReadOnlyList Implementation { get; } IReadOnlyList Transient { get; } + IReadOnlyList SyncTransient { get; } + IReadOnlyList AsyncTransient { get; } IReadOnlyList ContainerInstance { get; } IReadOnlyList TransientScopeInstance { get; } IReadOnlyList ScopeInstance { get; } @@ -18,6 +20,8 @@ internal interface ITypesFromAttributes IReadOnlyList FilterSpy { get; } IReadOnlyList FilterImplementation { get; } IReadOnlyList FilterTransient { get; } + IReadOnlyList FilterSyncTransient { get; } + IReadOnlyList FilterAsyncTransient { get; } IReadOnlyList FilterContainerInstance { get; } IReadOnlyList FilterTransientScopeInstance { get; } IReadOnlyList FilterScopeInstance { get; } @@ -66,6 +70,8 @@ internal ScopeTypesFromAttributes( Spy = GetTypesFromAttribute(wellKnownTypes.SpyAggregationAttribute).ToList(); Implementation = GetTypesFromAttribute(wellKnownTypes.ImplementationAggregationAttribute).ToList(); Transient = GetTypesFromAttribute(wellKnownTypes.TransientAggregationAttribute).ToList(); + SyncTransient = GetTypesFromAttribute(wellKnownTypes.SyncTransientAggregationAttribute).ToList(); + AsyncTransient = GetTypesFromAttribute(wellKnownTypes.AsyncTransientAggregationAttribute).ToList(); ContainerInstance = new List(); TransientScopeInstance = new List(); ScopeInstance = GetTypesFromAttribute(wellKnownTypes.ScopeInstanceAggregationAttribute).ToList(); @@ -77,6 +83,8 @@ internal ScopeTypesFromAttributes( FilterSpy = GetTypesFromAttribute(wellKnownTypes.FilterSpyAggregationAttribute).ToList(); FilterImplementation = GetTypesFromAttribute(wellKnownTypes.FilterImplementationAggregationAttribute).ToList(); FilterTransient = GetTypesFromAttribute(wellKnownTypes.FilterTransientAggregationAttribute).ToList(); + FilterSyncTransient = GetTypesFromAttribute(wellKnownTypes.FilterSyncTransientAggregationAttribute).ToList(); + FilterAsyncTransient = GetTypesFromAttribute(wellKnownTypes.FilterAsyncTransientAggregationAttribute).ToList(); FilterContainerInstance = new List(); FilterTransientScopeInstance = new List(); FilterScopeInstance = GetTypesFromAttribute(wellKnownTypes.FilterScopeInstanceAggregationAttribute).ToList(); @@ -219,6 +227,8 @@ bool CheckValidType(TypedConstant typedConstant, out INamedTypeSymbol type) public IReadOnlyList Spy { get; } public IReadOnlyList Implementation { get; } public IReadOnlyList Transient { get; } + public IReadOnlyList SyncTransient { get; } + public IReadOnlyList AsyncTransient { get; } public IReadOnlyList ContainerInstance { get; protected init; } public IReadOnlyList TransientScopeInstance { get; protected init; } public IReadOnlyList ScopeInstance { get; } @@ -232,6 +242,8 @@ bool CheckValidType(TypedConstant typedConstant, out INamedTypeSymbol type) public IReadOnlyList FilterSpy { get; } public IReadOnlyList FilterImplementation { get; } public IReadOnlyList FilterTransient { get; } + public IReadOnlyList FilterSyncTransient { get; } + public IReadOnlyList FilterAsyncTransient { get; } public IReadOnlyList FilterContainerInstance { get; protected init; } public IReadOnlyList FilterTransientScopeInstance { get; protected init; } public IReadOnlyList FilterScopeInstance { get; } diff --git a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs index ce6517e0..42b711b1 100644 --- a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs @@ -24,6 +24,8 @@ internal class ContainerResolutionBuilder : RangeResolutionBaseBuilder, IContain private readonly string _transientScopeAdapterReference; private readonly IScopeManager _scopeManager; + private DisposalType _disposalType = DisposalType.None; + internal ContainerResolutionBuilder( // parameters IContainerInfo containerInfo, @@ -78,21 +80,21 @@ public override MultiSynchronicityFunctionCallResolution CreateContainerInstance public override MultiSynchronicityFunctionCallResolution CreateTransientScopeInstanceReferenceResolution(ForConstructorParameter parameter) => _transientScopeInterfaceResolutionBuilder.CreateTransientScopeInstanceReferenceResolution(parameter, _transientScopeAdapterReference); - public override TransientScopeRootResolution CreateTransientScopeRootResolution(IScopeRootParameter parameter, INamedTypeSymbol rootType, - DisposableCollectionResolution disposableCollectionResolution, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) => + public override TransientScopeRootResolution CreateTransientScopeRootResolution( + IScopeRootParameter parameter, + INamedTypeSymbol rootType, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) => _scopeManager .GetTransientScopeBuilder(rootType) .AddCreateResolveFunction( parameter, rootType, "this", - disposableCollectionResolution, currentParameters); public override ScopeRootResolution CreateScopeRootResolution( IScopeRootParameter parameter, INamedTypeSymbol rootType, - DisposableCollectionResolution disposableCollectionResolution, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) => _scopeManager .GetScopeBuilder(rootType) @@ -101,9 +103,13 @@ public override ScopeRootResolution CreateScopeRootResolution( rootType, "this", _transientScopeAdapterReference, - disposableCollectionResolution, currentParameters); + public override void RegisterDisposalType(DisposalType disposalType) + { + if (disposalType > _disposalType) _disposalType = disposalType; + } + public bool HasWorkToDo => _rootResolutions.Any(r => r.CreateFunction.HasWorkToDo) || RangedInstanceReferenceResolutions.Values.Any(r => r.HasWorkToDo) @@ -135,7 +141,6 @@ public ContainerResolution Build() "private", privateFunctionResolution.Resolvable, privateFunctionResolution.Parameter, - DisposalHandling, privateFunctionResolution.LocalFunctions, privateFunctionResolution.SynchronicityDecision); @@ -158,7 +163,6 @@ public ContainerResolution Build() "public", call, privateRootResolutionFunction.Parameter, - DisposalHandling, Array.Empty(), SynchronicityDecision.Sync); @@ -184,7 +188,6 @@ public ContainerResolution Build() wrappedTaskReference, boundTaskTypeFullName), privateRootResolutionFunction.Parameter, - DisposalHandling, Array.Empty(), SynchronicityDecision.Sync); @@ -210,7 +213,6 @@ public ContainerResolution Build() wrappedValueTaskReference, boundValueTaskTypeFullName), privateRootResolutionFunction.Parameter, - DisposalHandling, Array.Empty(), SynchronicityDecision.Sync); @@ -232,7 +234,6 @@ public ContainerResolution Build() "public", call, privateRootResolutionFunction.Parameter, - DisposalHandling, Array.Empty(), SynchronicityDecision.Sync); @@ -258,7 +259,6 @@ public ContainerResolution Build() wrappedValueTaskReference, boundValueTaskTypeFullName), privateRootResolutionFunction.Parameter, - DisposalHandling, Array.Empty(), SynchronicityDecision.Sync); @@ -288,7 +288,6 @@ public ContainerResolution Build() wrappedTaskReference, boundTaskTypeFullName), privateRootResolutionFunction.Parameter, - DisposalHandling, Array.Empty(), SynchronicityDecision.Sync); @@ -306,7 +305,6 @@ public ContainerResolution Build() "public", valueCall, privateRootResolutionFunction.Parameter, - DisposalHandling, Array.Empty(), SynchronicityDecision.Sync); @@ -318,12 +316,15 @@ public ContainerResolution Build() return new( rootFunctions, - DisposalHandling, + BuildDisposalHandling(), RangedInstanceReferenceResolutions.Values.Select(b => b.Build()).ToList(), _transientScopeInterfaceResolutionBuilder.Build(), _transientScopeAdapterReference, transientScopeResolutions, - scopeResolutions); + scopeResolutions, + _disposalType, + RootReferenceGenerator.Generate("transientScopeDisposal"), + RootReferenceGenerator.Generate("transientScopeToDispose")); } public void EnqueueRangedInstanceResolution( diff --git a/Main/ResolutionBuilding/Function/ContainerCreateFunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/ContainerCreateFunctionResolutionBuilder.cs index 142cf1ba..9eefef99 100644 --- a/Main/ResolutionBuilding/Function/ContainerCreateFunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/ContainerCreateFunctionResolutionBuilder.cs @@ -42,7 +42,6 @@ public override FunctionResolution Build() TypeFullName, Resolvable.Value, Array.Empty(), - _rangeResolutionBaseBuilder.DisposalHandling, LocalFunctions .Select(lf => lf.Build()) .Select(f => new LocalFunctionResolution( @@ -50,7 +49,6 @@ public override FunctionResolution Build() f.TypeFullName, f.Resolvable, f.Parameter, - f.DisposalHandling, f.LocalFunctions, f.SynchronicityDecision)) .ToList(), diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs index 2bb010a4..71e9fff5 100644 --- a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs @@ -60,8 +60,7 @@ internal abstract class FunctionResolutionBuilder : IFunctionResolutionBuilder private readonly ICheckTypeProperties _checkTypeProperties; protected readonly IReferenceGenerator RootReferenceGenerator; - - private readonly DisposableCollectionResolution _disposableCollectionResolution; + private readonly IUserProvidedScopeElements _userProvidedScopeElements; protected readonly IList LocalFunctions = new List(); @@ -99,7 +98,6 @@ internal FunctionResolutionBuilder( _userProvidedScopeElements = rangeResolutionBaseBuilder.UserProvidedScopeElements; RootReferenceGenerator = referenceGeneratorFactory.Create(); - _disposableCollectionResolution = _rangeResolutionBaseBuilder.DisposableCollectionResolution; Parameters = currentParameters .Select(p => new ParameterResolution(RootReferenceGenerator.Generate(p.Type), TypeFullName)) .ToList(); @@ -154,7 +152,7 @@ internal FunctionResolutionBuilder( var constructorResolution = new ConstructorResolution( RootReferenceGenerator.Generate(valueTupleType), valueTupleType.FullName(), - ImplementsIDisposable(valueTupleType, _wellKnownTypes, _disposableCollectionResolution, _checkTypeProperties), + DisposalType.None, valueTupleType .TypeArguments .Select((t, i) => ($"item{(i + 1)}", SwitchType(new SwitchTypeParameter(t, currentFuncParameters)).Item1)) @@ -465,12 +463,10 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup ScopeLevel.TransientScope => (_rangeResolutionBaseBuilder.CreateTransientScopeRootResolution( nextParameter, interfaceType, - _disposableCollectionResolution, currentParameters), null), ScopeLevel.Scope => (_rangeResolutionBaseBuilder.CreateScopeRootResolution( nextParameter, interfaceType, - _disposableCollectionResolution, currentParameters), null), _ => SwitchInterfaceAfterScopeRoot(nextParameter) }; @@ -546,12 +542,10 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup ScopeLevel.TransientScope => (_rangeResolutionBaseBuilder.CreateTransientScopeRootResolution( nextParameter, interfaceType, - _disposableCollectionResolution, currentParameters), null), ScopeLevel.Scope => (_rangeResolutionBaseBuilder.CreateScopeRootResolution( nextParameter, interfaceType, - _disposableCollectionResolution, currentParameters), null), _ => CreateInterface(nextParameter) }; @@ -644,12 +638,10 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup ScopeLevel.TransientScope => (_rangeResolutionBaseBuilder.CreateTransientScopeRootResolution( nextParameter, implementationType, - _disposableCollectionResolution, currentParameters), null), ScopeLevel.Scope => (_rangeResolutionBaseBuilder.CreateScopeRootResolution( nextParameter, implementationType, - _disposableCollectionResolution, currentParameters), null), _ => SwitchImplementation(nextParameter) }; @@ -785,15 +777,10 @@ false when initializationMethod.ReturnType.Equals(_wellKnownTypes.ValueTask, Sym } } - var resolution = new ConstructorResolution( RootReferenceGenerator.Generate(implementationType), implementationType.FullName(), - ImplementsIDisposable( - implementationType, - _wellKnownTypes, - _disposableCollectionResolution, - _checkTypeProperties), + GetDisposalTypeFor(implementationType), new ReadOnlyCollection<(string Name, Resolvable Dependency)>(constructor .Parameters .Select(p => ProcessChildType(p.Type, p.Name, implementationType, currentParameters)) @@ -879,6 +866,13 @@ false when initializationMethod.ReturnType.Equals(_wellKnownTypes.ValueTask, Sym return (parameterName, new TransientScopeAsDisposableResolution( RootReferenceGenerator.Generate(_wellKnownTypes.Disposable), _wellKnownTypes.Disposable.FullName())); + + if (isTransientScopeRoot + && typeSymbol.Equals(_wellKnownTypes.AsyncDisposable, SymbolEqualityComparer.Default)) + return (parameterName, new TransientScopeAsAsyncDisposableResolution( + RootReferenceGenerator.Generate(_wellKnownTypes.AsyncDisposable), + _wellKnownTypes.AsyncDisposable.FullName())); + if (typeSymbol is not INamedTypeSymbol parameterType) return ("", new ErrorTreeItem( @@ -892,6 +886,13 @@ false when initializationMethod.ReturnType.Equals(_wellKnownTypes.ValueTask, Sym } } + private DisposalType GetDisposalTypeFor(INamedTypeSymbol type) + { + var disposalType = _checkTypeProperties.ShouldDisposalBeManaged(type); + _rangeResolutionBaseBuilder.RegisterDisposalType(disposalType); + return disposalType; + } + protected void AdjustForSynchronicity() => ActualReturnType = SynchronicityDecision.Value switch { @@ -900,15 +901,6 @@ protected void AdjustForSynchronicity() => _ => OriginalReturnType }; - private static DisposableCollectionResolution? ImplementsIDisposable( - INamedTypeSymbol type, - WellKnownTypes wellKnownTypes, - DisposableCollectionResolution disposableCollectionResolution, - ICheckTypeProperties checkDisposalManagement) => - type.AllInterfaces.Contains(wellKnownTypes.Disposable) && checkDisposalManagement.ShouldBeManaged(type) - ? disposableCollectionResolution - : null; - public MultiSynchronicityFunctionCallResolution BuildFunctionCall( IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters, string? ownerReference) { diff --git a/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs index 0c0700ea..71655f8a 100644 --- a/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs @@ -43,7 +43,6 @@ public override FunctionResolution Build() TypeFullName, Resolvable.Value, _parameters.Select(t => t.Resolution).ToList(), - _rangeResolutionBaseBuilder.DisposalHandling, LocalFunctions .Select(lf => lf.Build()) .Select(f => new LocalFunctionResolution( @@ -51,7 +50,6 @@ public override FunctionResolution Build() f.TypeFullName, f.Resolvable, f.Parameter, - f.DisposalHandling, f.LocalFunctions, f.SynchronicityDecision)) .ToList(), diff --git a/Main/ResolutionBuilding/Function/RangedFunctionGroupResolutionBuilder.cs b/Main/ResolutionBuilding/Function/RangedFunctionGroupResolutionBuilder.cs index 70cb38b1..4be19a3f 100644 --- a/Main/ResolutionBuilding/Function/RangedFunctionGroupResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/RangedFunctionGroupResolutionBuilder.cs @@ -83,7 +83,6 @@ public RangedInstanceFunctionGroupResolution Build() => functionResolution.TypeFullName, functionResolution.Resolvable, functionResolution.Parameter, - functionResolution.DisposalHandling, functionResolution.LocalFunctions, functionResolution.SynchronicityDecision)) .ToList(), diff --git a/Main/ResolutionBuilding/Function/RangedFunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/RangedFunctionResolutionBuilder.cs index a64e67e7..978e1945 100644 --- a/Main/ResolutionBuilding/Function/RangedFunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/RangedFunctionResolutionBuilder.cs @@ -42,7 +42,6 @@ public override FunctionResolution Build() TypeFullName, Resolvable.Value, _forConstructorParameter.CurrentFuncParameters.Select(t => t.Resolution).ToList(), - _rangeResolutionBaseBuilder.DisposalHandling, LocalFunctions .Select(lf => lf.Build()) .Select(f => new LocalFunctionResolution( @@ -50,7 +49,6 @@ public override FunctionResolution Build() f.TypeFullName, f.Resolvable, f.Parameter, - f.DisposalHandling, f.LocalFunctions, f.SynchronicityDecision)) .ToList(), diff --git a/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs index 5991cb4b..522219e5 100644 --- a/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs @@ -47,7 +47,6 @@ public override FunctionResolution Build() TypeFullName, Resolvable.Value, Parameters, - _rangeResolutionBaseBuilder.DisposalHandling, LocalFunctions .Select(lf => lf.Build()) .Select(f => new LocalFunctionResolution( @@ -55,7 +54,6 @@ public override FunctionResolution Build() f.TypeFullName, f.Resolvable, f.Parameter, - f.DisposalHandling, f.LocalFunctions, f.SynchronicityDecision)) .ToList(), diff --git a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs index d51e217c..9ee40ef0 100644 --- a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs +++ b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs @@ -7,8 +7,6 @@ internal interface IRangeResolutionBaseBuilder { ICheckTypeProperties CheckTypeProperties { get; } IUserProvidedScopeElements UserProvidedScopeElements { get; } - DisposableCollectionResolution DisposableCollectionResolution { get; } - DisposalHandling DisposalHandling { get; } MultiSynchronicityFunctionCallResolution CreateContainerInstanceReferenceResolution( ForConstructorParameter parameter); @@ -22,22 +20,20 @@ MultiSynchronicityFunctionCallResolution CreateScopeInstanceReferenceResolution( TransientScopeRootResolution CreateTransientScopeRootResolution( IScopeRootParameter parameter, INamedTypeSymbol rootType, - DisposableCollectionResolution disposableCollectionResolution, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters); ScopeRootResolution CreateScopeRootResolution( IScopeRootParameter parameter, INamedTypeSymbol rootType, - DisposableCollectionResolution disposableCollectionResolution, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters); + + void RegisterDisposalType(DisposalType disposalType); } internal abstract class RangeResolutionBaseBuilder : IRangeResolutionBaseBuilder { public ICheckTypeProperties CheckTypeProperties { get; } public IUserProvidedScopeElements UserProvidedScopeElements { get; } - public DisposableCollectionResolution DisposableCollectionResolution { get; } - public DisposalHandling DisposalHandling { get; } protected readonly WellKnownTypes WellKnownTypes; private readonly Func _rangedFunctionGroupResolutionBuilderFactory; @@ -67,18 +63,8 @@ protected RangeResolutionBaseBuilder( _synchronicityDecisionMakerFactory = synchronicityDecisionMakerFactory; RootReferenceGenerator = referenceGeneratorFactory.Create(); - DisposableCollectionResolution = new DisposableCollectionResolution( - RootReferenceGenerator.Generate(WellKnownTypes.ConcurrentBagOfDisposable), - WellKnownTypes.ConcurrentBagOfDisposable.FullName()); Name = name; - DisposalHandling = new DisposalHandling( - DisposableCollectionResolution, - Name, - RootReferenceGenerator.Generate("_disposed"), - RootReferenceGenerator.Generate("disposed"), - RootReferenceGenerator.Generate("Disposed"), - RootReferenceGenerator.Generate("disposable")); } public abstract MultiSynchronicityFunctionCallResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter); @@ -97,15 +83,15 @@ public MultiSynchronicityFunctionCallResolution CreateScopeInstanceReferenceReso public abstract TransientScopeRootResolution CreateTransientScopeRootResolution( IScopeRootParameter parameter, INamedTypeSymbol rootType, - DisposableCollectionResolution disposableCollectionResolution, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters); public abstract ScopeRootResolution CreateScopeRootResolution( IScopeRootParameter parameter, INamedTypeSymbol rootType, - DisposableCollectionResolution disposableCollectionResolution, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters); + public abstract void RegisterDisposalType(DisposalType disposalType); + protected MultiSynchronicityFunctionCallResolution CreateRangedInstanceReferenceResolution( ForConstructorParameter parameter, string label, @@ -143,4 +129,17 @@ protected void DoRangedInstancesWork() } } } + + protected DisposalHandling BuildDisposalHandling() => + new(new SyncDisposableCollectionResolution( + RootReferenceGenerator.Generate(WellKnownTypes.ConcurrentBagOfSyncDisposable), + WellKnownTypes.ConcurrentBagOfSyncDisposable.FullName()), + new AsyncDisposableCollectionResolution( + RootReferenceGenerator.Generate(WellKnownTypes.ConcurrentBagOfAsyncDisposable), + WellKnownTypes.ConcurrentBagOfAsyncDisposable.FullName()), + Name, + RootReferenceGenerator.Generate("_disposed"), + RootReferenceGenerator.Generate("disposed"), + RootReferenceGenerator.Generate("Disposed"), + RootReferenceGenerator.Generate("disposable")); } \ No newline at end of file diff --git a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs index e4b3c651..59f6f2ab 100644 --- a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs @@ -10,7 +10,6 @@ ScopeRootResolution AddCreateResolveFunction( INamedTypeSymbol rootType, string containerInstanceScopeReference, string transientInstanceScopeReference, - DisposableCollectionResolution disposableCollectionResolution, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters); } @@ -70,7 +69,6 @@ public override MultiSynchronicityFunctionCallResolution CreateTransientScopeIns public override TransientScopeRootResolution CreateTransientScopeRootResolution( IScopeRootParameter parameter, INamedTypeSymbol rootType, - DisposableCollectionResolution disposableCollectionResolution, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) => _scopeManager .GetTransientScopeBuilder(rootType) @@ -78,13 +76,11 @@ public override TransientScopeRootResolution CreateTransientScopeRootResolution( parameter, rootType, _containerReference, - disposableCollectionResolution, currentParameters); public override ScopeRootResolution CreateScopeRootResolution( IScopeRootParameter parameter, INamedTypeSymbol rootType, - DisposableCollectionResolution disposableCollectionResolution, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) => _scopeManager .GetScopeBuilder(rootType) @@ -93,9 +89,10 @@ public override ScopeRootResolution CreateScopeRootResolution( rootType, _containerReference, _transientScopeReference, - disposableCollectionResolution, currentParameters); + public override void RegisterDisposalType(DisposalType disposalType) => _containerResolutionBuilder.RegisterDisposalType(disposalType); + public bool HasWorkToDo => _scopeRootFunctionResolutions.Values.Any(f => f.HasWorkToDo) || RangedInstanceReferenceResolutions.Values.Any(r => r.HasWorkToDo); @@ -105,7 +102,6 @@ public ScopeRootResolution AddCreateResolveFunction( INamedTypeSymbol rootType, string containerInstanceScopeReference, string transientInstanceScopeReference, - DisposableCollectionResolution disposableCollectionResolution, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) { var key = $"{rootType.FullName()}{parameter.KeySuffix()}"; @@ -124,7 +120,6 @@ public ScopeRootResolution AddCreateResolveFunction( Name, containerInstanceScopeReference, transientInstanceScopeReference, - disposableCollectionResolution, function.BuildFunctionCall(currentParameters, scopeRootReference)); } @@ -151,11 +146,10 @@ public ScopeResolution Build() => "internal", f.Resolvable, f.Parameter, - f.DisposalHandling, f.LocalFunctions, f.SynchronicityDecision)) .ToList(), - DisposalHandling, + BuildDisposalHandling(), RangedInstanceReferenceResolutions.Values.Select(b => b.Build()).ToList(), _containerReference, _containerParameterReference, diff --git a/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs b/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs index e62972ca..96b39929 100644 --- a/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs @@ -9,7 +9,6 @@ TransientScopeRootResolution AddCreateResolveFunction( IScopeRootParameter parameter, INamedTypeSymbol rootType, string containerInstanceScopeReference, - DisposableCollectionResolution disposableCollectionResolution, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters); } @@ -62,21 +61,21 @@ public override MultiSynchronicityFunctionCallResolution CreateContainerInstance public override MultiSynchronicityFunctionCallResolution CreateTransientScopeInstanceReferenceResolution(ForConstructorParameter parameter) => _transientScopeInterfaceResolutionBuilder.CreateTransientScopeInstanceReferenceResolution(parameter, "this"); - public override TransientScopeRootResolution CreateTransientScopeRootResolution(IScopeRootParameter parameter, INamedTypeSymbol rootType, - DisposableCollectionResolution disposableCollectionResolution, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) => + public override TransientScopeRootResolution CreateTransientScopeRootResolution( + IScopeRootParameter parameter, + INamedTypeSymbol rootType, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) => _scopeManager .GetTransientScopeBuilder(rootType) .AddCreateResolveFunction( parameter, rootType, _containerReference, - disposableCollectionResolution, currentParameters); public override ScopeRootResolution CreateScopeRootResolution( IScopeRootParameter parameter, INamedTypeSymbol rootType, - DisposableCollectionResolution disposableCollectionResolution, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) => _scopeManager .GetScopeBuilder(rootType) @@ -85,9 +84,10 @@ public override ScopeRootResolution CreateScopeRootResolution( rootType, _containerReference, "this", - disposableCollectionResolution, currentParameters); + public override void RegisterDisposalType(DisposalType disposalType) => _containerResolutionBuilder.RegisterDisposalType(disposalType); + public bool HasWorkToDo => _transientScopeRootFunctionResolutions.Values.Any(f => f.HasWorkToDo) || RangedInstanceReferenceResolutions.Values.Any(r => r.HasWorkToDo); @@ -96,7 +96,6 @@ public TransientScopeRootResolution AddCreateResolveFunction( IScopeRootParameter parameter, INamedTypeSymbol rootType, string containerInstanceScopeReference, - DisposableCollectionResolution disposableCollectionResolution, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) { var key = $"{rootType.FullName()}{parameter.KeySuffix()}"; @@ -114,7 +113,6 @@ public TransientScopeRootResolution AddCreateResolveFunction( transientScopeRootReference, Name, containerInstanceScopeReference, - disposableCollectionResolution, function.BuildFunctionCall(currentParameters, transientScopeRootReference)); } @@ -141,11 +139,10 @@ public TransientScopeResolution Build() => "internal", f.Resolvable, f.Parameter, - f.DisposalHandling, f.LocalFunctions, f.SynchronicityDecision)) .ToList(), - DisposalHandling, + BuildDisposalHandling(), RangedInstanceReferenceResolutions.Values.Select(b => b.Build()).ToList(), _containerReference, _containerParameterReference, diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index 79377abb..c53d887a 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.ResolutionBuilding; +using MrMeeseeks.DIE.Configuration; using MrMeeseeks.DIE.ResolutionBuilding.Function; namespace MrMeeseeks.DIE; @@ -24,7 +24,6 @@ internal record FunctionResolution( string TypeFullName, Resolvable Resolvable, IReadOnlyList Parameter, - DisposalHandling DisposalHandling, IReadOnlyList LocalFunctions, SynchronicityDecision SynchronicityDecision) : Resolvable(Reference, TypeFullName); @@ -34,30 +33,27 @@ internal record RootResolutionFunction( string AccessModifier, Resolvable Resolvable, IReadOnlyList Parameter, - DisposalHandling DisposalHandling, IReadOnlyList LocalFunctions, SynchronicityDecision SynchronicityDecision) - : FunctionResolution(Reference, TypeFullName, Resolvable, Parameter, DisposalHandling, LocalFunctions, SynchronicityDecision); + : FunctionResolution(Reference, TypeFullName, Resolvable, Parameter, LocalFunctions, SynchronicityDecision); internal record LocalFunctionResolution( string Reference, string TypeFullName, Resolvable Resolvable, IReadOnlyList Parameter, - DisposalHandling DisposalHandling, IReadOnlyList LocalFunctions, SynchronicityDecision SynchronicityDecision) - : FunctionResolution(Reference, TypeFullName, Resolvable, Parameter, DisposalHandling, LocalFunctions, SynchronicityDecision); + : FunctionResolution(Reference, TypeFullName, Resolvable, Parameter, LocalFunctions, SynchronicityDecision); internal record RangedInstanceFunctionResolution( string Reference, string TypeFullName, Resolvable Resolvable, IReadOnlyList Parameter, - DisposalHandling DisposalHandling, IReadOnlyList LocalFunctions, SynchronicityDecision SynchronicityDecision) - : FunctionResolution(Reference, TypeFullName, Resolvable, Parameter, DisposalHandling, LocalFunctions, SynchronicityDecision); + : FunctionResolution(Reference, TypeFullName, Resolvable, Parameter, LocalFunctions, SynchronicityDecision); internal record RangedInstanceFunctionGroupResolution( string TypeFullName, @@ -75,6 +71,10 @@ internal record TransientScopeAsDisposableResolution( string Reference, string TypeFullName) : Resolvable(Reference, TypeFullName); +internal record TransientScopeAsAsyncDisposableResolution( + string Reference, + string TypeFullName) : Resolvable(Reference, TypeFullName); + internal record ErrorTreeItem( string Message) : Resolvable("error_99_99", "Error"); @@ -120,7 +120,7 @@ internal record ValueTaskTypeInitializationResolution( internal record ConstructorResolution( string Reference, string TypeFullName, - DisposableCollectionResolution? DisposableCollectionResolution, + DisposalType DisposalType, IReadOnlyList<(string Name, Resolvable Dependency)> Parameter, IReadOnlyList<(string Name, Resolvable Dependency)> InitializedProperties, ITypeInitializationResolution? Initialization) : Resolvable(Reference, TypeFullName), ITaskConsumableResolution; @@ -139,7 +139,6 @@ internal record TransientScopeRootResolution( string TransientScopeReference, string TransientScopeTypeFullName, string ContainerInstanceScopeReference, - DisposableCollectionResolution DisposableCollectionResolution, MultiSynchronicityFunctionCallResolution ScopeRootFunction) : Resolvable(ScopeRootFunction.Reference, ScopeRootFunction.TypeFullName); internal record ScopeRootResolution( @@ -147,7 +146,6 @@ internal record ScopeRootResolution( string ScopeTypeFullName, string ContainerInstanceScopeReference, string TransientInstanceScopeReference, - DisposableCollectionResolution DisposableCollectionResolution, MultiSynchronicityFunctionCallResolution ScopeRootFunction) : Resolvable(ScopeRootFunction.Reference, ScopeRootFunction.Sync.OriginalTypeFullName); internal record ScopeRootFunction( @@ -183,13 +181,24 @@ internal record CollectionResolution( string ItemFullName, IReadOnlyList Parameter) : Resolvable(Reference, TypeFullName); -internal record DisposableCollectionResolution( - string Reference, - string TypeFullName) +internal record SyncDisposableCollectionResolution( + string Reference, + string TypeFullName) + : ConstructorResolution( + Reference, + TypeFullName, + DisposalType.None, + Array.Empty<(string Name, Resolvable Dependency)>(), + Array.Empty<(string Name, Resolvable Dependency)>(), + null); + +internal record AsyncDisposableCollectionResolution( + string Reference, + string TypeFullName) : ConstructorResolution( Reference, TypeFullName, - null, + DisposalType.None, Array.Empty<(string Name, Resolvable Dependency)>(), Array.Empty<(string Name, Resolvable Dependency)>(), null); @@ -232,11 +241,15 @@ internal record ContainerResolution( TransientScopeInterfaceResolution TransientScopeInterface, string TransientScopeAdapterReference, IReadOnlyList TransientScopes, - IReadOnlyList Scopes) + IReadOnlyList Scopes, + DisposalType DisposalType, + string TransientScopeDisposalReference, + string TransientScopeDisposalElement) : RangeResolution(RootResolutions, DisposalHandling, RangedInstanceFunctionGroups, "this"); internal record DisposalHandling( - DisposableCollectionResolution DisposableCollection, + SyncDisposableCollectionResolution SyncDisposableCollection, + AsyncDisposableCollectionResolution AsyncDisposableCollection, string RangeName, string DisposedFieldReference, string DisposedLocalReference, diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index b12d4980..a51bf743 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -45,7 +45,7 @@ IContainerResolutionBuilder ResolutionTreeFactory(IContainerInfo ci) new TransientScopeInterfaceResolutionBuilder(referenceGeneratorFactory, wellKnownTypes, RangedFunctionGroupResolutionBuilderFactory, FunctionResolutionSynchronicityDecisionMakerFactory), referenceGeneratorFactory, - new CheckTypeProperties(new CurrentlyConsideredTypes(containerTypesFromAttributesList, context)), + new CheckTypeProperties(new CurrentlyConsideredTypes(containerTypesFromAttributesList, context), wellKnownTypes), wellKnownTypes, ScopeManagerFactory, ContainerCreateFunctionResolutionBuilderFactory, @@ -63,7 +63,7 @@ IScopeManager ScopeManagerFactory( TransientScopeResolutionBuilderFactory, ScopeResolutionBuilderFactory, ad => new ScopeTypesFromAttributes(ad, wellKnownTypes), - tfa => new CheckTypeProperties(new CurrentlyConsideredTypes(tfa, context)), + tfa => new CheckTypeProperties(new CurrentlyConsideredTypes(tfa, context), wellKnownTypes), st => new UserProvidedScopeElements(st), new EmptyUserProvidedScopeElements(), wellKnownTypes); diff --git a/Main/WellKnownTypes.cs b/Main/WellKnownTypes.cs index 94d6b01c..3c7b1bed 100644 --- a/Main/WellKnownTypes.cs +++ b/Main/WellKnownTypes.cs @@ -7,6 +7,8 @@ internal record WellKnownTypes( INamedTypeSymbol SpyConstructorChoiceAggregationAttribute, INamedTypeSymbol ImplementationAggregationAttribute, INamedTypeSymbol TransientAggregationAttribute, + INamedTypeSymbol SyncTransientAggregationAttribute, + INamedTypeSymbol AsyncTransientAggregationAttribute, INamedTypeSymbol ContainerInstanceAggregationAttribute, INamedTypeSymbol TransientScopeInstanceAggregationAttribute, INamedTypeSymbol ScopeInstanceAggregationAttribute, @@ -21,6 +23,8 @@ internal record WellKnownTypes( INamedTypeSymbol FilterSpyConstructorChoiceAggregationAttribute, INamedTypeSymbol FilterImplementationAggregationAttribute, INamedTypeSymbol FilterTransientAggregationAttribute, + INamedTypeSymbol FilterSyncTransientAggregationAttribute, + INamedTypeSymbol FilterAsyncTransientAggregationAttribute, INamedTypeSymbol FilterContainerInstanceAggregationAttribute, INamedTypeSymbol FilterTransientScopeInstanceAggregationAttribute, INamedTypeSymbol FilterScopeInstanceAggregationAttribute, @@ -44,7 +48,10 @@ internal record WellKnownTypes( INamedTypeSymbol Enumerable1, INamedTypeSymbol ReadOnlyCollection1, INamedTypeSymbol ReadOnlyList1, - INamedTypeSymbol ConcurrentBagOfDisposable, + INamedTypeSymbol ConcurrentBagOfSyncDisposable, + INamedTypeSymbol ConcurrentBagOfAsyncDisposable, + INamedTypeSymbol ConcurrentDictionaryOfSyncDisposable, + INamedTypeSymbol ConcurrentDictionaryOfAsyncDisposable, INamedTypeSymbol Action, INamedTypeSymbol Func, INamedTypeSymbol Exception, @@ -65,9 +72,19 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK var iReadOnlyCollection1 = compilation.GetTypeOrReport("System.Collections.Generic.IReadOnlyCollection`1"); var iReadOnlyList1 = compilation.GetTypeOrReport("System.Collections.Generic.IReadOnlyList`1"); var concurrentBag = compilation.GetTypeOrReport("System.Collections.Concurrent.ConcurrentBag`1"); - var concurrentBagOfDisposable = iDisposable is null + var concurrentBagOfSyncDisposable = iDisposable is null ? null : concurrentBag?.Construct(iDisposable); + var concurrentBagOfAsyncDisposable = iAsyncDisposable is null + ? null + : concurrentBag?.Construct(iAsyncDisposable); + var concurrentDictionary2= compilation.GetTypeOrReport("System.Collections.Concurrent.ConcurrentDictionary`2"); + var concurrentDictionary2OfSyncDisposable = iDisposable is null + ? null + : concurrentDictionary2?.Construct(iDisposable, iDisposable); + var concurrentDictionary2OfAsyncDisposable = iAsyncDisposable is null + ? null + : concurrentDictionary2?.Construct(iAsyncDisposable, iAsyncDisposable); var action = compilation.GetTypeOrReport("System.Action"); var func = compilation.GetTypeOrReport("System.Func`3"); var exception = compilation.GetTypeOrReport("System.Exception"); @@ -86,6 +103,12 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK var transientAggregationAttribute = compilation .GetTypeByMetadataName(typeof(TransientAggregationAttribute).FullName ?? ""); + var syncTransientAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(SyncTransientAggregationAttribute).FullName ?? ""); + + var asyncTransientAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(AsyncTransientAggregationAttribute).FullName ?? ""); + var containerInstanceAggregationAttribute = compilation .GetTypeByMetadataName(typeof(ContainerInstanceAggregationAttribute).FullName ?? ""); @@ -125,6 +148,12 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK var filterTransientAggregationAttribute = compilation .GetTypeByMetadataName(typeof(FilterTransientAggregationAttribute).FullName ?? ""); + var filterSyncTransientAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(FilterSyncTransientAggregationAttribute).FullName ?? ""); + + var filterAsyncTransientAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(FilterAsyncTransientAggregationAttribute).FullName ?? ""); + var filterContainerInstanceAggregationAttribute = compilation .GetTypeByMetadataName(typeof(FilterContainerInstanceAggregationAttribute).FullName ?? ""); @@ -168,6 +197,8 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK && spyConstructorChoiceAggregationAttribute is not null && implementationAggregationAttribute is not null && transientAggregationAttribute is not null + && syncTransientAggregationAttribute is not null + && asyncTransientAggregationAttribute is not null && containerInstanceAggregationAttribute is not null && transientScopeInstanceAggregationAttribute is not null && scopeInstanceAggregationAttribute is not null @@ -182,6 +213,8 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK && filterSpyConstructorChoiceAggregationAttribute is not null && filterImplementationAggregationAttribute is not null && filterTransientAggregationAttribute is not null + && filterSyncTransientAggregationAttribute is not null + && filterAsyncTransientAggregationAttribute is not null && filterContainerInstanceAggregationAttribute is not null && filterTransientScopeInstanceAggregationAttribute is not null && filterScopeInstanceAggregationAttribute is not null @@ -206,7 +239,10 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK && iEnumerable1 is not null && iReadOnlyCollection1 is not null && iReadOnlyList1 is not null - && concurrentBagOfDisposable is not null + && concurrentBagOfSyncDisposable is not null + && concurrentBagOfAsyncDisposable is not null + && concurrentDictionary2OfSyncDisposable is not null + && concurrentDictionary2OfAsyncDisposable is not null && action is not null && func is not null && exception is not null @@ -218,6 +254,8 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK SpyConstructorChoiceAggregationAttribute: spyConstructorChoiceAggregationAttribute, ImplementationAggregationAttribute: implementationAggregationAttribute, TransientAggregationAttribute: transientAggregationAttribute, + SyncTransientAggregationAttribute: syncTransientAggregationAttribute, + AsyncTransientAggregationAttribute: asyncTransientAggregationAttribute, ContainerInstanceAggregationAttribute: containerInstanceAggregationAttribute, TransientScopeInstanceAggregationAttribute: transientScopeInstanceAggregationAttribute, ScopeInstanceAggregationAttribute: scopeInstanceAggregationAttribute, @@ -232,6 +270,8 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK FilterSpyConstructorChoiceAggregationAttribute: filterSpyConstructorChoiceAggregationAttribute, FilterImplementationAggregationAttribute: filterImplementationAggregationAttribute, FilterTransientAggregationAttribute: filterTransientAggregationAttribute, + FilterSyncTransientAggregationAttribute: filterSyncTransientAggregationAttribute, + FilterAsyncTransientAggregationAttribute: filterAsyncTransientAggregationAttribute, FilterContainerInstanceAggregationAttribute: filterContainerInstanceAggregationAttribute, FilterTransientScopeInstanceAggregationAttribute: filterTransientScopeInstanceAggregationAttribute, FilterScopeInstanceAggregationAttribute: filterScopeInstanceAggregationAttribute, @@ -255,7 +295,10 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK Enumerable1: iEnumerable1, ReadOnlyCollection1: iReadOnlyCollection1, ReadOnlyList1: iReadOnlyList1, - ConcurrentBagOfDisposable: concurrentBagOfDisposable, + ConcurrentBagOfSyncDisposable: concurrentBagOfSyncDisposable, + ConcurrentBagOfAsyncDisposable: concurrentBagOfAsyncDisposable, + ConcurrentDictionaryOfSyncDisposable: concurrentDictionary2OfSyncDisposable, + ConcurrentDictionaryOfAsyncDisposable: concurrentDictionary2OfAsyncDisposable, Action: action, Func: func, Exception: exception, diff --git a/Sample/Context.cs b/Sample/Context.cs index 2ad076d5..24a3bf83 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -1,30 +1,86 @@ using System; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Sample; -namespace MrMeeseeks.DIE.Sample; -internal class Dependency : ITaskTypeInitializer +namespace MrMeeseeks.DIE.Test; + +internal interface ITransientScopeInstanceInner {} +internal class TransientScopeInstance : ITransientScopeInstanceInner, ITransientScopeInstance {} + +internal interface IScopeWithTransientScopeInstance {} + +internal class ScopeWithTransientScopeInstance : IScopeWithTransientScopeInstance, IScopeRoot { - public bool IsInitialized { get; private set; } - - async Task ITaskTypeInitializer.InitializeAsync() + public ScopeWithTransientScopeInstance(ITransientScopeInstanceInner _) {} +} + +internal interface IScopeWithTransientScopeInstanceAbove {} + +internal class ScopeWithTransientScopeInstanceAbove : IScopeWithTransientScopeInstanceAbove, IScopeRoot +{ + public ScopeWithTransientScopeInstanceAbove(IScopeWithTransientScopeInstance _) {} +} + +internal interface ITransientScopeWithTransientScopeInstance {} + +internal class TransientScopeWithTransientScopeInstance : ITransientScopeWithTransientScopeInstance, ITransientScopeRoot +{ + public TransientScopeWithTransientScopeInstance(IDisposable scopeDisposal, ITransientScopeInstanceInner _) {} +} + +internal interface ITransientScopeChild +{ + ITransientScopeInstanceInner TransientScopeInstance { get; } + bool Disposed { get; } +} + +internal class TransientScopeChild : ITransientScopeChild, IScopeRoot, IDisposable +{ + public TransientScopeChild(ITransientScopeInstanceInner transientScopeInstance) + { + TransientScopeInstance = transientScopeInstance; + } + + public ITransientScopeInstanceInner TransientScopeInstance { get; } + public bool Disposed { get; private set; } + + public void Dispose() { - await Task.Delay(500).ConfigureAwait(false); - IsInitialized = true; + Disposed = true; } } -internal class Instance : ITransientScopeInstance +internal interface ITransientScopeWithScopes { - public Dependency Dependency { get; } - - internal Instance(Dependency dependency) => Dependency = dependency; + ITransientScopeChild A { get; } + ITransientScopeChild B { get; } + void CleanUp(); } +internal class TransientScopeWithScopes : ITransientScopeWithScopes, ITransientScopeRoot +{ + private readonly IDisposable _scopeDisposal; + public TransientScopeWithScopes(IDisposable scopeDisposal, ITransientScopeChild a, ITransientScopeChild b) + { + _scopeDisposal = scopeDisposal; + A = a; + B = b; + } + public ITransientScopeChild A { get; } + public ITransientScopeChild B { get; } + public void CleanUp() + { + _scopeDisposal.Dispose(); + } +} -[CreateFunction(typeof(Func>), "CreateWithParameter")] -[CreateFunction(typeof(Func>), "CreateWithoutParameter")] -internal partial class Container +[CreateFunction(typeof(ITransientScopeInstanceInner), "Create0")] +[CreateFunction(typeof(IScopeWithTransientScopeInstance), "Create1")] +[CreateFunction(typeof(IScopeWithTransientScopeInstanceAbove), "Create2")] +[CreateFunction(typeof(ITransientScopeWithTransientScopeInstance), "Create3")] +[CreateFunction(typeof(ITransientScopeWithScopes), "Create4")] +internal partial class TransientScopeInstanceContainer { -} \ No newline at end of file + +} diff --git a/Test/Async/Awaited/AsyncScopeRootCallAsTask.cs b/Test/Async/Awaited/AsyncScopeRootCallAsTask.cs index 3bbbb2d4..edf104e6 100644 --- a/Test/Async/Awaited/AsyncScopeRootCallAsTask.cs +++ b/Test/Async/Awaited/AsyncScopeRootCallAsTask.cs @@ -35,7 +35,7 @@ public class Tests [Fact] public async ValueTask Test() { - using var container = new Container(); + var container = new Container(); var root = await container.Create().ConfigureAwait(false); Assert.True(root.Dep.IsInitialized); } diff --git a/Test/Async/Awaited/AsyncScopeRootCallAsValueTask.cs b/Test/Async/Awaited/AsyncScopeRootCallAsValueTask.cs index f24bb830..f66179cc 100644 --- a/Test/Async/Awaited/AsyncScopeRootCallAsValueTask.cs +++ b/Test/Async/Awaited/AsyncScopeRootCallAsValueTask.cs @@ -35,7 +35,7 @@ public class Tests [Fact] public async ValueTask Test() { - using var container = new Container(); + var container = new Container(); var root = await container.Create().ConfigureAwait(false); Assert.True(root.Dep.IsInitialized); } diff --git a/Test/Async/Awaited/AsyncScopeRootCallAwaited.cs b/Test/Async/Awaited/AsyncScopeRootCallAwaited.cs index 2d70df29..dc38a611 100644 --- a/Test/Async/Awaited/AsyncScopeRootCallAwaited.cs +++ b/Test/Async/Awaited/AsyncScopeRootCallAwaited.cs @@ -35,7 +35,7 @@ public class Tests [Fact] public async ValueTask Test() { - using var container = new Container(); + var container = new Container(); var root = await container.CreateValueAsync().ConfigureAwait(false); Assert.True(root.Dep.IsInitialized); } diff --git a/Test/Async/Awaited/ContainerInstanceFunctionAsTask.cs b/Test/Async/Awaited/ContainerInstanceFunctionAsTask.cs index bc375411..cb249d24 100644 --- a/Test/Async/Awaited/ContainerInstanceFunctionAsTask.cs +++ b/Test/Async/Awaited/ContainerInstanceFunctionAsTask.cs @@ -26,7 +26,7 @@ public class Tests [Fact] public async ValueTask Test() { - using var container = new Container(); + var container = new Container(); var instance = container.CreateValueAsync(); Assert.True((await instance.ConfigureAwait(false)).IsInitialized); } diff --git a/Test/Async/Awaited/ContainerInstanceFunctionAsValueTask.cs b/Test/Async/Awaited/ContainerInstanceFunctionAsValueTask.cs index 8c5d993d..94e22163 100644 --- a/Test/Async/Awaited/ContainerInstanceFunctionAsValueTask.cs +++ b/Test/Async/Awaited/ContainerInstanceFunctionAsValueTask.cs @@ -26,7 +26,7 @@ public class Tests [Fact] public async ValueTask Test() { - using var container = new Container(); + var container = new Container(); var instance = container.CreateValueAsync(); Assert.True((await instance.ConfigureAwait(false)).IsInitialized); } diff --git a/Test/Async/Awaited/ScopeInstanceFunctionAsTask.cs b/Test/Async/Awaited/ScopeInstanceFunctionAsTask.cs index ebf4d810..268e9c88 100644 --- a/Test/Async/Awaited/ScopeInstanceFunctionAsTask.cs +++ b/Test/Async/Awaited/ScopeInstanceFunctionAsTask.cs @@ -26,7 +26,7 @@ public class Tests [Fact] public async ValueTask Test() { - using var container = new Container(); + var container = new Container(); var instance = container.CreateValueAsync(); Assert.True((await instance.ConfigureAwait(false)).IsInitialized); } diff --git a/Test/Async/Awaited/ScopeInstanceFunctionAsValueTask.cs b/Test/Async/Awaited/ScopeInstanceFunctionAsValueTask.cs index eae807cb..7868d08e 100644 --- a/Test/Async/Awaited/ScopeInstanceFunctionAsValueTask.cs +++ b/Test/Async/Awaited/ScopeInstanceFunctionAsValueTask.cs @@ -26,7 +26,7 @@ public class Tests [Fact] public async ValueTask Test() { - using var container = new Container(); + var container = new Container(); var instance = container.CreateValueAsync(); Assert.True((await instance.ConfigureAwait(false)).IsInitialized); } diff --git a/Test/Async/Awaited/TaskTypeInitializerTask.cs b/Test/Async/Awaited/TaskTypeInitializerTask.cs index a1198c53..5012db68 100644 --- a/Test/Async/Awaited/TaskTypeInitializerTask.cs +++ b/Test/Async/Awaited/TaskTypeInitializerTask.cs @@ -26,7 +26,7 @@ public class Tests [Fact] public async ValueTask Test() { - using var container = new Container(); + var container = new Container(); var instance = await container.CreateAsync().ConfigureAwait(false); Assert.True(instance.IsInitialized); } diff --git a/Test/Async/Awaited/TaskTypeInitializerValueTask.cs b/Test/Async/Awaited/TaskTypeInitializerValueTask.cs index e6aed65d..64a09226 100644 --- a/Test/Async/Awaited/TaskTypeInitializerValueTask.cs +++ b/Test/Async/Awaited/TaskTypeInitializerValueTask.cs @@ -26,7 +26,7 @@ public class Tests [Fact] public async ValueTask Test() { - using var container = new Container(); + var container = new Container(); var instance = await container.CreateAsync().ConfigureAwait(false); Assert.True(instance.IsInitialized); } diff --git a/Test/Async/Awaited/TransientScopeInstanceFunctionAsTask.cs b/Test/Async/Awaited/TransientScopeInstanceFunctionAsTask.cs index f9bc8330..aea93a17 100644 --- a/Test/Async/Awaited/TransientScopeInstanceFunctionAsTask.cs +++ b/Test/Async/Awaited/TransientScopeInstanceFunctionAsTask.cs @@ -25,7 +25,7 @@ public class Tests [Fact] public async ValueTask Test() { - using var container = new Container(); + var container = new Container(); var instance = container.CreateValueAsync(); Assert.True((await instance.ConfigureAwait(false)).IsInitialized); } diff --git a/Test/Async/Awaited/TransientScopeInstanceFunctionAsValueTask.cs b/Test/Async/Awaited/TransientScopeInstanceFunctionAsValueTask.cs index a4a83c47..d956e93a 100644 --- a/Test/Async/Awaited/TransientScopeInstanceFunctionAsValueTask.cs +++ b/Test/Async/Awaited/TransientScopeInstanceFunctionAsValueTask.cs @@ -25,7 +25,7 @@ public class Tests [Fact] public async ValueTask Test() { - using var container = new Container(); + var container = new Container(); var instance = container.CreateValueAsync(); Assert.True((await instance.ConfigureAwait(false)).IsInitialized); } diff --git a/Test/Async/Awaited/TransientScopeInstanceFunction_DifferentSynchronicity.cs b/Test/Async/Awaited/TransientScopeInstanceFunction_DifferentSynchronicity.cs index a4932e90..e7ef889c 100644 --- a/Test/Async/Awaited/TransientScopeInstanceFunction_DifferentSynchronicity.cs +++ b/Test/Async/Awaited/TransientScopeInstanceFunction_DifferentSynchronicity.cs @@ -74,7 +74,7 @@ public class Tests [Fact] public async ValueTask Test() { - using var container = new Container(); + var container = new Container(); var instance0 = container.Create0ValueAsync(); var _ = container.Create1ValueAsync(); Assert.True((((await instance0.ConfigureAwait(false)).Dependency).Inner as DependencyA)?.IsInitialized); diff --git a/Test/Async/Wrapped/ContainerInstanceFunctionAsTask.cs b/Test/Async/Wrapped/ContainerInstanceFunctionAsTask.cs index e638db1e..678fb50d 100644 --- a/Test/Async/Wrapped/ContainerInstanceFunctionAsTask.cs +++ b/Test/Async/Wrapped/ContainerInstanceFunctionAsTask.cs @@ -26,7 +26,7 @@ public class Tests [Fact] public async ValueTask Test() { - using var container = new Container(); + var container = new Container(); var instance = container.Create(); Assert.True((await instance.ConfigureAwait(false)).IsInitialized); } diff --git a/Test/Async/Wrapped/ContainerInstanceFunctionAsValueTask.cs b/Test/Async/Wrapped/ContainerInstanceFunctionAsValueTask.cs index cbaba179..f4706d78 100644 --- a/Test/Async/Wrapped/ContainerInstanceFunctionAsValueTask.cs +++ b/Test/Async/Wrapped/ContainerInstanceFunctionAsValueTask.cs @@ -26,7 +26,7 @@ public class Tests [Fact] public async ValueTask Test() { - using var container = new Container(); + var container = new Container(); var instance = container.Create(); Assert.True((await instance.ConfigureAwait(false)).IsInitialized); } diff --git a/Test/Async/Wrapped/DecorationChaining.cs b/Test/Async/Wrapped/DecorationChaining.cs index 92a453eb..c6b59b03 100644 --- a/Test/Async/Wrapped/DecorationChaining.cs +++ b/Test/Async/Wrapped/DecorationChaining.cs @@ -58,7 +58,7 @@ public class Tests [Fact] public async ValueTask Test() { - using var container = new Container(); + var container = new Container(); var instance = await container.Create().ConfigureAwait(false); Assert.True(instance.IsInitialized); } diff --git a/Test/Async/Wrapped/Func.cs b/Test/Async/Wrapped/Func.cs index 2d3e2df9..021ad48f 100644 --- a/Test/Async/Wrapped/Func.cs +++ b/Test/Async/Wrapped/Func.cs @@ -27,7 +27,7 @@ public class Tests [Fact] public async ValueTask Test() { - using var container = new Container(); + var container = new Container(); var instance = container.Create(); Assert.True((await instance().ConfigureAwait(false)).IsInitialized); } diff --git a/Test/Async/Wrapped/Lazy.cs b/Test/Async/Wrapped/Lazy.cs index 369d8e8c..9e03f4b0 100644 --- a/Test/Async/Wrapped/Lazy.cs +++ b/Test/Async/Wrapped/Lazy.cs @@ -28,7 +28,7 @@ public class Tests [Fact] public async ValueTask Test() { - using var container = new Container(); + var container = new Container(); var instance = container.Create(); Assert.True((await instance.Value.ConfigureAwait(false)).IsInitialized); } diff --git a/Test/Async/Wrapped/ScopeInstanceFunctionAsTask.cs b/Test/Async/Wrapped/ScopeInstanceFunctionAsTask.cs index 83e38d25..ebfd8ecb 100644 --- a/Test/Async/Wrapped/ScopeInstanceFunctionAsTask.cs +++ b/Test/Async/Wrapped/ScopeInstanceFunctionAsTask.cs @@ -26,7 +26,7 @@ public class Tests [Fact] public async ValueTask Test() { - using var container = new Container(); + var container = new Container(); var instance = container.Create(); Assert.True((await instance.ConfigureAwait(false)).IsInitialized); } diff --git a/Test/Async/Wrapped/ScopeInstanceFunctionAsValueTask.cs b/Test/Async/Wrapped/ScopeInstanceFunctionAsValueTask.cs index db74cd0c..c0968abf 100644 --- a/Test/Async/Wrapped/ScopeInstanceFunctionAsValueTask.cs +++ b/Test/Async/Wrapped/ScopeInstanceFunctionAsValueTask.cs @@ -26,7 +26,7 @@ public class Tests [Fact] public async ValueTask Test() { - using var container = new Container(); + var container = new Container(); var instance = container.Create(); Assert.True((await instance.ConfigureAwait(false)).IsInitialized); } diff --git a/Test/Async/Wrapped/SyncToTask.cs b/Test/Async/Wrapped/SyncToTask.cs index d0fea881..015fbed1 100644 --- a/Test/Async/Wrapped/SyncToTask.cs +++ b/Test/Async/Wrapped/SyncToTask.cs @@ -24,7 +24,7 @@ public class Tests [Fact] public async ValueTask Test() { - using var container = new Container(); + var container = new Container(); var instance = await container.Create().ConfigureAwait(false); Assert.True(instance.IsInitialized); } diff --git a/Test/Async/Wrapped/SyncToValueTask.cs b/Test/Async/Wrapped/SyncToValueTask.cs index 2c76f5ba..205c469f 100644 --- a/Test/Async/Wrapped/SyncToValueTask.cs +++ b/Test/Async/Wrapped/SyncToValueTask.cs @@ -24,7 +24,7 @@ public class Tests [Fact] public async ValueTask Test() { - using var container = new Container(); + var container = new Container(); var instance = await container.Create().ConfigureAwait(false); Assert.True(instance.IsInitialized); } diff --git a/Test/Async/Wrapped/TaskCollection.cs b/Test/Async/Wrapped/TaskCollection.cs index 58d61429..02933f00 100644 --- a/Test/Async/Wrapped/TaskCollection.cs +++ b/Test/Async/Wrapped/TaskCollection.cs @@ -57,7 +57,7 @@ public class Tests [Fact] public async ValueTask Test() { - using var container = new Container(); + var container = new Container(); var instance = container.Create(); Assert.Equal(4, instance.Count); await Task.WhenAll(instance).ConfigureAwait(false); diff --git a/Test/Async/Wrapped/TaskComposition.cs b/Test/Async/Wrapped/TaskComposition.cs index b8f64976..7f281822 100644 --- a/Test/Async/Wrapped/TaskComposition.cs +++ b/Test/Async/Wrapped/TaskComposition.cs @@ -76,7 +76,7 @@ public class Tests [Fact] public async ValueTask Test() { - using var container = new Container(); + var container = new Container(); var instance = await container.Create().ConfigureAwait(false); Assert.IsType(instance); Assert.Equal(4, ((Composite) instance).Count); diff --git a/Test/Async/Wrapped/TaskToTask.cs b/Test/Async/Wrapped/TaskToTask.cs index 61a5bcf1..193f51e4 100644 --- a/Test/Async/Wrapped/TaskToTask.cs +++ b/Test/Async/Wrapped/TaskToTask.cs @@ -25,7 +25,7 @@ public class Tests [Fact] public async ValueTask Test() { - using var container = new Container(); + var container = new Container(); var instance = await container.Create().ConfigureAwait(false); Assert.True(instance.IsInitialized); } diff --git a/Test/Async/Wrapped/TaskToValueTask.cs b/Test/Async/Wrapped/TaskToValueTask.cs index f979c96b..c178bc8e 100644 --- a/Test/Async/Wrapped/TaskToValueTask.cs +++ b/Test/Async/Wrapped/TaskToValueTask.cs @@ -26,7 +26,7 @@ public class Tests [Fact] public async ValueTask Test() { - using var container = new Container(); + var container = new Container(); var instance = await container.Create().ConfigureAwait(false); Assert.True(instance.IsInitialized); } diff --git a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask.cs b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask.cs index 71a4df38..a795ad3b 100644 --- a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask.cs +++ b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask.cs @@ -25,7 +25,7 @@ public class Tests [Fact] public async ValueTask Test() { - using var container = new Container(); + var container = new Container(); var instance = container.Create(); Assert.True((await instance.ConfigureAwait(false)).IsInitialized); } diff --git a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask_DifferentSynchronicity.cs b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask_DifferentSynchronicity.cs index 58d62cb5..e2a95b7b 100644 --- a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask_DifferentSynchronicity.cs +++ b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask_DifferentSynchronicity.cs @@ -74,7 +74,7 @@ public class Tests [Fact] public async ValueTask Test() { - using var container = new Container(); + var container = new Container(); var instance0 = container.Create0(); var _ = container.Create1(); Assert.True(((await instance0.Dependency.ConfigureAwait(false)).Inner as DependencyA)?.IsInitialized); diff --git a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask.cs b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask.cs index 245368ab..9d2463b0 100644 --- a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask.cs +++ b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask.cs @@ -25,7 +25,7 @@ public class Tests [Fact] public async ValueTask Test() { - using var container = new Container(); + var container = new Container(); var instance = container.Create(); Assert.True((await instance.ConfigureAwait(false)).IsInitialized); } diff --git a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask_DifferentSynchronicity.cs b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask_DifferentSynchronicity.cs index 729dd3f4..52d1b899 100644 --- a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask_DifferentSynchronicity.cs +++ b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask_DifferentSynchronicity.cs @@ -74,7 +74,7 @@ public class Tests [Fact] public async ValueTask Test() { - using var container = new Container(); + var container = new Container(); var instance0 = container.Create0(); var _ = container.Create1(); Assert.True(((await instance0.Dependency.ConfigureAwait(false)).Inner as DependencyA)?.IsInitialized); diff --git a/Test/Async/Wrapped/ValueTaskCollection.cs b/Test/Async/Wrapped/ValueTaskCollection.cs index 94e0b00b..09ddba19 100644 --- a/Test/Async/Wrapped/ValueTaskCollection.cs +++ b/Test/Async/Wrapped/ValueTaskCollection.cs @@ -57,7 +57,7 @@ public class Tests [Fact] public async ValueTask Test() { - using var container = new Container(); + var container = new Container(); var instance = container.Create(); Assert.Equal(4, instance.Count); foreach (var task in instance) diff --git a/Test/Async/Wrapped/ValueTaskComposition.cs b/Test/Async/Wrapped/ValueTaskComposition.cs index fba71c64..aa8d313d 100644 --- a/Test/Async/Wrapped/ValueTaskComposition.cs +++ b/Test/Async/Wrapped/ValueTaskComposition.cs @@ -77,7 +77,7 @@ public class Tests [Fact] public async ValueTask Test() { - using var container = new Container(); + var container = new Container(); var instance = await container.Create().ConfigureAwait(false); Assert.IsType(instance); Assert.Equal(4, ((Composite) instance).Count); diff --git a/Test/Async/Wrapped/ValueTaskToTask.cs b/Test/Async/Wrapped/ValueTaskToTask.cs index ee5370b7..ea9598ca 100644 --- a/Test/Async/Wrapped/ValueTaskToTask.cs +++ b/Test/Async/Wrapped/ValueTaskToTask.cs @@ -26,7 +26,7 @@ public class Tests [Fact] public async ValueTask Test() { - using var container = new Container(); + var container = new Container(); var instance = await container.Create().ConfigureAwait(false); Assert.True(instance.IsInitialized); } diff --git a/Test/Async/Wrapped/ValueTaskToValueTask.cs b/Test/Async/Wrapped/ValueTaskToValueTask.cs index 1612a630..1ecf33a7 100644 --- a/Test/Async/Wrapped/ValueTaskToValueTask.cs +++ b/Test/Async/Wrapped/ValueTaskToValueTask.cs @@ -26,7 +26,7 @@ public class Tests [Fact] public async ValueTask Test() { - using var container = new Container(); + var container = new Container(); var instance = await container.Create().ConfigureAwait(false); Assert.True(instance.IsInitialized); } diff --git a/Test/CompositeTests.cs b/Test/CompositeTests.cs index 63ac7138..2e6d192f 100644 --- a/Test/CompositeTests.cs +++ b/Test/CompositeTests.cs @@ -43,7 +43,7 @@ public partial class CompositeTests [Fact] public void Normal() { - using var container = new CompositeNormalContainer(); + var container = new CompositeNormalContainer(); var composite = container.CreateDep(); foreach (var compositeComposite in composite.Composites) { @@ -56,7 +56,7 @@ public void Normal() [Fact] public void NormalList() { - using var container = new CompositeNormalContainer(); + var container = new CompositeNormalContainer(); var composites = container.CreateCollection(); foreach (var compositeComposite in composites) { @@ -102,7 +102,7 @@ public partial class CompositeTests [Fact] public void ContainerInstance() { - using var container = new CompositeContainerInstanceContainer(); + var container = new CompositeContainerInstanceContainer(); var composite = container.CreateDep(); foreach (var compositeComposite in composite.Composites) { @@ -117,7 +117,7 @@ public void ContainerInstance() [Fact] public void ContainerInstanceList() { - using var container = new CompositeContainerInstanceContainer(); + var container = new CompositeContainerInstanceContainer(); var composites = container.CreateCollection(); foreach (var compositeComposite in composites) { @@ -166,7 +166,7 @@ public partial class CompositeTests [Fact] public void MixedScoping() { - using var container = new CompositeMixedScopingContainer(); + var container = new CompositeMixedScopingContainer(); var composite = container.CreateDep(); foreach (var compositeComposite in composite.Composites) { @@ -181,7 +181,7 @@ public void MixedScoping() [Fact] public void MixedScopingList() { - using var container = new CompositeMixedScopingContainer(); + var container = new CompositeMixedScopingContainer(); var composites = container.CreateCollection(); foreach (var compositeComposite in composites) { @@ -245,7 +245,7 @@ public partial class CompositeTests [Fact] public void ScopeRoot() { - using var container = new CompositeScopeRootContainer(); + var container = new CompositeScopeRootContainer(); var composite = container.CreateDep(); foreach (var compositeComposite in composite.Composites) { @@ -261,7 +261,7 @@ public void ScopeRoot() [Fact] public void ScopeRootList() { - using var container = new CompositeScopeRootContainer(); + var container = new CompositeScopeRootContainer(); var composites = container.CreateCollection(); foreach (var compositeComposite in composites) { @@ -332,7 +332,7 @@ public partial class CompositeTests [Fact] public void Decorated() { - using var container = new CompositeDecoratedContainer(); + var container = new CompositeDecoratedContainer(); var composite = container.CreateDep(); Assert.IsType(composite); Assert.IsType(composite.Decorated); @@ -349,7 +349,7 @@ public void Decorated() [Fact] public void DecoratedList() { - using var container = new CompositeDecoratedContainer(); + var container = new CompositeDecoratedContainer(); var composites = container.CreateCollection(); foreach (var compositeComposite in composites) { diff --git a/Test/ConstructorChoiceTests.cs b/Test/ConstructorChoiceTests.cs index 72736e54..6b00ede0 100644 --- a/Test/ConstructorChoiceTests.cs +++ b/Test/ConstructorChoiceTests.cs @@ -18,7 +18,7 @@ public class ImplementationAggregationTests [Fact] public void ResolveExternalType() { - using var container = new ConstructorChoiceContainer(); + var container = new ConstructorChoiceContainer(); var dateTime = container.Create(); Assert.Equal(DateTime.MinValue, dateTime); } diff --git a/Test/ConstructorTests.cs b/Test/ConstructorTests.cs index b79ae3b7..2f75158d 100644 --- a/Test/ConstructorTests.cs +++ b/Test/ConstructorTests.cs @@ -27,7 +27,7 @@ public class ConstructorsTests [Fact] public void ResolveInitProperty() { - using var container = new ConstructorInitContainer(); + var container = new ConstructorInitContainer(); var resolution = container.Create(); Assert.NotNull(resolution.Dependency); Assert.IsType(resolution.Dependency); diff --git a/Test/Decorator/ContainerInstance.cs b/Test/Decorator/ContainerInstance.cs index ffa8c9da..beee7022 100644 --- a/Test/Decorator/ContainerInstance.cs +++ b/Test/Decorator/ContainerInstance.cs @@ -32,7 +32,7 @@ public class Tests [Fact] public void Test() { - using var container = new Container(); + var container = new Container(); var decorated = container.Create(); Assert.NotEqual(decorated, decorated.Decorated); Assert.IsType(decorated); diff --git a/Test/Decorator/List.cs b/Test/Decorator/List.cs index 3df164c1..1d365a35 100644 --- a/Test/Decorator/List.cs +++ b/Test/Decorator/List.cs @@ -38,7 +38,7 @@ public class Tests [Fact] public void Test() { - using var container = new Container(); + var container = new Container(); var decorated = container.Create(); var decoratedOfA = decorated[0]; var decoratedOfB = decorated[1]; diff --git a/Test/Decorator/Multi.cs b/Test/Decorator/Multi.cs index 89af08d9..1ae52eab 100644 --- a/Test/Decorator/Multi.cs +++ b/Test/Decorator/Multi.cs @@ -41,7 +41,7 @@ public class Tests [Fact] public void Test() { - using var container = new Container(); + var container = new Container(); var decorated = container.Create(); var decoratedB = decorated; var decoratedA = decorated.Decorated; diff --git a/Test/Decorator/Normal.cs b/Test/Decorator/Normal.cs index 04b64702..14224db8 100644 --- a/Test/Decorator/Normal.cs +++ b/Test/Decorator/Normal.cs @@ -32,7 +32,7 @@ public class Tests [Fact] public void Test() { - using var container = new Container(); + var container = new Container(); var decorated = container.Create(); Assert.NotEqual(decorated, decorated.Decorated); Assert.IsType(decorated); diff --git a/Test/Decorator/ScopeDecoratorForContainerDependency.cs b/Test/Decorator/ScopeDecoratorForContainerDependency.cs index 06ba84ff..d10389b3 100644 --- a/Test/Decorator/ScopeDecoratorForContainerDependency.cs +++ b/Test/Decorator/ScopeDecoratorForContainerDependency.cs @@ -42,7 +42,7 @@ public class Tests [Fact] public void Test() { - using var container = new Container(); + var container = new Container(); var scopeRoot0 = container.Create(); var decorator0 = scopeRoot0.Decorated; diff --git a/Test/Decorator/ScopeDecoratorForTransientScopeDependency.cs b/Test/Decorator/ScopeDecoratorForTransientScopeDependency.cs index e028e9ce..14dd59e4 100644 --- a/Test/Decorator/ScopeDecoratorForTransientScopeDependency.cs +++ b/Test/Decorator/ScopeDecoratorForTransientScopeDependency.cs @@ -42,7 +42,7 @@ public class Tests [Fact] public void Test() { - using var container = new Container(); + var container = new Container(); var scopeRoot0 = container.Create(); var decorator0 = scopeRoot0.Decorated; diff --git a/Test/Decorator/SequenceEdgeCase.cs b/Test/Decorator/SequenceEdgeCase.cs index e5912901..9357558c 100644 --- a/Test/Decorator/SequenceEdgeCase.cs +++ b/Test/Decorator/SequenceEdgeCase.cs @@ -67,7 +67,7 @@ public class Tests [Fact] public void Test() { - using var container0Then1 = new Container(); + var container0Then1 = new Container(); var _0Then1_0_2 = container0Then1.Create0().Decorated; var _0Then1_0_1 = _0Then1_0_2.Decorated; @@ -91,7 +91,7 @@ public void Test() Assert.Same(_0Then1_1_0, _0Then1_SanityCheck); - using var container1Then0 = new Container(); + var container1Then0 = new Container(); var _1Then0_1_1 = container1Then0.Create1().Decorated; var _1Then0_1_0 = _1Then0_1_1.Decorated; diff --git a/Test/Disposal/Async/Normal.cs b/Test/Disposal/Async/Normal.cs new file mode 100644 index 00000000..26deabbc --- /dev/null +++ b/Test/Disposal/Async/Normal.cs @@ -0,0 +1,36 @@ +using System; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Disposal.Async.Normal; + +internal class Dependency : IAsyncDisposable +{ + public bool IsDisposed { get; private set; } + + public async ValueTask DisposeAsync() + { + await Task.Delay(500).ConfigureAwait(false); + IsDisposed = true; + } +} + +[CreateFunction(typeof(Dependency), "Create")] +internal partial class Container +{ + +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var dependency = container.Create(); + Assert.False(dependency.IsDisposed); + await container.DisposeAsync().ConfigureAwait(false); + Assert.True(dependency.IsDisposed); + } +} \ No newline at end of file diff --git a/Test/Disposal/Sync/Normal.cs b/Test/Disposal/Sync/Normal.cs new file mode 100644 index 00000000..9d1a1025 --- /dev/null +++ b/Test/Disposal/Sync/Normal.cs @@ -0,0 +1,34 @@ +using System; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Disposal.Sync.Normal; + +internal class Dependency : IDisposable +{ + public bool IsDisposed { get; private set; } + + public void Dispose() + { + IsDisposed = true; + } +} + +[CreateFunction(typeof(Dependency), "Create")] +internal partial class Container +{ + +} + +public class Tests +{ + [Fact] + public void Test() + { + using var container = new Container(); + var dependency = container.Create(); + Assert.False(dependency.IsDisposed); + container.Dispose(); + Assert.True(dependency.IsDisposed); + } +} \ No newline at end of file diff --git a/Test/FactoryTests.cs b/Test/FactoryTests.cs index 795e8b23..35e91b35 100644 --- a/Test/FactoryTests.cs +++ b/Test/FactoryTests.cs @@ -51,7 +51,7 @@ public partial class FactoryTests public void ResolveExternalType() { var check = @"C:\HelloWorld.txt"; - using var container = new FactoryContainer(check); + var container = new FactoryContainer(check); var fileInfo = container.CreateFileInfo(); Assert.Equal(check, fileInfo.FullName); } @@ -60,7 +60,7 @@ public void ResolveExternalType() public void ResolveFromFactoryInTransientScope() { var check = @"C:\HelloWorld.txt"; - using var container = new FactoryContainer(check); + var container = new FactoryContainer(check); var transientScope = container.CreateFactoryContainerTransientScope(); Assert.Equal(69, transientScope.Number); } @@ -69,7 +69,7 @@ public void ResolveFromFactoryInTransientScope() public void ResolveFromFactoryInScope() { var check = @"C:\HelloWorld.txt"; - using var container = new FactoryContainer(check); + var container = new FactoryContainer(check); var scope = container.CreateFactoryContainerScope(); Assert.Equal("Yeah", scope.Yeah); } diff --git a/Test/Func/Vanilla.cs b/Test/Func/Vanilla.cs index fd934512..4fa53200 100644 --- a/Test/Func/Vanilla.cs +++ b/Test/Func/Vanilla.cs @@ -17,7 +17,7 @@ public class Tests [Fact] public void Test() { - using var container = new Container(); + var container = new Container(); var _ = container.Create()(DateTime.Now, new List()); } } diff --git a/Test/ImplementationAggregationTests.cs b/Test/ImplementationAggregationTests.cs index a6af72f7..6d11295b 100644 --- a/Test/ImplementationAggregationTests.cs +++ b/Test/ImplementationAggregationTests.cs @@ -18,7 +18,7 @@ public partial class ConstructorChoiceTests [Fact] public void ResolveExternalType() { - using var container = new ImplementationAggregationContainer(); + var container = new ImplementationAggregationContainer(); var path = @"C:\HelloWorld.txt"; var fileInfo = container.Create()(path); Assert.NotNull(fileInfo); diff --git a/Test/InstanceTests.cs b/Test/InstanceTests.cs index 4dc25eeb..4fa8a103 100644 --- a/Test/InstanceTests.cs +++ b/Test/InstanceTests.cs @@ -31,7 +31,7 @@ public partial class InstanceTests public void ResolveExternalType() { var check = "Hello, instance!"; - using var container = new InstanceContainer(check); + var container = new InstanceContainer(check); var instanceClass = container.Create(); Assert.Equal(check, instanceClass.Dependency); } diff --git a/Test/Lazy/Vanilla.cs b/Test/Lazy/Vanilla.cs index 338421c7..a76279a7 100644 --- a/Test/Lazy/Vanilla.cs +++ b/Test/Lazy/Vanilla.cs @@ -16,7 +16,7 @@ public class Tests [Fact] public void Test() { - using var container = new Container(); + var container = new Container(); var lazy = container.Create(); var _ = lazy.Value; } diff --git a/Test/PropertyTests.cs b/Test/PropertyTests.cs index 7a0f1af0..d598e1d5 100644 --- a/Test/PropertyTests.cs +++ b/Test/PropertyTests.cs @@ -33,7 +33,7 @@ public partial class PropertyTests public void ResolveExternalType() { var check = "Hello, Property!"; - using var container = new PropertyContainer(check); + var container = new PropertyContainer(check); var propertyClass = container.Create(); Assert.Equal(check, propertyClass.Dependency); } diff --git a/Test/ScopeSpecificAttributesTestsWithDecorator.cs b/Test/ScopeSpecificAttributesTestsWithDecorator.cs index 6898ecfd..b121c24c 100644 --- a/Test/ScopeSpecificAttributesTestsWithDecorator.cs +++ b/Test/ScopeSpecificAttributesTestsWithDecorator.cs @@ -128,35 +128,35 @@ public class ScopeSpecificAttributesTests [Fact] public void Container() { - using var container = new Container(); + var container = new Container(); var instance = container.Create0(); Assert.Equal(69, instance.CheckNumber); } [Fact] public void TransientScope() { - using var container = new Container(); + var container = new Container(); var instance = container.Create1(); Assert.Equal(23, instance.Dep.CheckNumber); } [Fact] public void TransientScopeSpecific() { - using var container = new Container(); + var container = new Container(); var instance = container.Create2(); Assert.Equal(7, instance.Dep.CheckNumber); } [Fact] public void Scope() { - using var container = new Container(); + var container = new Container(); var instance = container.Create3(); Assert.Equal(3, instance.Dep.CheckNumber); } [Fact] public void ScopeSpecific() { - using var container = new Container(); + var container = new Container(); var instance = container.Create4(); Assert.Equal(13, instance.Dep.CheckNumber); } diff --git a/Test/ScopeSpecificAttributesTestsWithImplementationLists.cs b/Test/ScopeSpecificAttributesTestsWithImplementationLists.cs index 956364eb..3a9c261e 100644 --- a/Test/ScopeSpecificAttributesTestsWithImplementationLists.cs +++ b/Test/ScopeSpecificAttributesTestsWithImplementationLists.cs @@ -51,7 +51,7 @@ public class Tests [Fact] public void Container() { - using var container = new Container(); + var container = new Container(); var dependencies = container.Create0(); Assert.Equal(3, dependencies.Count); Assert.Contains(dependencies, d => d.GetType() == typeof(DependencyContainer)); @@ -61,7 +61,7 @@ public void Container() [Fact] public void TransientScope() { - using var container = new Container(); + var container = new Container(); var dependencies = container.Create1(); Assert.Equal(1, dependencies.Dependencies.Count); Assert.Contains(dependencies.Dependencies, d => d.GetType() == typeof(DependencyTransientScope)); @@ -69,7 +69,7 @@ public void TransientScope() [Fact] public void Scope() { - using var container = new Container(); + var container = new Container(); var dependencies = container.Create2(); Assert.Equal(1, dependencies.Dependencies.Count); Assert.Contains(dependencies.Dependencies, d => d.GetType() == typeof(DependencyScope)); diff --git a/Test/ScopeSpecificAttributesTestsWithImplementations.cs b/Test/ScopeSpecificAttributesTestsWithImplementations.cs index 7fae0684..3ac58d11 100644 --- a/Test/ScopeSpecificAttributesTestsWithImplementations.cs +++ b/Test/ScopeSpecificAttributesTestsWithImplementations.cs @@ -52,21 +52,21 @@ public class Tests [Fact] public void Container() { - using var container = new Container(); + var container = new Container(); var dependency = container.Create0(); Assert.IsType(dependency); } [Fact] public void TransientScope() { - using var container = new Container(); + var container = new Container(); var dependency = container.Create1(); Assert.IsType(dependency.Dependency); } [Fact] public void Scope() { - using var container = new Container(); + var container = new Container(); var dependency = container.Create2(); Assert.IsType(dependency.Dependency); } diff --git a/Test/SyncTypeInitializationTest.cs b/Test/SyncTypeInitializationTest.cs index 40a8f290..f3eb8c5d 100644 --- a/Test/SyncTypeInitializationTest.cs +++ b/Test/SyncTypeInitializationTest.cs @@ -20,7 +20,7 @@ public partial class Tests [Fact] public void Test() { - using var container = new Container(); + var container = new Container(); var instance = container.Create0(); Assert.True(instance.IsInitialized); } diff --git a/Test/TransientScopeInstanceTests.cs b/Test/TransientScopeInstanceTests.cs index 89c60802..f2be4d50 100644 --- a/Test/TransientScopeInstanceTests.cs +++ b/Test/TransientScopeInstanceTests.cs @@ -137,5 +137,6 @@ public void TransientScopeWithScopes() transientScopeRoot.CleanUp(); Assert.True(transientScopeRoot.A.Disposed); Assert.True(transientScopeRoot.B.Disposed); + container.Dispose(); } } \ No newline at end of file diff --git a/Test/ValueTupleTests.cs b/Test/ValueTupleTests.cs index 86591d4f..8a740ab1 100644 --- a/Test/ValueTupleTests.cs +++ b/Test/ValueTupleTests.cs @@ -46,7 +46,7 @@ public partial class ValueTupleTests [Fact] public void ResolveValueTuple() { - using var container = new ValueTupleContainer(); + var container = new ValueTupleContainer(); var valueTupleBase = container.CreateDep(); Assert.Equal(25, valueTupleBase.Dependency._25); } @@ -91,7 +91,7 @@ public partial class ValueTupleTests [Fact] public void ResolveNonSyntaxValueTuple() { - using var container = new NonSyntaxValueTupleContainer(); + var container = new NonSyntaxValueTupleContainer(); var nonSyntaxValueTupleBase = container.CreateDep(); Assert.Equal(25, nonSyntaxValueTupleBase.Dependency.Item26); } @@ -127,7 +127,7 @@ public partial class ValueTupleTests [Fact] public void ResolveNonSyntaxSingleItemValueTuple() { - using var container = new NonSyntaxSingleItemValueTupleContainer(); + var container = new NonSyntaxSingleItemValueTupleContainer(); var NonSyntaxSingleItemValueTupleBase = container.CreateDep(); Assert.Equal(0, NonSyntaxSingleItemValueTupleBase.Dependency.Item1); } @@ -163,7 +163,7 @@ public partial class ValueTupleTests [Fact] public void ResolveNonSyntaxDoubleItemValueTuple() { - using var container = new NonSyntaxDoubleItemValueTupleContainer(); + var container = new NonSyntaxDoubleItemValueTupleContainer(); var NonSyntaxDoubleItemValueTupleBase = container.CreateDep(); Assert.Equal(1, NonSyntaxDoubleItemValueTupleBase.Dependency.Item2); } From 4c7c3e1d9ce261507a6a91a4574ce4ce70fef28c Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sat, 16 Apr 2022 17:33:38 +0200 Subject: [PATCH 061/162] Improved disposal handles of transient scopes --- Main/CodeBuilding/ContainerCodeBuilder.cs | 27 +++++++++++++++++++ Main/CodeBuilding/RangeCodeBaseBuilder.cs | 20 +++++++++----- .../ContainerResolutionBuilder.cs | 12 ++++++++- ...ontainerCreateFunctionResolutionBuilder.cs | 2 -- Main/ResolutionTreeItem.cs | 18 ++++++++++++- Sample/Program.cs | 27 +++++++++++++++++++ 6 files changed, 96 insertions(+), 10 deletions(-) diff --git a/Main/CodeBuilding/ContainerCodeBuilder.cs b/Main/CodeBuilding/ContainerCodeBuilder.cs index 55c89305..72ffbaa4 100644 --- a/Main/CodeBuilding/ContainerCodeBuilder.cs +++ b/Main/CodeBuilding/ContainerCodeBuilder.cs @@ -107,6 +107,33 @@ public override StringBuilder Build(StringBuilder stringBuilder) stringBuilder = _scopeCodeBuilders.Aggregate(stringBuilder, (sb, cb) => cb.Build(sb)); + var disposableTypeFullName = WellKnownTypes.Disposable.FullName(); + var asyncDisposableTypeFullName = WellKnownTypes.AsyncDisposable.FullName(); + var valueTaskFullName = WellKnownTypes.ValueTask.FullName(); + stringBuilder = stringBuilder + .AppendLine($"private class {_containerResolution.NopDisposable.ClassName} : {disposableTypeFullName}") + .AppendLine($"{{") + .AppendLine($"internal static {disposableTypeFullName} {_containerResolution.NopDisposable.InstanceReference} {{ get; }} = new {_containerResolution.NopDisposable.ClassName}();") + .AppendLine($"public void Dispose()") + .AppendLine($"{{") + .AppendLine($"}}") + .AppendLine($"}}") + .AppendLine($"private class {_containerResolution.NopAsyncDisposable.ClassName} : {asyncDisposableTypeFullName}") + .AppendLine($"{{") + .AppendLine($"internal static {asyncDisposableTypeFullName} {_containerResolution.NopAsyncDisposable.InstanceReference} {{ get; }} = new {_containerResolution.NopAsyncDisposable.ClassName}();") + .AppendLine($"public {valueTaskFullName} DisposeAsync() => {valueTaskFullName}.CompletedTask;") + .AppendLine($"}}") + .AppendLine($"private class {_containerResolution.SyncToAsyncDisposable.ClassName} : {asyncDisposableTypeFullName}") + .AppendLine($"{{") + .AppendLine($"private readonly {disposableTypeFullName} {_containerResolution.SyncToAsyncDisposable.DisposableFieldReference};") + .AppendLine($"internal {_containerResolution.SyncToAsyncDisposable.ClassName}({disposableTypeFullName} {_containerResolution.SyncToAsyncDisposable.DisposableParameterReference}) => {_containerResolution.SyncToAsyncDisposable.DisposableFieldReference} = {_containerResolution.SyncToAsyncDisposable.DisposableParameterReference};") + .AppendLine($"public {valueTaskFullName} DisposeAsync()") + .AppendLine($"{{") + .AppendLine($"{_containerResolution.SyncToAsyncDisposable.DisposableFieldReference}.Dispose();") + .AppendLine($"return {valueTaskFullName}.CompletedTask;") + .AppendLine($"}}") + .AppendLine($"}}"); + return stringBuilder .AppendLine($"}}") .AppendLine($"}}") diff --git a/Main/CodeBuilding/RangeCodeBaseBuilder.cs b/Main/CodeBuilding/RangeCodeBaseBuilder.cs index 842611db..15f81cae 100644 --- a/Main/CodeBuilding/RangeCodeBaseBuilder.cs +++ b/Main/CodeBuilding/RangeCodeBaseBuilder.cs @@ -463,14 +463,22 @@ private StringBuilder GenerateResolutions( $"{reference} = ({typeFullName}) {resolutionBase.Reference};"); break; case TransientScopeAsDisposableResolution(var reference, var typeFullName): - if (_containerResolution.DisposalType is not DisposalType.Sync) - throw new Exception(); - stringBuilder = stringBuilder.AppendLine($"{reference} = ({typeFullName}) this;"); + stringBuilder = _containerResolution.DisposalType switch + { + DisposalType.Async => throw new Exception("If the container disposal has to be async, then sync disposal handles in transient scopes are not allowed."), + DisposalType.Sync => stringBuilder.AppendLine($"{reference} = ({typeFullName}) this;"), + DisposalType.None => stringBuilder.AppendLine($"{reference} = ({typeFullName}) {_containerResolution.NopDisposable}.{_containerResolution.NopDisposable.InstanceReference};"), + _ => stringBuilder + }; break; case TransientScopeAsAsyncDisposableResolution(var reference, var typeFullName): - if (_containerResolution.DisposalType is not DisposalType.Async) - throw new Exception(); - stringBuilder = stringBuilder.AppendLine($"{reference} = ({typeFullName}) this;"); + stringBuilder = _containerResolution.DisposalType switch + { + DisposalType.Async => stringBuilder.AppendLine($"{reference} = ({typeFullName}) this;"), + DisposalType.Sync => stringBuilder.AppendLine($"{reference} = ({typeFullName}) new {_containerResolution.SyncToAsyncDisposable}(({WellKnownTypes.Disposable.FullName()}) this);"), + DisposalType.None => stringBuilder.AppendLine($"{reference} = ({typeFullName}) {_containerResolution.NopAsyncDisposable}.{_containerResolution.NopAsyncDisposable.InstanceReference};"), + _ => stringBuilder + }; break; case ConstructorResolution(var reference, var typeFullName, var disposalType, var parameters, var initializedProperties, var initialization): stringBuilder = parameters.Aggregate(stringBuilder, diff --git a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs index 42b711b1..bf4b45c5 100644 --- a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs @@ -324,7 +324,17 @@ public ContainerResolution Build() scopeResolutions, _disposalType, RootReferenceGenerator.Generate("transientScopeDisposal"), - RootReferenceGenerator.Generate("transientScopeToDispose")); + RootReferenceGenerator.Generate("transientScopeToDispose"), + new NopDisposable( + RootReferenceGenerator.Generate("NopDisposable"), + RootReferenceGenerator.Generate("Instance")), + new NopAsyncDisposable( + RootReferenceGenerator.Generate("NopDisposable"), + RootReferenceGenerator.Generate("Instance")), + new SyncToAsyncDisposable( + RootReferenceGenerator.Generate("NopDisposable"), + RootReferenceGenerator.Generate("disposable"), + RootReferenceGenerator.Generate("_disposable"))); } public void EnqueueRangedInstanceResolution( diff --git a/Main/ResolutionBuilding/Function/ContainerCreateFunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/ContainerCreateFunctionResolutionBuilder.cs index 9eefef99..5eee26d3 100644 --- a/Main/ResolutionBuilding/Function/ContainerCreateFunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/ContainerCreateFunctionResolutionBuilder.cs @@ -6,7 +6,6 @@ internal interface IContainerCreateFunctionResolutionBuilder : IFunctionResoluti internal class ContainerCreateFunctionResolutionBuilder : FunctionResolutionBuilder, IContainerCreateFunctionResolutionBuilder { - private readonly IRangeResolutionBaseBuilder _rangeResolutionBaseBuilder; private readonly INamedTypeSymbol _returnType; public ContainerCreateFunctionResolutionBuilder( @@ -22,7 +21,6 @@ public ContainerCreateFunctionResolutionBuilder( Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) : base(rangeResolutionBaseBuilder, returnType, Array.Empty<(ITypeSymbol, ParameterResolution)>(), synchronicityDecisionMaker, wellKnownTypes, referenceGeneratorFactory, localFunctionResolutionBuilderFactory) { - _rangeResolutionBaseBuilder = rangeResolutionBaseBuilder; _returnType = returnType; Name = RootReferenceGenerator.Generate("Create"); diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index c53d887a..514c237c 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -244,9 +244,25 @@ internal record ContainerResolution( IReadOnlyList Scopes, DisposalType DisposalType, string TransientScopeDisposalReference, - string TransientScopeDisposalElement) + string TransientScopeDisposalElement, + NopDisposable NopDisposable, + NopAsyncDisposable NopAsyncDisposable, + SyncToAsyncDisposable SyncToAsyncDisposable) : RangeResolution(RootResolutions, DisposalHandling, RangedInstanceFunctionGroups, "this"); +internal record NopDisposable( + string ClassName, + string InstanceReference); + +internal record NopAsyncDisposable( + string ClassName, + string InstanceReference); + +internal record SyncToAsyncDisposable( + string ClassName, + string DisposableParameterReference, + string DisposableFieldReference); + internal record DisposalHandling( SyncDisposableCollectionResolution SyncDisposableCollection, AsyncDisposableCollectionResolution AsyncDisposableCollection, diff --git a/Sample/Program.cs b/Sample/Program.cs index 497ea562..37092818 100644 --- a/Sample/Program.cs +++ b/Sample/Program.cs @@ -6,4 +6,31 @@ private static void Main() { Console.WriteLine("Hello, world!"); } + + private class NopDisposable : global::System.IDisposable + { + internal static global::System.IDisposable Instance { get; } = new NopDisposable(); + public void Dispose() + { + } + } + + private class NopAsyncDisposable : global::System.IAsyncDisposable + { + internal static global::System.IAsyncDisposable Instance { get; } = new NopAsyncDisposable(); + public global::System.Threading.Tasks.ValueTask DisposeAsync() => global::System.Threading.Tasks.ValueTask.CompletedTask; + } + + private class SyncToAsyncDisposable : global::System.IAsyncDisposable + { + private readonly IDisposable _disposable; + + internal SyncToAsyncDisposable(IDisposable disposable) => _disposable = disposable; + + public global::System.Threading.Tasks.ValueTask DisposeAsync() + { + _disposable.Dispose(); + return global::System.Threading.Tasks.ValueTask.CompletedTask; + } + } } \ No newline at end of file From 94e9d1f5499447eee3daea569a2788e0b43ab3cd Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sat, 16 Apr 2022 23:09:53 +0200 Subject: [PATCH 062/162] Testing disposal and some fixing --- Main/CodeBuilding/RangeCodeBaseBuilder.cs | 6 +- .../ContainerResolutionBuilder.cs | 2 +- .../Function/FunctionResolutionBuilder.cs | 2 +- .../RangedFunctionGroupResolutionBuilder.cs | 2 +- .../ScopeResolutionBuilder.cs | 2 +- .../TransientScopeResolutionBuilder.cs | 2 +- Sample/Context.cs | 91 ++++++------------- .../Async/{Normal.cs => InContainer.cs} | 2 +- Test/Disposal/Async/InScope.cs | 43 +++++++++ .../Disposal/Async/InScopeInTransientScope.cs | 59 ++++++++++++ Test/Disposal/Async/InTransientScope.cs | 43 +++++++++ .../Async/InTransientScopeInTransientScope.cs | 67 ++++++++++++++ .../Sync/{Normal.cs => InContainer.cs} | 2 +- Test/Disposal/Sync/InScope.cs | 38 ++++++++ Test/Disposal/Sync/InScopeInTransientScope.cs | 55 +++++++++++ Test/Disposal/Sync/InTransientScope.cs | 38 ++++++++ .../Sync/InTransientScopeInTransientScope.cs | 63 +++++++++++++ .../AsyncContainerToAsyncDisposalHandle.cs | 49 ++++++++++ .../NoneContainerToAsyncDisposalHandle.cs | 43 +++++++++ .../NoneContainerToSyncDisposalHandle.cs | 42 +++++++++ .../SyncContainerToAsyncDisposalHandle.cs | 45 +++++++++ .../SyncContainerToSyncDisposalHandle.cs | 44 +++++++++ 22 files changed, 666 insertions(+), 74 deletions(-) rename Test/Disposal/Async/{Normal.cs => InContainer.cs} (92%) create mode 100644 Test/Disposal/Async/InScope.cs create mode 100644 Test/Disposal/Async/InScopeInTransientScope.cs create mode 100644 Test/Disposal/Async/InTransientScope.cs create mode 100644 Test/Disposal/Async/InTransientScopeInTransientScope.cs rename Test/Disposal/Sync/{Normal.cs => InContainer.cs} (91%) create mode 100644 Test/Disposal/Sync/InScope.cs create mode 100644 Test/Disposal/Sync/InScopeInTransientScope.cs create mode 100644 Test/Disposal/Sync/InTransientScope.cs create mode 100644 Test/Disposal/Sync/InTransientScopeInTransientScope.cs create mode 100644 Test/Disposal/TransientScopeDisposalHandle/AsyncContainerToAsyncDisposalHandle.cs create mode 100644 Test/Disposal/TransientScopeDisposalHandle/NoneContainerToAsyncDisposalHandle.cs create mode 100644 Test/Disposal/TransientScopeDisposalHandle/NoneContainerToSyncDisposalHandle.cs create mode 100644 Test/Disposal/TransientScopeDisposalHandle/SyncContainerToAsyncDisposalHandle.cs create mode 100644 Test/Disposal/TransientScopeDisposalHandle/SyncContainerToSyncDisposalHandle.cs diff --git a/Main/CodeBuilding/RangeCodeBaseBuilder.cs b/Main/CodeBuilding/RangeCodeBaseBuilder.cs index 15f81cae..dc5a752b 100644 --- a/Main/CodeBuilding/RangeCodeBaseBuilder.cs +++ b/Main/CodeBuilding/RangeCodeBaseBuilder.cs @@ -467,7 +467,7 @@ private StringBuilder GenerateResolutions( { DisposalType.Async => throw new Exception("If the container disposal has to be async, then sync disposal handles in transient scopes are not allowed."), DisposalType.Sync => stringBuilder.AppendLine($"{reference} = ({typeFullName}) this;"), - DisposalType.None => stringBuilder.AppendLine($"{reference} = ({typeFullName}) {_containerResolution.NopDisposable}.{_containerResolution.NopDisposable.InstanceReference};"), + DisposalType.None => stringBuilder.AppendLine($"{reference} = ({typeFullName}) {_containerResolution.NopDisposable.ClassName}.{_containerResolution.NopDisposable.InstanceReference};"), _ => stringBuilder }; break; @@ -475,8 +475,8 @@ private StringBuilder GenerateResolutions( stringBuilder = _containerResolution.DisposalType switch { DisposalType.Async => stringBuilder.AppendLine($"{reference} = ({typeFullName}) this;"), - DisposalType.Sync => stringBuilder.AppendLine($"{reference} = ({typeFullName}) new {_containerResolution.SyncToAsyncDisposable}(({WellKnownTypes.Disposable.FullName()}) this);"), - DisposalType.None => stringBuilder.AppendLine($"{reference} = ({typeFullName}) {_containerResolution.NopAsyncDisposable}.{_containerResolution.NopAsyncDisposable.InstanceReference};"), + DisposalType.Sync => stringBuilder.AppendLine($"{reference} = ({typeFullName}) new {_containerResolution.SyncToAsyncDisposable.ClassName}(({WellKnownTypes.Disposable.FullName()}) this);"), + DisposalType.None => stringBuilder.AppendLine($"{reference} = ({typeFullName}) {_containerResolution.NopAsyncDisposable.ClassName}.{_containerResolution.NopAsyncDisposable.InstanceReference};"), _ => stringBuilder }; break; diff --git a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs index bf4b45c5..cdecaed0 100644 --- a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs @@ -119,7 +119,7 @@ public void DoWork() { while (HasWorkToDo) { - foreach ((IContainerCreateFunctionResolutionBuilder createFunction, _) in _rootResolutions.Where(r => r.CreateFunction.HasWorkToDo)) + foreach ((IContainerCreateFunctionResolutionBuilder createFunction, _) in _rootResolutions.Where(r => r.CreateFunction.HasWorkToDo).ToList()) { createFunction.DoWork(); } diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs index 71e9fff5..f266591c 100644 --- a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs @@ -939,7 +939,7 @@ public void DoWork() var _ = Resolvable.Value; while (LocalFunctions.Any(lf => lf.HasWorkToDo)) { - foreach (var localFunction in LocalFunctions) + foreach (var localFunction in LocalFunctions.ToList()) { localFunction.DoWork(); } diff --git a/Main/ResolutionBuilding/Function/RangedFunctionGroupResolutionBuilder.cs b/Main/ResolutionBuilding/Function/RangedFunctionGroupResolutionBuilder.cs index 4be19a3f..b096325e 100644 --- a/Main/ResolutionBuilding/Function/RangedFunctionGroupResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/RangedFunctionGroupResolutionBuilder.cs @@ -70,7 +70,7 @@ public IRangedFunctionResolutionBuilder GetInstanceFunction( public void DoWork() { while (_functionQueue.Any(f => f.HasWorkToDo)) - foreach (var function in _functionQueue.Where(f => f.HasWorkToDo)) + foreach (var function in _functionQueue.Where(f => f.HasWorkToDo).ToList()) function.DoWork(); } diff --git a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs index 59f6f2ab..c489d3b9 100644 --- a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs @@ -127,7 +127,7 @@ public void DoWork() { while (HasWorkToDo) { - foreach (var functionResolutionBuilder in _scopeRootFunctionResolutions.Values.Where(f => f.HasWorkToDo)) + foreach (var functionResolutionBuilder in _scopeRootFunctionResolutions.Values.Where(f => f.HasWorkToDo).ToList()) { functionResolutionBuilder.DoWork(); } diff --git a/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs b/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs index 96b39929..4a05eda7 100644 --- a/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs @@ -120,7 +120,7 @@ public void DoWork() { while (HasWorkToDo) { - foreach (var functionResolutionBuilder in _transientScopeRootFunctionResolutions.Values.Where(f => f.HasWorkToDo)) + foreach (var functionResolutionBuilder in _transientScopeRootFunctionResolutions.Values.Where(f => f.HasWorkToDo).ToList()) { functionResolutionBuilder.DoWork(); } diff --git a/Sample/Context.cs b/Sample/Context.cs index 24a3bf83..992f8b44 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -1,86 +1,49 @@ using System; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration; using MrMeeseeks.DIE.Sample; -namespace MrMeeseeks.DIE.Test; +namespace MrMeeseeks.DIE.Test.Disposal.Async.InTransientScopeInTransientScope; -internal interface ITransientScopeInstanceInner {} -internal class TransientScopeInstance : ITransientScopeInstanceInner, ITransientScopeInstance {} - -internal interface IScopeWithTransientScopeInstance {} - -internal class ScopeWithTransientScopeInstance : IScopeWithTransientScopeInstance, IScopeRoot -{ - public ScopeWithTransientScopeInstance(ITransientScopeInstanceInner _) {} -} - -internal interface IScopeWithTransientScopeInstanceAbove {} - -internal class ScopeWithTransientScopeInstanceAbove : IScopeWithTransientScopeInstanceAbove, IScopeRoot -{ - public ScopeWithTransientScopeInstanceAbove(IScopeWithTransientScopeInstance _) {} -} - -internal interface ITransientScopeWithTransientScopeInstance {} - -internal class TransientScopeWithTransientScopeInstance : ITransientScopeWithTransientScopeInstance, ITransientScopeRoot -{ - public TransientScopeWithTransientScopeInstance(IDisposable scopeDisposal, ITransientScopeInstanceInner _) {} -} - -internal interface ITransientScopeChild +internal class Dependency : IAsyncDisposable { - ITransientScopeInstanceInner TransientScopeInstance { get; } - bool Disposed { get; } -} - -internal class TransientScopeChild : ITransientScopeChild, IScopeRoot, IDisposable -{ - public TransientScopeChild(ITransientScopeInstanceInner transientScopeInstance) - { - TransientScopeInstance = transientScopeInstance; - } - - public ITransientScopeInstanceInner TransientScopeInstance { get; } - public bool Disposed { get; private set; } - - public void Dispose() + public bool IsDisposed { get; private set; } + + public async ValueTask DisposeAsync() { - Disposed = true; + await Task.Delay(500).ConfigureAwait(false); + IsDisposed = true; } } -internal interface ITransientScopeWithScopes +internal class TransientScopeRootInner : ITransientScopeRoot { - ITransientScopeChild A { get; } - ITransientScopeChild B { get; } - void CleanUp(); + public TransientScopeRootInner(Dependency dependency) => Dependency = dependency; + + internal Dependency Dependency { get; } } -internal class TransientScopeWithScopes : ITransientScopeWithScopes, ITransientScopeRoot +internal class TransientScopeRoot : ITransientScopeRoot { - private readonly IDisposable _scopeDisposal; + public TransientScopeRootInner TransientScopeRootInner { get; } + public Dependency Dependency { get; } + private readonly IAsyncDisposable _disposable; - public TransientScopeWithScopes(IDisposable scopeDisposal, ITransientScopeChild a, ITransientScopeChild b) + internal TransientScopeRoot( + TransientScopeRootInner transientScopeRootInner, + Dependency dependency, + IAsyncDisposable disposable) { - _scopeDisposal = scopeDisposal; - A = a; - B = b; - } - public ITransientScopeChild A { get; } - public ITransientScopeChild B { get; } - public void CleanUp() - { - _scopeDisposal.Dispose(); + TransientScopeRootInner = transientScopeRootInner; + Dependency = dependency; + _disposable = disposable; } + + internal ValueTask Cleanup() => _disposable.DisposeAsync(); } -[CreateFunction(typeof(ITransientScopeInstanceInner), "Create0")] -[CreateFunction(typeof(IScopeWithTransientScopeInstance), "Create1")] -[CreateFunction(typeof(IScopeWithTransientScopeInstanceAbove), "Create2")] -[CreateFunction(typeof(ITransientScopeWithTransientScopeInstance), "Create3")] -[CreateFunction(typeof(ITransientScopeWithScopes), "Create4")] -internal partial class TransientScopeInstanceContainer +[CreateFunction(typeof(TransientScopeRoot), "Create")] +internal partial class Container { } diff --git a/Test/Disposal/Async/Normal.cs b/Test/Disposal/Async/InContainer.cs similarity index 92% rename from Test/Disposal/Async/Normal.cs rename to Test/Disposal/Async/InContainer.cs index 26deabbc..55e7b47d 100644 --- a/Test/Disposal/Async/Normal.cs +++ b/Test/Disposal/Async/InContainer.cs @@ -3,7 +3,7 @@ using MrMeeseeks.DIE.Configuration; using Xunit; -namespace MrMeeseeks.DIE.Test.Disposal.Async.Normal; +namespace MrMeeseeks.DIE.Test.Disposal.Async.InContainer; internal class Dependency : IAsyncDisposable { diff --git a/Test/Disposal/Async/InScope.cs b/Test/Disposal/Async/InScope.cs new file mode 100644 index 00000000..b00a0ff2 --- /dev/null +++ b/Test/Disposal/Async/InScope.cs @@ -0,0 +1,43 @@ +using System; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Disposal.Async.InScope; + +internal class Dependency : IAsyncDisposable +{ + public bool IsDisposed { get; private set; } + + public async ValueTask DisposeAsync() + { + await Task.Delay(500).ConfigureAwait(false); + IsDisposed = true; + } +} + +internal class ScopeRoot : IScopeRoot +{ + public ScopeRoot(Dependency dependency) => Dependency = dependency; + + internal Dependency Dependency { get; } +} + +[CreateFunction(typeof(ScopeRoot), "Create")] +internal partial class Container +{ + +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var dependency = container.Create(); + Assert.False(dependency.Dependency.IsDisposed); + await container.DisposeAsync().ConfigureAwait(false); + Assert.True(dependency.Dependency.IsDisposed); + } +} \ No newline at end of file diff --git a/Test/Disposal/Async/InScopeInTransientScope.cs b/Test/Disposal/Async/InScopeInTransientScope.cs new file mode 100644 index 00000000..eb13b95c --- /dev/null +++ b/Test/Disposal/Async/InScopeInTransientScope.cs @@ -0,0 +1,59 @@ +using System; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Disposal.Async.InScopeInTransientScope; + +internal class Dependency : IAsyncDisposable +{ + public bool IsDisposed { get; private set; } + + public async ValueTask DisposeAsync() + { + await Task.Delay(500).ConfigureAwait(false); + IsDisposed = true; + } +} + +internal class ScopeRoot : IScopeRoot +{ + public ScopeRoot(Dependency dependency) => Dependency = dependency; + + internal Dependency Dependency { get; } +} + +internal class TransientScopeRoot : ITransientScopeRoot +{ + public ScopeRoot ScopeRoot { get; } + private readonly IAsyncDisposable _disposable; + + internal TransientScopeRoot( + ScopeRoot scopeRoot, + IAsyncDisposable disposable) + { + ScopeRoot = scopeRoot; + _disposable = disposable; + } + + internal ValueTask Cleanup() => _disposable.DisposeAsync(); +} + +[CreateFunction(typeof(TransientScopeRoot), "Create")] +internal partial class Container +{ + +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var transientScopeRoot = container.Create(); + Assert.False(transientScopeRoot.ScopeRoot.Dependency.IsDisposed); + await transientScopeRoot.Cleanup().ConfigureAwait(false); + Assert.True(transientScopeRoot.ScopeRoot.Dependency.IsDisposed); + } +} \ No newline at end of file diff --git a/Test/Disposal/Async/InTransientScope.cs b/Test/Disposal/Async/InTransientScope.cs new file mode 100644 index 00000000..1bdc9873 --- /dev/null +++ b/Test/Disposal/Async/InTransientScope.cs @@ -0,0 +1,43 @@ +using System; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Disposal.Async.InTransientScope; + +internal class Dependency : IAsyncDisposable +{ + public bool IsDisposed { get; private set; } + + public async ValueTask DisposeAsync() + { + await Task.Delay(500).ConfigureAwait(false); + IsDisposed = true; + } +} + +internal class TransientScopeRoot : ITransientScopeRoot +{ + public TransientScopeRoot(Dependency dependency) => Dependency = dependency; + + internal Dependency Dependency { get; } +} + +[CreateFunction(typeof(TransientScopeRoot), "Create")] +internal partial class Container +{ + +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var dependency = container.Create(); + Assert.False(dependency.Dependency.IsDisposed); + await container.DisposeAsync().ConfigureAwait(false); + Assert.True(dependency.Dependency.IsDisposed); + } +} \ No newline at end of file diff --git a/Test/Disposal/Async/InTransientScopeInTransientScope.cs b/Test/Disposal/Async/InTransientScopeInTransientScope.cs new file mode 100644 index 00000000..1e8134aa --- /dev/null +++ b/Test/Disposal/Async/InTransientScopeInTransientScope.cs @@ -0,0 +1,67 @@ +using System; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Disposal.Async.InTransientScopeInTransientScope; + +internal class Dependency : IAsyncDisposable +{ + public bool IsDisposed { get; private set; } + + public async ValueTask DisposeAsync() + { + await Task.Delay(500).ConfigureAwait(false); + IsDisposed = true; + } +} + +internal class TransientScopeRootInner : ITransientScopeRoot +{ + public TransientScopeRootInner(Dependency dependency) => Dependency = dependency; + + internal Dependency Dependency { get; } +} + +internal class TransientScopeRoot : ITransientScopeRoot +{ + public TransientScopeRootInner TransientScopeRootInner { get; } + public Dependency Dependency { get; } + private readonly IAsyncDisposable _disposable; + + internal TransientScopeRoot( + TransientScopeRootInner transientScopeRootInner, + Dependency dependency, + IAsyncDisposable disposable) + { + TransientScopeRootInner = transientScopeRootInner; + Dependency = dependency; + _disposable = disposable; + } + + internal ValueTask Cleanup() => _disposable.DisposeAsync(); +} + +[CreateFunction(typeof(TransientScopeRoot), "Create")] +internal partial class Container +{ + +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var transientScopeRoot = container.Create(); + Assert.False(transientScopeRoot.TransientScopeRootInner.Dependency.IsDisposed); + Assert.False(transientScopeRoot.Dependency.IsDisposed); + await transientScopeRoot.Cleanup().ConfigureAwait(false); + Assert.False(transientScopeRoot.TransientScopeRootInner.Dependency.IsDisposed); + Assert.True(transientScopeRoot.Dependency.IsDisposed); + await container.DisposeAsync().ConfigureAwait(false); + Assert.True(transientScopeRoot.TransientScopeRootInner.Dependency.IsDisposed); + Assert.True(transientScopeRoot.Dependency.IsDisposed); + } +} \ No newline at end of file diff --git a/Test/Disposal/Sync/Normal.cs b/Test/Disposal/Sync/InContainer.cs similarity index 91% rename from Test/Disposal/Sync/Normal.cs rename to Test/Disposal/Sync/InContainer.cs index 9d1a1025..d0d86066 100644 --- a/Test/Disposal/Sync/Normal.cs +++ b/Test/Disposal/Sync/InContainer.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration; using Xunit; -namespace MrMeeseeks.DIE.Test.Disposal.Sync.Normal; +namespace MrMeeseeks.DIE.Test.Disposal.Sync.InContainer; internal class Dependency : IDisposable { diff --git a/Test/Disposal/Sync/InScope.cs b/Test/Disposal/Sync/InScope.cs new file mode 100644 index 00000000..fee5a612 --- /dev/null +++ b/Test/Disposal/Sync/InScope.cs @@ -0,0 +1,38 @@ +using System; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Disposal.Sync.InScope; + +internal class Dependency : IDisposable +{ + public bool IsDisposed { get; private set; } + + public void Dispose() => IsDisposed = true; +} + +internal class ScopeRoot : IScopeRoot +{ + public ScopeRoot(Dependency dependency) => Dependency = dependency; + + internal Dependency Dependency { get; } +} + +[CreateFunction(typeof(ScopeRoot), "Create")] +internal partial class Container +{ + +} + +public class Tests +{ + [Fact] + public void Test() + { + using var container = new Container(); + var dependency = container.Create(); + Assert.False(dependency.Dependency.IsDisposed); + container.Dispose(); + Assert.True(dependency.Dependency.IsDisposed); + } +} \ No newline at end of file diff --git a/Test/Disposal/Sync/InScopeInTransientScope.cs b/Test/Disposal/Sync/InScopeInTransientScope.cs new file mode 100644 index 00000000..fdadf842 --- /dev/null +++ b/Test/Disposal/Sync/InScopeInTransientScope.cs @@ -0,0 +1,55 @@ +using System; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Disposal.Sync.InScopeInTransientScope; + +internal class Dependency : IDisposable +{ + public bool IsDisposed { get; private set; } + + public void Dispose() => IsDisposed = true; +} + +internal class ScopeRoot : IScopeRoot +{ + public ScopeRoot(Dependency dependency) => Dependency = dependency; + + internal Dependency Dependency { get; } +} + +internal class TransientScopeRoot : ITransientScopeRoot +{ + public ScopeRoot ScopeRoot { get; } + private readonly IDisposable _disposable; + + internal TransientScopeRoot( + ScopeRoot scopeRoot, + IDisposable disposable) + { + ScopeRoot = scopeRoot; + _disposable = disposable; + } + + internal void Cleanup() => _disposable.Dispose(); +} + +[CreateFunction(typeof(TransientScopeRoot), "Create")] +internal partial class Container +{ + +} + +public class Tests +{ + [Fact] + public void Test() + { + using var container = new Container(); + var transientScopeRoot = container.Create(); + Assert.False(transientScopeRoot.ScopeRoot.Dependency.IsDisposed); + transientScopeRoot.Cleanup(); + Assert.True(transientScopeRoot.ScopeRoot.Dependency.IsDisposed); + } +} \ No newline at end of file diff --git a/Test/Disposal/Sync/InTransientScope.cs b/Test/Disposal/Sync/InTransientScope.cs new file mode 100644 index 00000000..5c3d9756 --- /dev/null +++ b/Test/Disposal/Sync/InTransientScope.cs @@ -0,0 +1,38 @@ +using System; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Disposal.Sync.InTransientScope; + +internal class Dependency : IDisposable +{ + public bool IsDisposed { get; private set; } + + public void Dispose() => IsDisposed = true; +} + +internal class TransientScopeRoot : ITransientScopeRoot +{ + public TransientScopeRoot(Dependency dependency) => Dependency = dependency; + + internal Dependency Dependency { get; } +} + +[CreateFunction(typeof(TransientScopeRoot), "Create")] +internal partial class Container +{ + +} + +public class Tests +{ + [Fact] + public void Test() + { + using var container = new Container(); + var dependency = container.Create(); + Assert.False(dependency.Dependency.IsDisposed); + container.Dispose(); + Assert.True(dependency.Dependency.IsDisposed); + } +} \ No newline at end of file diff --git a/Test/Disposal/Sync/InTransientScopeInTransientScope.cs b/Test/Disposal/Sync/InTransientScopeInTransientScope.cs new file mode 100644 index 00000000..fff30a3b --- /dev/null +++ b/Test/Disposal/Sync/InTransientScopeInTransientScope.cs @@ -0,0 +1,63 @@ +using System; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Disposal.Sync.InTransientScopeInTransientScope; + +internal class Dependency : IDisposable +{ + public bool IsDisposed { get; private set; } + + public void Dispose() => IsDisposed = true; +} + +internal class TransientScopeRootInner : ITransientScopeRoot +{ + public TransientScopeRootInner(Dependency dependency) => Dependency = dependency; + + internal Dependency Dependency { get; } +} + +internal class TransientScopeRoot : ITransientScopeRoot +{ + public TransientScopeRootInner TransientScopeRootInner { get; } + public Dependency Dependency { get; } + private readonly IDisposable _disposable; + + internal TransientScopeRoot( + TransientScopeRootInner transientScopeRootInner, + Dependency dependency, + IDisposable disposable) + { + TransientScopeRootInner = transientScopeRootInner; + Dependency = dependency; + _disposable = disposable; + } + + internal void Cleanup() => _disposable.Dispose(); +} + +[CreateFunction(typeof(TransientScopeRoot), "Create")] +internal partial class Container +{ + +} + +public class Tests +{ + [Fact] + public void Test() + { + using var container = new Container(); + var transientScopeRoot = container.Create(); + Assert.False(transientScopeRoot.TransientScopeRootInner.Dependency.IsDisposed); + Assert.False(transientScopeRoot.Dependency.IsDisposed); + transientScopeRoot.Cleanup(); + Assert.False(transientScopeRoot.TransientScopeRootInner.Dependency.IsDisposed); + Assert.True(transientScopeRoot.Dependency.IsDisposed); + container.Dispose(); + Assert.True(transientScopeRoot.TransientScopeRootInner.Dependency.IsDisposed); + Assert.True(transientScopeRoot.Dependency.IsDisposed); + } +} \ No newline at end of file diff --git a/Test/Disposal/TransientScopeDisposalHandle/AsyncContainerToAsyncDisposalHandle.cs b/Test/Disposal/TransientScopeDisposalHandle/AsyncContainerToAsyncDisposalHandle.cs new file mode 100644 index 00000000..e53351f1 --- /dev/null +++ b/Test/Disposal/TransientScopeDisposalHandle/AsyncContainerToAsyncDisposalHandle.cs @@ -0,0 +1,49 @@ +using System; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Disposal.TransientScopeDisposalHandle.AsyncContainerToAsyncDisposalHandle; + +internal class Dependency : IAsyncDisposable +{ + internal bool IsDisposed { get; private set; } + + public async ValueTask DisposeAsync() + { + await Task.Delay(500).ConfigureAwait(false); + IsDisposed = true; + } +} + +internal class TransientScopeRoot : ITransientScopeRoot +{ + internal Dependency Dependency { get; } + private readonly IAsyncDisposable _disposable; + + internal TransientScopeRoot( + Dependency dependency, + IAsyncDisposable disposable) + { + Dependency = dependency; + _disposable = disposable; + } + + internal ValueTask Cleanup() => _disposable.DisposeAsync(); +} + +[CreateFunction(typeof(TransientScopeRoot), "Create")] +internal partial class Container {} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var transientScopeRoot = container.Create(); + Assert.False(transientScopeRoot.Dependency.IsDisposed); + await transientScopeRoot.Cleanup().ConfigureAwait(false); + Assert.True(transientScopeRoot.Dependency.IsDisposed); + } +} \ No newline at end of file diff --git a/Test/Disposal/TransientScopeDisposalHandle/NoneContainerToAsyncDisposalHandle.cs b/Test/Disposal/TransientScopeDisposalHandle/NoneContainerToAsyncDisposalHandle.cs new file mode 100644 index 00000000..87d955f1 --- /dev/null +++ b/Test/Disposal/TransientScopeDisposalHandle/NoneContainerToAsyncDisposalHandle.cs @@ -0,0 +1,43 @@ +using System; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Disposal.TransientScopeDisposalHandle.NoneContainerToAsyncDisposalHandle; + +internal class Dependency +{ + internal bool IsDisposed => true; +} + +internal class TransientScopeRoot : ITransientScopeRoot +{ + internal Dependency Dependency { get; } + private readonly IAsyncDisposable _disposable; + + internal TransientScopeRoot( + Dependency dependency, + IAsyncDisposable disposable) + { + Dependency = dependency; + _disposable = disposable; + } + + internal ValueTask Cleanup() => _disposable.DisposeAsync(); +} + +[CreateFunction(typeof(TransientScopeRoot), "Create")] +internal partial class Container {} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + var container = new Container(); + var transientScopeRoot = container.Create(); + Assert.True(transientScopeRoot.Dependency.IsDisposed); + await transientScopeRoot.Cleanup().ConfigureAwait(false); + Assert.True(transientScopeRoot.Dependency.IsDisposed); + } +} \ No newline at end of file diff --git a/Test/Disposal/TransientScopeDisposalHandle/NoneContainerToSyncDisposalHandle.cs b/Test/Disposal/TransientScopeDisposalHandle/NoneContainerToSyncDisposalHandle.cs new file mode 100644 index 00000000..b6c94abc --- /dev/null +++ b/Test/Disposal/TransientScopeDisposalHandle/NoneContainerToSyncDisposalHandle.cs @@ -0,0 +1,42 @@ +using System; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Disposal.TransientScopeDisposalHandle.NoneContainerToSyncDisposalHandle; + +internal class Dependency +{ + internal bool IsDisposed => true; +} + +internal class TransientScopeRoot : ITransientScopeRoot +{ + internal Dependency Dependency { get; } + private readonly IDisposable _disposable; + + internal TransientScopeRoot( + Dependency dependency, + IDisposable disposable) + { + Dependency = dependency; + _disposable = disposable; + } + + internal void Cleanup() => _disposable.Dispose(); +} + +[CreateFunction(typeof(TransientScopeRoot), "Create")] +internal partial class Container {} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var transientScopeRoot = container.Create(); + Assert.True(transientScopeRoot.Dependency.IsDisposed); + transientScopeRoot.Cleanup(); + Assert.True(transientScopeRoot.Dependency.IsDisposed); + } +} \ No newline at end of file diff --git a/Test/Disposal/TransientScopeDisposalHandle/SyncContainerToAsyncDisposalHandle.cs b/Test/Disposal/TransientScopeDisposalHandle/SyncContainerToAsyncDisposalHandle.cs new file mode 100644 index 00000000..595957bb --- /dev/null +++ b/Test/Disposal/TransientScopeDisposalHandle/SyncContainerToAsyncDisposalHandle.cs @@ -0,0 +1,45 @@ +using System; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Disposal.TransientScopeDisposalHandle.SyncContainerToAsyncDisposalHandle; + +internal class Dependency : IDisposable +{ + internal bool IsDisposed { get; private set; } + + public void Dispose() => IsDisposed = true; +} + +internal class TransientScopeRoot : ITransientScopeRoot +{ + internal Dependency Dependency { get; } + private readonly IAsyncDisposable _disposable; + + internal TransientScopeRoot( + Dependency dependency, + IAsyncDisposable disposable) + { + Dependency = dependency; + _disposable = disposable; + } + + internal ValueTask Cleanup() => _disposable.DisposeAsync(); +} + +[CreateFunction(typeof(TransientScopeRoot), "Create")] +internal partial class Container {} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + using var container = new Container(); + var transientScopeRoot = container.Create(); + Assert.False(transientScopeRoot.Dependency.IsDisposed); + await transientScopeRoot.Cleanup().ConfigureAwait(false); + Assert.True(transientScopeRoot.Dependency.IsDisposed); + } +} \ No newline at end of file diff --git a/Test/Disposal/TransientScopeDisposalHandle/SyncContainerToSyncDisposalHandle.cs b/Test/Disposal/TransientScopeDisposalHandle/SyncContainerToSyncDisposalHandle.cs new file mode 100644 index 00000000..91898a5d --- /dev/null +++ b/Test/Disposal/TransientScopeDisposalHandle/SyncContainerToSyncDisposalHandle.cs @@ -0,0 +1,44 @@ +using System; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Disposal.TransientScopeDisposalHandle.SyncContainerToSyncDisposalHandle; + +internal class Dependency : IDisposable +{ + internal bool IsDisposed { get; private set; } + + public void Dispose() => IsDisposed = true; +} + +internal class TransientScopeRoot : ITransientScopeRoot +{ + internal Dependency Dependency { get; } + private readonly IDisposable _disposable; + + internal TransientScopeRoot( + Dependency dependency, + IDisposable disposable) + { + Dependency = dependency; + _disposable = disposable; + } + + internal void Cleanup() => _disposable.Dispose(); +} + +[CreateFunction(typeof(TransientScopeRoot), "Create")] +internal partial class Container {} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var transientScopeRoot = container.Create(); + Assert.False(transientScopeRoot.Dependency.IsDisposed); + transientScopeRoot.Cleanup(); + Assert.True(transientScopeRoot.Dependency.IsDisposed); + } +} \ No newline at end of file From 8c23fc9a100e340c17cb6cd560cdc6e5c67f28d8 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sun, 17 Apr 2022 19:56:30 +0200 Subject: [PATCH 063/162] Spyable constructors --- Main/Configuration/Attributes.cs | 4 +- Main/Configuration/TypesFromAttributes.cs | 69 ++++++++++++++++++----- Main/WellKnownTypes.cs | 8 --- Sample/Context.cs | 50 +++------------- Sample/Program.cs | 27 --------- Sample/Sample.csproj | 3 +- Spy/Attributes.cs | 11 ---- Spy/TypeReportGenerator.cs | 54 +++++++++++------- Test/AssemblyInfo.cs | 1 + Test/Spy/Implementations.cs | 29 ++++++++++ 10 files changed, 130 insertions(+), 126 deletions(-) delete mode 100644 Spy/Attributes.cs create mode 100644 Test/Spy/Implementations.cs diff --git a/Main/Configuration/Attributes.cs b/Main/Configuration/Attributes.cs index 81737a1e..0f9eb6fe 100644 --- a/Main/Configuration/Attributes.cs +++ b/Main/Configuration/Attributes.cs @@ -17,13 +17,13 @@ public FilterSpyAggregationAttribute(params Type[] types) {} [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class SpyConstructorChoiceAggregationAttribute : Attribute { - public SpyConstructorChoiceAggregationAttribute(params Enum[] references) {} + public SpyConstructorChoiceAggregationAttribute(params Type[] references) {} } [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class FilterSpyConstructorChoiceAggregationAttribute : Attribute { - public FilterSpyConstructorChoiceAggregationAttribute(params Enum[] references) {} + public FilterSpyConstructorChoiceAggregationAttribute(params Type[] references) {} } [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] diff --git a/Main/Configuration/TypesFromAttributes.cs b/Main/Configuration/TypesFromAttributes.cs index 3449dfff..77792aa4 100644 --- a/Main/Configuration/TypesFromAttributes.cs +++ b/Main/Configuration/TypesFromAttributes.cs @@ -128,7 +128,7 @@ internal ScopeTypesFromAttributes( .Select(ad => { if (ad.ConstructorArguments.Length < 2) - return null; + return ((INamedTypeSymbol, IList)?) null; var implementationType = ad.ConstructorArguments[0].Value as INamedTypeSymbol; var parameterTypes = ad .ConstructorArguments[1] @@ -137,32 +137,71 @@ internal ScopeTypesFromAttributes( .OfType() .ToList(); - if (implementationType is { }) + return implementationType is {} + ? (implementationType, parameterTypes) + : null; + }) + .Concat(GetTypesFromAttribute(wellKnownTypes.SpyConstructorChoiceAggregationAttribute) + .Select(t => { - var constructorChoice = implementationType - .Constructors - .Where(c => c.Parameters.Length == parameterTypes.Count) - .SingleOrDefault(c => c.Parameters.Select(p => p.Type) - .Zip(parameterTypes, - (pLeft, pRight) => pLeft.Equals(pRight, SymbolEqualityComparer.Default)) - .All(b => b)); - return constructorChoice is { } - ? (implementationType, constructorChoice) - : ((INamedTypeSymbol, IMethodSymbol)?)null; - } + var members = t + .GetMembers() + .OfType() + .OrderBy(m => m.Name) + .Select(m => m.ReturnType) + .OfType() + .ToImmutableArray(); + if (members.Length < 1) + return ((INamedTypeSymbol, IList)?) null; + + return (members[0], members.Skip(1).ToList()); + })) + .Select(t => + { + if (t is null) return null; + + var implementationType = t.Value.Item1; + var parameterTypes = t.Value.Item2; + + if (implementationType is null) return null; + + var constructorChoice = implementationType + .Constructors + .Where(c => c.Parameters.Length == parameterTypes.Count) + .SingleOrDefault(c => c.Parameters.Select(p => p.Type) + .Zip(parameterTypes, + (pLeft, pRight) => pLeft.Equals(pRight, SymbolEqualityComparer.Default)) + .All(b => b)); + return constructorChoice is { } + ? (implementationType, constructorChoice) + : ((INamedTypeSymbol, IMethodSymbol)?)null; - return null; }) .OfType<(INamedTypeSymbol, IMethodSymbol)>() .ToList(); FilterConstructorChoices = (AttributeDictionary.TryGetValue(wellKnownTypes.FilterConstructorChoiceAttribute, out var group2) ? group2 : Enumerable.Empty()) + .Concat(GetTypesFromAttribute(wellKnownTypes.FilterSpyConstructorChoiceAggregationAttribute) + .Select(t => t.GetAttributes().FirstOrDefault(ad => ad.AttributeClass?.Name == nameof(ConstructorChoiceAttribute))) + .OfType()) .Select(ad => { - if (ad.ConstructorArguments.Length != 1) + if (ad.ConstructorArguments.Length < 1) return null; return ad.ConstructorArguments[0].Value as INamedTypeSymbol; }) + .Concat(GetTypesFromAttribute(wellKnownTypes.FilterSpyConstructorChoiceAggregationAttribute) + .Select(t => + { + var members = t + .GetMembers() + .OfType() + .OrderBy(m => m.Name) + .Select(m => m.ReturnType) + .OfType() + .ToImmutableArray(); + return members.Length < 1 ? null : members[0]; + })) .OfType() .ToList(); diff --git a/Main/WellKnownTypes.cs b/Main/WellKnownTypes.cs index 3c7b1bed..7b3c80fd 100644 --- a/Main/WellKnownTypes.cs +++ b/Main/WellKnownTypes.cs @@ -52,8 +52,6 @@ internal record WellKnownTypes( INamedTypeSymbol ConcurrentBagOfAsyncDisposable, INamedTypeSymbol ConcurrentDictionaryOfSyncDisposable, INamedTypeSymbol ConcurrentDictionaryOfAsyncDisposable, - INamedTypeSymbol Action, - INamedTypeSymbol Func, INamedTypeSymbol Exception, INamedTypeSymbol TaskCanceledException, INamedTypeSymbol SemaphoreSlim) @@ -85,8 +83,6 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK var concurrentDictionary2OfAsyncDisposable = iAsyncDisposable is null ? null : concurrentDictionary2?.Construct(iAsyncDisposable, iAsyncDisposable); - var action = compilation.GetTypeOrReport("System.Action"); - var func = compilation.GetTypeOrReport("System.Func`3"); var exception = compilation.GetTypeOrReport("System.Exception"); var taskCanceledException = compilation.GetTypeOrReport("System.Threading.Tasks.TaskCanceledException"); var semaphoreSlim = compilation.GetTypeOrReport("System.Threading.SemaphoreSlim"); @@ -243,8 +239,6 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK && concurrentBagOfAsyncDisposable is not null && concurrentDictionary2OfSyncDisposable is not null && concurrentDictionary2OfAsyncDisposable is not null - && action is not null - && func is not null && exception is not null && semaphoreSlim is not null) { @@ -299,8 +293,6 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK ConcurrentBagOfAsyncDisposable: concurrentBagOfAsyncDisposable, ConcurrentDictionaryOfSyncDisposable: concurrentDictionary2OfSyncDisposable, ConcurrentDictionaryOfAsyncDisposable: concurrentDictionary2OfAsyncDisposable, - Action: action, - Func: func, Exception: exception, TaskCanceledException: taskCanceledException, SemaphoreSlim: semaphoreSlim); diff --git a/Sample/Context.cs b/Sample/Context.cs index 992f8b44..766e67f4 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -1,48 +1,16 @@ using System; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration; -using MrMeeseeks.DIE.Sample; +using MrMeeseeks.DIE.SampleChild; +using SampleChild; -namespace MrMeeseeks.DIE.Test.Disposal.Async.InTransientScopeInTransientScope; +namespace MrMeeseeks.DIE.Test.Spy.Implementations; -internal class Dependency : IAsyncDisposable -{ - public bool IsDisposed { get; private set; } - - public async ValueTask DisposeAsync() - { - await Task.Delay(500).ConfigureAwait(false); - IsDisposed = true; - } -} - -internal class TransientScopeRootInner : ITransientScopeRoot -{ - public TransientScopeRootInner(Dependency dependency) => Dependency = dependency; - - internal Dependency Dependency { get; } -} - -internal class TransientScopeRoot : ITransientScopeRoot -{ - public TransientScopeRootInner TransientScopeRootInner { get; } - public Dependency Dependency { get; } - private readonly IAsyncDisposable _disposable; - - internal TransientScopeRoot( - TransientScopeRootInner transientScopeRootInner, - Dependency dependency, - IAsyncDisposable disposable) - { - TransientScopeRootInner = transientScopeRootInner; - Dependency = dependency; - _disposable = disposable; - } - - internal ValueTask Cleanup() => _disposable.DisposeAsync(); -} - -[CreateFunction(typeof(TransientScopeRoot), "Create")] +[SpyAggregation(typeof(IPublicTypeReport))] +[SpyConstructorChoiceAggregation( + typeof(PublicConstructorReport.global__MrMeeseeks_DIE_SampleChild_Class._), + typeof(PublicConstructorReport.global__MrMeeseeks_DIE_SampleChild_ClassToo.Int32))] +[CreateFunction(typeof(Class), "CreateClass")] +[CreateFunction(typeof(Func), "CreateClassToo")] internal partial class Container { diff --git a/Sample/Program.cs b/Sample/Program.cs index 37092818..497ea562 100644 --- a/Sample/Program.cs +++ b/Sample/Program.cs @@ -6,31 +6,4 @@ private static void Main() { Console.WriteLine("Hello, world!"); } - - private class NopDisposable : global::System.IDisposable - { - internal static global::System.IDisposable Instance { get; } = new NopDisposable(); - public void Dispose() - { - } - } - - private class NopAsyncDisposable : global::System.IAsyncDisposable - { - internal static global::System.IAsyncDisposable Instance { get; } = new NopAsyncDisposable(); - public global::System.Threading.Tasks.ValueTask DisposeAsync() => global::System.Threading.Tasks.ValueTask.CompletedTask; - } - - private class SyncToAsyncDisposable : global::System.IAsyncDisposable - { - private readonly IDisposable _disposable; - - internal SyncToAsyncDisposable(IDisposable disposable) => _disposable = disposable; - - public global::System.Threading.Tasks.ValueTask DisposeAsync() - { - _disposable.Dispose(); - return global::System.Threading.Tasks.ValueTask.CompletedTask; - } - } } \ No newline at end of file diff --git a/Sample/Sample.csproj b/Sample/Sample.csproj index b70bf202..e8ef5c6e 100644 --- a/Sample/Sample.csproj +++ b/Sample/Sample.csproj @@ -2,7 +2,7 @@ Exe - net5.0 + net6.0 MrMeeseeks.DIE.Sample true @@ -22,6 +22,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/Spy/Attributes.cs b/Spy/Attributes.cs deleted file mode 100644 index 9fe0afa8..00000000 --- a/Spy/Attributes.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; - -namespace MrMeeseeks.DIE.Spy; - -[AttributeUsage(AttributeTargets.Field | AttributeTargets.Assembly | AttributeTargets.Class)] -public class ConstructorChoiceAttribute : Attribute -{ - public ConstructorChoiceAttribute(Type implementationType, params Type[] parameterTypes) - { - } -} diff --git a/Spy/TypeReportGenerator.cs b/Spy/TypeReportGenerator.cs index a2d62327..73acf3d8 100644 --- a/Spy/TypeReportGenerator.cs +++ b/Spy/TypeReportGenerator.cs @@ -1,5 +1,4 @@ using System; -using System.Runtime.Serialization; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Text; @@ -68,28 +67,41 @@ static StringBuilder GenerateBody(Accessibility accessModifier, IList i.Constructors) - .Where(c => c.DeclaredAccessibility == accessModifier) - .Select(c => (c, $"{c.ContainingType.Name}{(c.Parameters.Any() ? $"_{string.Join("_", c.Parameters.Select(p => p.Type.Name))}" : "")}")) - .GroupBy(t => t.Item2) - .SelectMany(g => !g.Any() - ? Array.Empty<(IMethodSymbol, string)>() - : g.Count() == 1 - ? new (IMethodSymbol, string)[] { (g.First().c, g.Key) } - : g.Select((t, i) => (t.c, $"{t.Item2}_{i}"))) - .Select(t => @$" -[global::{typeof(EnumMemberAttribute).FullName}({nameof(EnumMemberAttribute.Value)} = ""{t.c.ToDisplayString()}"")] -[global::{typeof(ConstructorChoiceAttribute).FullName}(typeof({t.c.ContainingType.FullName()}){(t.c.Parameters.Any() ? $", {string.Join(", ", t.c.Parameters.Select(p => $"typeof({p.Type.FullName()})"))}" : "")})] -{t.Item2},") - .Aggregate( - generatedContainer, - (current, line) => current.AppendLine(line)); + + foreach (var implementation in allNonStaticImplementations + .Where(i => i.Constructors.Any(c => c.DeclaredAccessibility == accessModifier))) + { + generatedContainer = generatedContainer + .AppendLine($"{lowerCaseAccessModifier} static class {implementation.FullName().Replace(':','_').Replace('.', '_')}") + .AppendLine("{"); + + foreach (var constructor in implementation.Constructors + .Where(c => c.DeclaredAccessibility == accessModifier)) + { + int j = 0; + generatedContainer = generatedContainer + .AppendLine( + $"{lowerCaseAccessModifier} interface {(constructor.Parameters.Any() ? "" : "_")}{string.Join("_", constructor.Parameters.Select(p => p.Type.Name))}") + .AppendLine($"{{") + .AppendLine($"{implementation.FullName()} _{(j++).ToString().PadLeft(20, '0')}();"); + + foreach (var constructorParameter in constructor.Parameters) + { + generatedContainer = generatedContainer + .AppendLine($"{constructorParameter.Type.FullName()} _{(j++).ToString().PadLeft(20, '0')}();"); + } + + generatedContainer = generatedContainer + .AppendLine($"}}"); + } + + generatedContainer = generatedContainer + .AppendLine("}"); + } - generatedContainer = generatedContainer + generatedContainer = generatedContainer .AppendLine("}"); return generatedContainer; diff --git a/Test/AssemblyInfo.cs b/Test/AssemblyInfo.cs index dbd40887..25e97b5b 100644 --- a/Test/AssemblyInfo.cs +++ b/Test/AssemblyInfo.cs @@ -1,5 +1,6 @@ using MrMeeseeks.DIE.Configuration; using MrMeeseeks.DIE.Test; +using TestChild; [assembly:ContainerInstanceAggregation(typeof(IContainerInstance))] [assembly:TransientScopeInstanceAggregation(typeof(ITransientScopeInstance))] diff --git a/Test/Spy/Implementations.cs b/Test/Spy/Implementations.cs new file mode 100644 index 00000000..8734772e --- /dev/null +++ b/Test/Spy/Implementations.cs @@ -0,0 +1,29 @@ +using System; +using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.TestChild; +using TestChild; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Spy.Implementations; + +[SpyAggregation(typeof(IPublicTypeReport))] +[SpyConstructorChoiceAggregation( + typeof(PublicConstructorReport.global__MrMeeseeks_DIE_TestChild_Class._), + typeof(PublicConstructorReport.global__MrMeeseeks_DIE_TestChild_ClassToo.Int32))] +[CreateFunction(typeof(Class), "CreateClass")] +[CreateFunction(typeof(Func), "CreateClassToo")] +internal partial class Container +{ + +} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var _ = container.CreateClass(); + var __ = container.CreateClassToo()(69); + } +} \ No newline at end of file From c073be2ab5d0140886b68bf38232b52645671324 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Mon, 18 Apr 2022 15:34:54 +0200 Subject: [PATCH 064/162] Simple nullability support --- Main/CodeBuilding/RangeCodeBaseBuilder.cs | 6 ++ .../Function/FunctionResolutionBuilder.cs | 63 ++++++++++--------- Main/ResolutionTreeItem.cs | 4 ++ Main/RoslynExtensions.cs | 3 +- Sample/Context.cs | 29 +++++---- .../NonOptional/MultipleImplementations.cs | 33 ++++++++++ .../NonOptional/NoImplementation.cs | 29 +++++++++ .../Optional/MultipleImplementations.cs | 33 ++++++++++ Test/Nullability/Optional/NoImplementation.cs | 29 +++++++++ 9 files changed, 187 insertions(+), 42 deletions(-) create mode 100644 Test/Nullability/NonOptional/MultipleImplementations.cs create mode 100644 Test/Nullability/NonOptional/NoImplementation.cs create mode 100644 Test/Nullability/Optional/MultipleImplementations.cs create mode 100644 Test/Nullability/Optional/NoImplementation.cs diff --git a/Main/CodeBuilding/RangeCodeBaseBuilder.cs b/Main/CodeBuilding/RangeCodeBaseBuilder.cs index dc5a752b..00b154a5 100644 --- a/Main/CodeBuilding/RangeCodeBaseBuilder.cs +++ b/Main/CodeBuilding/RangeCodeBaseBuilder.cs @@ -270,6 +270,9 @@ private static StringBuilder GenerateFields( stringBuilder = stringBuilder.AppendLine($"{scopeTypeFullName} {scopeReference};"); stringBuilder = GenerateFields(stringBuilder, functionCallResolution); break; + case NullResolution(var reference, var typeFullName): + stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); + break; case TransientScopeAsDisposableResolution(var reference, var typeFullName): stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); break; @@ -530,6 +533,9 @@ private StringBuilder GenerateResolutions( break; case ParameterResolution: break; // parameter exists already + case NullResolution(var reference, var typeFullName): + stringBuilder = stringBuilder.AppendLine($"{reference} = ({typeFullName}) null;"); + break; case FieldResolution(var reference, _, var fieldName): stringBuilder = stringBuilder.AppendLine($"{reference} = this.{fieldName};"); break; diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs index f266591c..3fddbec2 100644 --- a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs @@ -451,7 +451,9 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup var interfaceType = (INamedTypeSymbol) typeSymbol; var implementations = _checkTypeProperties .MapToImplementations(typeSymbol); - var shouldBeScopeRoot = implementations.Max(i => _checkTypeProperties.ShouldBeScopeRoot(i)); + var shouldBeScopeRoot = implementations.Any() + ? implementations.Max(i => _checkTypeProperties.ShouldBeScopeRoot(i)) + : ScopeLevel.None; var nextParameter = new SwitchInterfaceAfterScopeRootParameter( interfaceType, @@ -508,17 +510,18 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup currentParameters, composition)); } - if (implementations.SingleOrDefault() is not { } implementationType) + if (implementations.FirstOrDefault() is not { } implementationType || implementations.Count > 1) { - return ( - new ErrorTreeItem(implementations.Count switch - { - 0 => $"[{interfaceType.FullName()}] Interface: No implementation found", - > 1 => $"[{interfaceType.FullName()}] Interface: more than one implementation found", - _ => - $"[{interfaceType.FullName()}] Interface: Found single implementation {implementations[0].FullName()} is not a named type symbol" - }), - null); + return interfaceType.NullableAnnotation == NullableAnnotation.Annotated + ? (new NullResolution(RootReferenceGenerator.Generate(interfaceType), interfaceType.FullName()), null) // todo warning + : (new ErrorTreeItem(implementations.Count switch + { + 0 => $"[{interfaceType.FullName()}] Interface: No implementation found", + > 1 => $"[{interfaceType.FullName()}] Interface: more than one implementation found", + _ => + $"[{interfaceType.FullName()}] Interface: Found single implementation {implementations[0].FullName()} is not a named type symbol" + }), + null); } return CreateInterface(new CreateInterfaceParameter( @@ -616,17 +619,18 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup var (typeSymbol, currentParameters) = parameter; var implementations = _checkTypeProperties .MapToImplementations(typeSymbol); - var implementationType = implementations.SingleOrDefault(); - if (implementationType is not { }) + var implementationType = implementations.FirstOrDefault(); + if (implementationType is not { } || implementations.Count > 1) { - return ( - new ErrorTreeItem(implementations.Count switch - { - 0 => $"[{typeSymbol.FullName()}] Class: No implementation found", - > 1 => $"[{typeSymbol.FullName()}] Class: more than one implementation found", - _ => $"[{typeSymbol.FullName()}] Class: Found single implementation{implementations[0].FullName()} is not a named type symbol" - }), - null); + return typeSymbol.NullableAnnotation == NullableAnnotation.Annotated + ? (new NullResolution(RootReferenceGenerator.Generate(typeSymbol), typeSymbol.FullName()), null) // todo warning + : (new ErrorTreeItem(implementations.Count switch + { + 0 => $"[{typeSymbol.FullName()}] Class: No implementation found", + > 1 => $"[{typeSymbol.FullName()}] Class: more than one implementation found", + _ => $"[{typeSymbol.FullName()}] Class: Found single implementation{implementations[0].FullName()} is not a named type symbol" + }), + null); } var nextParameter = new SwitchImplementationParameter( @@ -715,14 +719,15 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup if (_checkTypeProperties.GetConstructorChoiceFor(implementationType) is not { } constructor) { - return ( - new ErrorTreeItem(implementationType.Constructors.Length switch - { - 0 => $"[{implementationType.FullName()}] Class.Constructor: No constructor found for implementation {implementationType.FullName()}", - > 1 => $"[{implementationType.FullName()}] Class.Constructor: More than one constructor found for implementation {implementationType.FullName()}", - _ => $"[{implementationType.FullName()}] Class.Constructor: {implementationType.Constructors[0].Name} is not a method symbol" - }), - null); + return implementationType.NullableAnnotation == NullableAnnotation.Annotated + ? (new NullResolution(RootReferenceGenerator.Generate(implementationType), implementationType.FullName()), null) // todo warning + : (new ErrorTreeItem(implementationType.Constructors.Length switch + { + 0 => $"[{implementationType.FullName()}] Class.Constructor: No constructor found for implementation {implementationType.FullName()}", + > 1 => $"[{implementationType.FullName()}] Class.Constructor: More than one constructor found for implementation {implementationType.FullName()}", + _ => $"[{implementationType.FullName()}] Class.Constructor: {implementationType.Constructors[0].Name} is not a method symbol" + }), + null); } var checkForDecoration = false; diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index 514c237c..1ff2d2a4 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -272,6 +272,10 @@ internal record DisposalHandling( string DisposedPropertyReference, string DisposableLocalReference); +internal record NullResolution( + string Reference, + string TypeFullName) : Resolvable(Reference, TypeFullName); + internal record FieldResolution( string Reference, string TypeFullName, diff --git a/Main/RoslynExtensions.cs b/Main/RoslynExtensions.cs index 0dd3acd9..5c71d4c4 100644 --- a/Main/RoslynExtensions.cs +++ b/Main/RoslynExtensions.cs @@ -46,7 +46,8 @@ public static string FullName(this ITypeSymbol type) => typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces, genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters, parameterOptions: SymbolDisplayParameterOptions.IncludeType | SymbolDisplayParameterOptions.IncludeParamsRefOut, - memberOptions: SymbolDisplayMemberOptions.IncludeRef)); + memberOptions: SymbolDisplayMemberOptions.IncludeRef, + miscellaneousOptions: SymbolDisplayMiscellaneousOptions.IncludeNullableReferenceTypeModifier)); // Picked from https://github.com/YairHalberstadt/stronginject Thank you! internal static string FullName(this INamespaceSymbol @namespace) => diff --git a/Sample/Context.cs b/Sample/Context.cs index 766e67f4..8a750ad1 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -1,17 +1,22 @@ -using System; -using MrMeeseeks.DIE.Configuration; -using MrMeeseeks.DIE.SampleChild; -using SampleChild; +using MrMeeseeks.DIE.Configuration; -namespace MrMeeseeks.DIE.Test.Spy.Implementations; +namespace MrMeeseeks.DIE.Test.Nullability.MultipleConstructors; -[SpyAggregation(typeof(IPublicTypeReport))] -[SpyConstructorChoiceAggregation( - typeof(PublicConstructorReport.global__MrMeeseeks_DIE_SampleChild_Class._), - typeof(PublicConstructorReport.global__MrMeeseeks_DIE_SampleChild_ClassToo.Int32))] -[CreateFunction(typeof(Class), "CreateClass")] -[CreateFunction(typeof(Func), "CreateClassToo")] +internal class Dependency +{ + internal Dependency() {} + internal Dependency(int _) {} +} + +internal class Wrapper +{ + public Dependency? Dependency { get; } + + internal Wrapper(Dependency? dependency) => Dependency = dependency; +} + +[CreateFunction(typeof(Wrapper), "Create")] internal partial class Container { - + private int DIE_Counter() => 69; } diff --git a/Test/Nullability/NonOptional/MultipleImplementations.cs b/Test/Nullability/NonOptional/MultipleImplementations.cs new file mode 100644 index 00000000..b243eba2 --- /dev/null +++ b/Test/Nullability/NonOptional/MultipleImplementations.cs @@ -0,0 +1,33 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Nullability.NonOptional.MultipleImplementations; + +internal interface IDependency{} + +internal class Dependency0 : IDependency {} + +internal class Dependency1 : IDependency {} + +internal class Wrapper +{ + public IDependency? Dependency { get; } + + internal Wrapper(IDependency? dependency) => Dependency = dependency; +} + +[CreateFunction(typeof(Wrapper), "Create")] +internal partial class Container +{ +} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var dependency = container.Create().Dependency; + Assert.Null(dependency); + } +} \ No newline at end of file diff --git a/Test/Nullability/NonOptional/NoImplementation.cs b/Test/Nullability/NonOptional/NoImplementation.cs new file mode 100644 index 00000000..54ac5931 --- /dev/null +++ b/Test/Nullability/NonOptional/NoImplementation.cs @@ -0,0 +1,29 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Nullability.NonOptional.NoImplementation; + +internal interface IDependency{} + +internal class Wrapper +{ + public IDependency? Dependency { get; } + + internal Wrapper(IDependency? dependency) => Dependency = dependency; +} + +[CreateFunction(typeof(Wrapper), "Create")] +internal partial class Container +{ +} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var dependency = container.Create().Dependency; + Assert.Null(dependency); + } +} \ No newline at end of file diff --git a/Test/Nullability/Optional/MultipleImplementations.cs b/Test/Nullability/Optional/MultipleImplementations.cs new file mode 100644 index 00000000..4e933972 --- /dev/null +++ b/Test/Nullability/Optional/MultipleImplementations.cs @@ -0,0 +1,33 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Nullability.Optional.MultipleImplementations; + +internal interface IDependency{} + +internal class Dependency0 : IDependency {} + +internal class Dependency1 : IDependency {} + +internal class Wrapper +{ + public IDependency? Dependency { get; } + + internal Wrapper(IDependency? dependency = null) => Dependency = dependency; +} + +[CreateFunction(typeof(Wrapper), "Create")] +internal partial class Container +{ +} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var dependency = container.Create().Dependency; + Assert.Null(dependency); + } +} \ No newline at end of file diff --git a/Test/Nullability/Optional/NoImplementation.cs b/Test/Nullability/Optional/NoImplementation.cs new file mode 100644 index 00000000..b461709d --- /dev/null +++ b/Test/Nullability/Optional/NoImplementation.cs @@ -0,0 +1,29 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Nullability.Optional.NoImplementation; + +internal interface IDependency{} + +internal class Wrapper +{ + public IDependency? Dependency { get; } + + internal Wrapper(IDependency? dependency = null) => Dependency = dependency; +} + +[CreateFunction(typeof(Wrapper), "Create")] +internal partial class Container +{ +} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var dependency = container.Create().Dependency; + Assert.Null(dependency); + } +} \ No newline at end of file From 9ad6c99d092d56127ab75e6f423248d76881763b Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Mon, 18 Apr 2022 20:00:52 +0200 Subject: [PATCH 065/162] Refactoring some tests --- Main/UserProvidedScopeElements.cs | 2 +- Test/ConstructorChoice/Parameterless.cs | 24 +++ Test/ConstructorChoice/WithParameter.cs | 25 +++ Test/ConstructorChoiceTests.cs | 25 --- Test/ConstructorTests.cs | 35 ---- Test/CustomEmbedding/FactoryInContainercs.cs | 29 +++ Test/CustomEmbedding/FactoryInScope.cs | 32 ++++ .../FactoryInTransientScope.cs | 32 ++++ .../FactoryWithParameterInContainercs.cs | 24 +++ .../FactoryWithParameterInScope.cs | 33 ++++ .../FactoryWithParameterInTransientScope.cs | 33 ++++ Test/CustomEmbedding/FieldInContainercs.cs | 29 +++ Test/CustomEmbedding/FieldInScope.cs | 32 ++++ Test/CustomEmbedding/FieldInTransientScope.cs | 32 ++++ Test/CustomEmbedding/PropertyInContainercs.cs | 29 +++ Test/CustomEmbedding/PropertyInScope.cs | 32 ++++ .../PropertyInTransientScope.cs | 32 ++++ Test/FactoryTests.cs | 76 -------- .../ExternalType.cs} | 12 +- Test/InitProperty/Vanilla.cs | 29 +++ Test/InstanceTests.cs | 38 ---- Test/PropertyTests.cs | 40 ----- Test/TypeInitializer/AsyncTask.cs | 32 ++++ Test/TypeInitializer/AsyncValueTask.cs | 32 ++++ .../Sync.cs} | 8 +- Test/ValueTuple/NonSyntaxVariant.cs | 41 +++++ Test/ValueTuple/NonSyntaxVariantSingleItem.cs | 35 ++++ Test/ValueTuple/SyntaxVariant.cs | 42 +++++ Test/ValueTuple/ValueTupleTests.cs | 35 ++++ Test/ValueTupleTests.cs | 170 ------------------ 30 files changed, 675 insertions(+), 395 deletions(-) create mode 100644 Test/ConstructorChoice/Parameterless.cs create mode 100644 Test/ConstructorChoice/WithParameter.cs delete mode 100644 Test/ConstructorChoiceTests.cs delete mode 100644 Test/ConstructorTests.cs create mode 100644 Test/CustomEmbedding/FactoryInContainercs.cs create mode 100644 Test/CustomEmbedding/FactoryInScope.cs create mode 100644 Test/CustomEmbedding/FactoryInTransientScope.cs create mode 100644 Test/CustomEmbedding/FactoryWithParameterInContainercs.cs create mode 100644 Test/CustomEmbedding/FactoryWithParameterInScope.cs create mode 100644 Test/CustomEmbedding/FactoryWithParameterInTransientScope.cs create mode 100644 Test/CustomEmbedding/FieldInContainercs.cs create mode 100644 Test/CustomEmbedding/FieldInScope.cs create mode 100644 Test/CustomEmbedding/FieldInTransientScope.cs create mode 100644 Test/CustomEmbedding/PropertyInContainercs.cs create mode 100644 Test/CustomEmbedding/PropertyInScope.cs create mode 100644 Test/CustomEmbedding/PropertyInTransientScope.cs delete mode 100644 Test/FactoryTests.cs rename Test/{ImplementationAggregationTests.cs => ImplementationAggregation/ExternalType.cs} (57%) create mode 100644 Test/InitProperty/Vanilla.cs delete mode 100644 Test/InstanceTests.cs delete mode 100644 Test/PropertyTests.cs create mode 100644 Test/TypeInitializer/AsyncTask.cs create mode 100644 Test/TypeInitializer/AsyncValueTask.cs rename Test/{SyncTypeInitializationTest.cs => TypeInitializer/Sync.cs} (69%) create mode 100644 Test/ValueTuple/NonSyntaxVariant.cs create mode 100644 Test/ValueTuple/NonSyntaxVariantSingleItem.cs create mode 100644 Test/ValueTuple/SyntaxVariant.cs create mode 100644 Test/ValueTuple/ValueTupleTests.cs delete mode 100644 Test/ValueTupleTests.cs diff --git a/Main/UserProvidedScopeElements.cs b/Main/UserProvidedScopeElements.cs index cc908004..1f9bddff 100644 --- a/Main/UserProvidedScopeElements.cs +++ b/Main/UserProvidedScopeElements.cs @@ -27,7 +27,7 @@ public UserProvidedScopeElements(INamedTypeSymbol scopeType) .ToList(); _typeToField = dieMembers - .Where(s => s is IFieldSymbol fieldSymbol && (fieldSymbol.IsConst || fieldSymbol.IsReadOnly)) + .Where(s => s is IFieldSymbol) .OfType() .ToDictionary(fs => fs.Type, fs => fs, SymbolEqualityComparer.IncludeNullability); diff --git a/Test/ConstructorChoice/Parameterless.cs b/Test/ConstructorChoice/Parameterless.cs new file mode 100644 index 00000000..4d749367 --- /dev/null +++ b/Test/ConstructorChoice/Parameterless.cs @@ -0,0 +1,24 @@ +using System; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.ConstructorChoice.Parameterless; + +[ImplementationAggregation(typeof(DateTime))] +[ConstructorChoice(typeof(DateTime))] +[CreateFunction(typeof(DateTime), "Create")] +internal partial class Container +{ + +} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var dateTime = container.Create(); + Assert.Equal(DateTime.MinValue, dateTime); + } +} \ No newline at end of file diff --git a/Test/ConstructorChoice/WithParameter.cs b/Test/ConstructorChoice/WithParameter.cs new file mode 100644 index 00000000..d2678992 --- /dev/null +++ b/Test/ConstructorChoice/WithParameter.cs @@ -0,0 +1,25 @@ +using System; +using System.IO; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.ConstructorChoice.WithParameter; + +[ImplementationAggregation(typeof(FileInfo))] +[ConstructorChoice(typeof(FileInfo), typeof(string))] +[CreateFunction(typeof(Func), "Create")] +internal partial class Container +{ + +} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var fileInfo = container.Create()("C:\\Yeah.txt"); + Assert.Equal("C:\\Yeah.txt", fileInfo.FullName); + } +} \ No newline at end of file diff --git a/Test/ConstructorChoiceTests.cs b/Test/ConstructorChoiceTests.cs deleted file mode 100644 index 6b00ede0..00000000 --- a/Test/ConstructorChoiceTests.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using MrMeeseeks.DIE.Configuration; -using Xunit; - -[assembly:ImplementationAggregation(typeof(DateTime))] -[assembly:ConstructorChoice(typeof(DateTime))] - -namespace MrMeeseeks.DIE.Test; - -[CreateFunction(typeof(DateTime), "Create")] -internal partial class ConstructorChoiceContainer -{ - -} - -public class ImplementationAggregationTests -{ - [Fact] - public void ResolveExternalType() - { - var container = new ConstructorChoiceContainer(); - var dateTime = container.Create(); - Assert.Equal(DateTime.MinValue, dateTime); - } -} \ No newline at end of file diff --git a/Test/ConstructorTests.cs b/Test/ConstructorTests.cs deleted file mode 100644 index 2f75158d..00000000 --- a/Test/ConstructorTests.cs +++ /dev/null @@ -1,35 +0,0 @@ -using MrMeeseeks.DIE.Configuration; -using Xunit; - -namespace MrMeeseeks.DIE.Test; - -internal interface IConstructorInitDependency {} - -internal class ConstructorInitDependency : IConstructorInitDependency {} - -internal interface IConstructorInit -{ - IConstructorInitDependency? Dependency { get; } -} - -internal class ConstructorInit : IConstructorInit -{ - public IConstructorInitDependency? Dependency { get; init; } -} - -[CreateFunction(typeof(IConstructorInit), "Create")] -internal partial class ConstructorInitContainer -{ -} - -public class ConstructorsTests -{ - [Fact] - public void ResolveInitProperty() - { - var container = new ConstructorInitContainer(); - var resolution = container.Create(); - Assert.NotNull(resolution.Dependency); - Assert.IsType(resolution.Dependency); - } -} \ No newline at end of file diff --git a/Test/CustomEmbedding/FactoryInContainercs.cs b/Test/CustomEmbedding/FactoryInContainercs.cs new file mode 100644 index 00000000..dfaf82a1 --- /dev/null +++ b/Test/CustomEmbedding/FactoryInContainercs.cs @@ -0,0 +1,29 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CustomEmbedding.FactoryInContainer; + +internal class Wrapper +{ + public string Property { get; } + + internal Wrapper(string property) => Property = property; +} + +[CreateFunction(typeof(Wrapper), "Create")] +internal partial class Container +{ + private string DIE_Factory() => "Yeah"; +} + +public class Tests +{ + + [Fact] + public void Test() + { + var container = new Container(); + var wrapper = container.Create(); + Assert.Equal("Yeah", wrapper.Property); + } +} \ No newline at end of file diff --git a/Test/CustomEmbedding/FactoryInScope.cs b/Test/CustomEmbedding/FactoryInScope.cs new file mode 100644 index 00000000..a41e0f71 --- /dev/null +++ b/Test/CustomEmbedding/FactoryInScope.cs @@ -0,0 +1,32 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CustomEmbedding.FactoryInScope; + +internal class ScopeRoot : IScopeRoot +{ + public string Property { get; } + + internal ScopeRoot(string property) => Property = property; +} + +[CreateFunction(typeof(ScopeRoot), "Create")] +internal partial class Container +{ + partial class DIE_DefaultScope + { + private string DIE_Factory() => "Yeah"; + } +} + +public class Tests +{ + + [Fact] + public void Test() + { + var container = new Container(); + var scopeRoot = container.Create(); + Assert.Equal("Yeah", scopeRoot.Property); + } +} \ No newline at end of file diff --git a/Test/CustomEmbedding/FactoryInTransientScope.cs b/Test/CustomEmbedding/FactoryInTransientScope.cs new file mode 100644 index 00000000..dc7ae25a --- /dev/null +++ b/Test/CustomEmbedding/FactoryInTransientScope.cs @@ -0,0 +1,32 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CustomEmbedding.FactoryInTransientScope; + +internal class TransientScopeRoot : ITransientScopeRoot +{ + public string Property { get; } + + internal TransientScopeRoot(string property) => Property = property; +} + +[CreateFunction(typeof(TransientScopeRoot), "Create")] +internal partial class Container +{ + partial class DIE_DefaultTransientScope + { + private string DIE_Factory() => "Yeah"; + } +} + +public class Tests +{ + + [Fact] + public void Test() + { + var container = new Container(); + var transientScopeRoot = container.Create(); + Assert.Equal("Yeah", transientScopeRoot.Property); + } +} \ No newline at end of file diff --git a/Test/CustomEmbedding/FactoryWithParameterInContainercs.cs b/Test/CustomEmbedding/FactoryWithParameterInContainercs.cs new file mode 100644 index 00000000..864a00d4 --- /dev/null +++ b/Test/CustomEmbedding/FactoryWithParameterInContainercs.cs @@ -0,0 +1,24 @@ +using System.IO; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CustomEmbedding.FactoryWithParameterInContainer; + +[ImplementationAggregation(typeof(FileInfo))] +[CreateFunction(typeof(FileInfo), "Create")] +internal partial class Container +{ + private string DIE_Path => "C:\\Yeah.txt"; + private FileInfo DIE_Factory(string path) => new (path); +} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var fileInfo = container.Create(); + Assert.Equal("C:\\Yeah.txt", fileInfo.FullName); + } +} \ No newline at end of file diff --git a/Test/CustomEmbedding/FactoryWithParameterInScope.cs b/Test/CustomEmbedding/FactoryWithParameterInScope.cs new file mode 100644 index 00000000..70af6a09 --- /dev/null +++ b/Test/CustomEmbedding/FactoryWithParameterInScope.cs @@ -0,0 +1,33 @@ +using System.IO; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CustomEmbedding.FactoryWithParameterInScope; + +internal class ScopeRoot : IScopeRoot +{ + public FileInfo Property { get; } + + internal ScopeRoot(FileInfo property) => Property = property; +} + +[CreateFunction(typeof(ScopeRoot), "Create")] +internal partial class Container +{ + partial class DIE_DefaultScope + { + private string DIE_Path => "C:\\Yeah.txt"; + private FileInfo DIE_Factory(string path) => new (path); + } +} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var scopeRoot = container.Create(); + Assert.Equal("C:\\Yeah.txt", scopeRoot.Property.FullName); + } +} \ No newline at end of file diff --git a/Test/CustomEmbedding/FactoryWithParameterInTransientScope.cs b/Test/CustomEmbedding/FactoryWithParameterInTransientScope.cs new file mode 100644 index 00000000..4149b466 --- /dev/null +++ b/Test/CustomEmbedding/FactoryWithParameterInTransientScope.cs @@ -0,0 +1,33 @@ +using System.IO; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CustomEmbedding.FactoryWithParameterInTransientScope; + +internal class TransientScopeRoot : ITransientScopeRoot +{ + public FileInfo Property { get; } + + internal TransientScopeRoot(FileInfo property) => Property = property; +} + +[CreateFunction(typeof(TransientScopeRoot), "Create")] +internal partial class Container +{ + partial class DIE_DefaultTransientScope + { + private string DIE_Path => "C:\\Yeah.txt"; + private FileInfo DIE_Factory(string path) => new (path); + } +} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var transientScopeRoot = container.Create(); + Assert.Equal("C:\\Yeah.txt", transientScopeRoot.Property.FullName); + } +} \ No newline at end of file diff --git a/Test/CustomEmbedding/FieldInContainercs.cs b/Test/CustomEmbedding/FieldInContainercs.cs new file mode 100644 index 00000000..11ef1332 --- /dev/null +++ b/Test/CustomEmbedding/FieldInContainercs.cs @@ -0,0 +1,29 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CustomEmbedding.FieldInContainer; + +internal class Wrapper +{ + public string Property { get; } + + internal Wrapper(string property) => Property = property; +} + +[CreateFunction(typeof(Wrapper), "Create")] +internal partial class Container +{ + private readonly string DIE_Yeah = "Yeah"; +} + +public class Tests +{ + + [Fact] + public void Test() + { + var container = new Container(); + var wrapper = container.Create(); + Assert.Equal("Yeah", wrapper.Property); + } +} \ No newline at end of file diff --git a/Test/CustomEmbedding/FieldInScope.cs b/Test/CustomEmbedding/FieldInScope.cs new file mode 100644 index 00000000..1115e884 --- /dev/null +++ b/Test/CustomEmbedding/FieldInScope.cs @@ -0,0 +1,32 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CustomEmbedding.FieldInScope; + +internal class ScopeRoot : IScopeRoot +{ + public string Property { get; } + + internal ScopeRoot(string property) => Property = property; +} + +[CreateFunction(typeof(ScopeRoot), "Create")] +internal partial class Container +{ + partial class DIE_DefaultScope + { + private readonly string DIE_Yeah = "Yeah"; + } +} + +public class Tests +{ + + [Fact] + public void Test() + { + var container = new Container(); + var scopeRoot = container.Create(); + Assert.Equal("Yeah", scopeRoot.Property); + } +} \ No newline at end of file diff --git a/Test/CustomEmbedding/FieldInTransientScope.cs b/Test/CustomEmbedding/FieldInTransientScope.cs new file mode 100644 index 00000000..6f1ef794 --- /dev/null +++ b/Test/CustomEmbedding/FieldInTransientScope.cs @@ -0,0 +1,32 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CustomEmbedding.FieldInTransientScope; + +internal class TransientScopeRoot : ITransientScopeRoot +{ + public string Property { get; } + + internal TransientScopeRoot(string property) => Property = property; +} + +[CreateFunction(typeof(TransientScopeRoot), "Create")] +internal partial class Container +{ + partial class DIE_DefaultTransientScope + { + private readonly string DIE_Yeah = "Yeah"; + } +} + +public class Tests +{ + + [Fact] + public void Test() + { + var container = new Container(); + var transientScopeRoot = container.Create(); + Assert.Equal("Yeah", transientScopeRoot.Property); + } +} \ No newline at end of file diff --git a/Test/CustomEmbedding/PropertyInContainercs.cs b/Test/CustomEmbedding/PropertyInContainercs.cs new file mode 100644 index 00000000..864f1a16 --- /dev/null +++ b/Test/CustomEmbedding/PropertyInContainercs.cs @@ -0,0 +1,29 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CustomEmbedding.PropertyInContainer; + +internal class Wrapper +{ + public string Property { get; } + + internal Wrapper(string property) => Property = property; +} + +[CreateFunction(typeof(Wrapper), "Create")] +internal partial class Container +{ + private string DIE_Yeah => "Yeah"; +} + +public class Tests +{ + + [Fact] + public void Test() + { + var container = new Container(); + var wrapper = container.Create(); + Assert.Equal("Yeah", wrapper.Property); + } +} \ No newline at end of file diff --git a/Test/CustomEmbedding/PropertyInScope.cs b/Test/CustomEmbedding/PropertyInScope.cs new file mode 100644 index 00000000..1a7af579 --- /dev/null +++ b/Test/CustomEmbedding/PropertyInScope.cs @@ -0,0 +1,32 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CustomEmbedding.PropertyInScope; + +internal class ScopeRoot : IScopeRoot +{ + public string Property { get; } + + internal ScopeRoot(string property) => Property = property; +} + +[CreateFunction(typeof(ScopeRoot), "Create")] +internal partial class Container +{ + partial class DIE_DefaultScope + { + private string DIE_Yeah => "Yeah"; + } +} + +public class Tests +{ + + [Fact] + public void Test() + { + var container = new Container(); + var scopeRoot = container.Create(); + Assert.Equal("Yeah", scopeRoot.Property); + } +} \ No newline at end of file diff --git a/Test/CustomEmbedding/PropertyInTransientScope.cs b/Test/CustomEmbedding/PropertyInTransientScope.cs new file mode 100644 index 00000000..8929e70c --- /dev/null +++ b/Test/CustomEmbedding/PropertyInTransientScope.cs @@ -0,0 +1,32 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CustomEmbedding.PropertyInTransientScope; + +internal class TransientScopeRoot : ITransientScopeRoot +{ + public string Property { get; } + + internal TransientScopeRoot(string property) => Property = property; +} + +[CreateFunction(typeof(TransientScopeRoot), "Create")] +internal partial class Container +{ + partial class DIE_DefaultTransientScope + { + private string DIE_Yeah => "Yeah"; + } +} + +public class Tests +{ + + [Fact] + public void Test() + { + var container = new Container(); + var transientScopeRoot = container.Create(); + Assert.Equal("Yeah", transientScopeRoot.Property); + } +} \ No newline at end of file diff --git a/Test/FactoryTests.cs b/Test/FactoryTests.cs deleted file mode 100644 index 35e91b35..00000000 --- a/Test/FactoryTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -using System.IO; -using MrMeeseeks.DIE.Configuration; -using Xunit; - -namespace MrMeeseeks.DIE.Test; - -internal class FactoryContainerTransientScope : ITransientScopeRoot -{ - public int Number { get; } - - internal FactoryContainerTransientScope(int number) - { - Number = number; - } -} -internal class FactoryContainerScope : IScopeRoot -{ - public string Yeah { get; } - - internal FactoryContainerScope(string yeah) - { - Yeah = yeah; - } -} - -[CreateFunction(typeof(FileInfo), "CreateFileInfo")] -[CreateFunction(typeof(FactoryContainerTransientScope), "CreateFactoryContainerTransientScope")] -[CreateFunction(typeof(FactoryContainerScope), "CreateFactoryContainerScope")] -internal partial class FactoryContainer -{ - private string DIE_Path { get; } - - private FileInfo DIE_FileInfo(string path) => new (path); - - public FactoryContainer(string diePath) => DIE_Path = diePath; - - partial class DIE_DefaultTransientScope - { - private int DIE_Num => 69; - } - - partial class DIE_DefaultScope - { - private string DIE_Yeah => "Yeah"; - } -} - -public partial class FactoryTests -{ - [Fact] - public void ResolveExternalType() - { - var check = @"C:\HelloWorld.txt"; - var container = new FactoryContainer(check); - var fileInfo = container.CreateFileInfo(); - Assert.Equal(check, fileInfo.FullName); - } - - [Fact] - public void ResolveFromFactoryInTransientScope() - { - var check = @"C:\HelloWorld.txt"; - var container = new FactoryContainer(check); - var transientScope = container.CreateFactoryContainerTransientScope(); - Assert.Equal(69, transientScope.Number); - } - - [Fact] - public void ResolveFromFactoryInScope() - { - var check = @"C:\HelloWorld.txt"; - var container = new FactoryContainer(check); - var scope = container.CreateFactoryContainerScope(); - Assert.Equal("Yeah", scope.Yeah); - } -} \ No newline at end of file diff --git a/Test/ImplementationAggregationTests.cs b/Test/ImplementationAggregation/ExternalType.cs similarity index 57% rename from Test/ImplementationAggregationTests.cs rename to Test/ImplementationAggregation/ExternalType.cs index 6d11295b..ace9fd37 100644 --- a/Test/ImplementationAggregationTests.cs +++ b/Test/ImplementationAggregation/ExternalType.cs @@ -3,22 +3,22 @@ using MrMeeseeks.DIE.Configuration; using Xunit; -[assembly:ImplementationAggregation(typeof(FileInfo))] +namespace MrMeeseeks.DIE.Test.ImplementationAggregation.ExternalType; -namespace MrMeeseeks.DIE.Test; +[ImplementationAggregation(typeof(FileInfo))] [CreateFunction(typeof(Func), "Create")] -internal partial class ImplementationAggregationContainer +internal partial class Container { } -public partial class ConstructorChoiceTests +public class Tests { [Fact] - public void ResolveExternalType() + public void Test() { - var container = new ImplementationAggregationContainer(); + var container = new Container(); var path = @"C:\HelloWorld.txt"; var fileInfo = container.Create()(path); Assert.NotNull(fileInfo); diff --git a/Test/InitProperty/Vanilla.cs b/Test/InitProperty/Vanilla.cs new file mode 100644 index 00000000..79caff84 --- /dev/null +++ b/Test/InitProperty/Vanilla.cs @@ -0,0 +1,29 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.InitProperty.Vanilla; + +internal class Dependency {} + +internal class Wrapper +{ + public Dependency? Dependency { get; init; } +} + +[CreateFunction(typeof(Wrapper), "Create")] +internal partial class Container +{ +} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var hasInitProperty = container.Create(); + Assert.NotNull(hasInitProperty); + Assert.NotNull(hasInitProperty.Dependency); + Assert.IsType(hasInitProperty.Dependency); + } +} \ No newline at end of file diff --git a/Test/InstanceTests.cs b/Test/InstanceTests.cs deleted file mode 100644 index 4fa8a103..00000000 --- a/Test/InstanceTests.cs +++ /dev/null @@ -1,38 +0,0 @@ -using MrMeeseeks.DIE.Configuration; -using Xunit; - -namespace MrMeeseeks.DIE.Test; - -internal interface IInstanceClass -{ - string Dependency { get; } -} - -internal class InstanceClass : IInstanceClass -{ - public string Dependency { get; } - - public InstanceClass(string dependency) - { - Dependency = dependency; - } -} -[CreateFunction(typeof(IInstanceClass), "Create")] -internal partial class InstanceContainer -{ - private readonly string DIE_Dependency; - - public InstanceContainer(string dieDependency) => DIE_Dependency = dieDependency; -} - -public partial class InstanceTests -{ - [Fact] - public void ResolveExternalType() - { - var check = "Hello, instance!"; - var container = new InstanceContainer(check); - var instanceClass = container.Create(); - Assert.Equal(check, instanceClass.Dependency); - } -} \ No newline at end of file diff --git a/Test/PropertyTests.cs b/Test/PropertyTests.cs deleted file mode 100644 index d598e1d5..00000000 --- a/Test/PropertyTests.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System.Collections.Generic; -using MrMeeseeks.DIE.Configuration; -using Xunit; - -namespace MrMeeseeks.DIE.Test; - -internal interface IPropertyClass -{ - string Dependency { get; } -} - -internal class PropertyClass : IPropertyClass -{ - public string Dependency { get; } - - public PropertyClass(string dependency) - { - Dependency = dependency; - } -} - -[CreateFunction(typeof(IPropertyClass), "Create")] -internal partial class PropertyContainer -{ - private string DIE_Dependency { get; } - - public PropertyContainer(string dieDependency) => DIE_Dependency = dieDependency; -} - -public partial class PropertyTests -{ - [Fact] - public void ResolveExternalType() - { - var check = "Hello, Property!"; - var container = new PropertyContainer(check); - var propertyClass = container.Create(); - Assert.Equal(check, propertyClass.Dependency); - } -} \ No newline at end of file diff --git a/Test/TypeInitializer/AsyncTask.cs b/Test/TypeInitializer/AsyncTask.cs new file mode 100644 index 00000000..41b4bf1f --- /dev/null +++ b/Test/TypeInitializer/AsyncTask.cs @@ -0,0 +1,32 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.TypeInitializer.AsyncTask; + +internal class Dependency : ITaskTypeInitializer +{ + public bool IsInitialized { get; private set; } + + Task ITaskTypeInitializer.InitializeAsync() + { + IsInitialized = true; + return Task.CompletedTask; + } +} + +[CreateFunction(typeof(Dependency), "Create")] +internal partial class Container +{ +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + var container = new Container(); + var instance = await container.CreateAsync().ConfigureAwait(false); + Assert.True(instance.IsInitialized); + } +} \ No newline at end of file diff --git a/Test/TypeInitializer/AsyncValueTask.cs b/Test/TypeInitializer/AsyncValueTask.cs new file mode 100644 index 00000000..7d355aa5 --- /dev/null +++ b/Test/TypeInitializer/AsyncValueTask.cs @@ -0,0 +1,32 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.TypeInitializer.AsyncValueTask; + +internal class Dependency : IValueTaskTypeInitializer +{ + public bool IsInitialized { get; private set; } + + ValueTask IValueTaskTypeInitializer.InitializeAsync() + { + IsInitialized = true; + return ValueTask.CompletedTask; + } +} + +[CreateFunction(typeof(Dependency), "Create")] +internal partial class Container +{ +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + var container = new Container(); + var instance = await container.CreateValueAsync().ConfigureAwait(false); + Assert.True(instance.IsInitialized); + } +} \ No newline at end of file diff --git a/Test/SyncTypeInitializationTest.cs b/Test/TypeInitializer/Sync.cs similarity index 69% rename from Test/SyncTypeInitializationTest.cs rename to Test/TypeInitializer/Sync.cs index f3eb8c5d..396b275d 100644 --- a/Test/SyncTypeInitializationTest.cs +++ b/Test/TypeInitializer/Sync.cs @@ -1,7 +1,7 @@ using MrMeeseeks.DIE.Configuration; using Xunit; -namespace MrMeeseeks.DIE.Test.SyncTypeInitializationTest; +namespace MrMeeseeks.DIE.Test.TypeInitializer.Sync; internal class Dependency : ITypeInitializer { @@ -10,18 +10,18 @@ internal class Dependency : ITypeInitializer void ITypeInitializer.Initialize() => IsInitialized = true; } -[CreateFunction(typeof(Dependency), "Create0")] +[CreateFunction(typeof(Dependency), "Create")] internal partial class Container { } -public partial class Tests +public class Tests { [Fact] public void Test() { var container = new Container(); - var instance = container.Create0(); + var instance = container.Create(); Assert.True(instance.IsInitialized); } } \ No newline at end of file diff --git a/Test/ValueTuple/NonSyntaxVariant.cs b/Test/ValueTuple/NonSyntaxVariant.cs new file mode 100644 index 00000000..6e782a7a --- /dev/null +++ b/Test/ValueTuple/NonSyntaxVariant.cs @@ -0,0 +1,41 @@ +using System; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.ValueTuple.NonSyntaxVariant; + +internal class Wrapper +{ + public Wrapper( + ValueTuple>>> + dependency) => + Dependency = dependency; + + public ValueTuple>>> + Dependency { get; } +} + +[CreateFunction(typeof(Wrapper), "Create")] +internal partial class Container +{ + private int _i; + + private int DIE_Counter() => _i++; +} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var nonSyntaxValueTupleBase = container.Create(); + Assert.Equal(25, nonSyntaxValueTupleBase.Dependency.Item26); + } +} \ No newline at end of file diff --git a/Test/ValueTuple/NonSyntaxVariantSingleItem.cs b/Test/ValueTuple/NonSyntaxVariantSingleItem.cs new file mode 100644 index 00000000..3589babb --- /dev/null +++ b/Test/ValueTuple/NonSyntaxVariantSingleItem.cs @@ -0,0 +1,35 @@ +using System; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.ValueTuple.NonSyntaxVariantSingleItem; + +internal class Wrapper +{ + public Wrapper( + ValueTuple + dependency) => + Dependency = dependency; + + public ValueTuple + Dependency { get; } +} + +[CreateFunction(typeof(Wrapper), "Create")] +internal partial class Container +{ + private int _i; + + private int DIE_Counter() => _i++; +} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var wrapper = container.Create(); + Assert.Equal(0, wrapper.Dependency.Item1); + } +} \ No newline at end of file diff --git a/Test/ValueTuple/SyntaxVariant.cs b/Test/ValueTuple/SyntaxVariant.cs new file mode 100644 index 00000000..b9deaef2 --- /dev/null +++ b/Test/ValueTuple/SyntaxVariant.cs @@ -0,0 +1,42 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.ValueTuple.SyntaxVariant; + +internal class Wrapper +{ + public Wrapper( + (int _0, int _1, int _2, int _3, int _4, + int _5, int _6, int _7, int _8, int _9, + int _10, int _11, int _12, int _13, int _14, + int _15, int _16, int _17, int _18, int _19, + int _20, int _21, int _22, int _23, int _24, + int _25) dependency) => + Dependency = dependency; + + public (int _0, int _1, int _2, int _3, int _4, + int _5, int _6, int _7, int _8, int _9, + int _10, int _11, int _12, int _13, int _14, + int _15, int _16, int _17, int _18, int _19, + int _20, int _21, int _22, int _23, int _24, + int _25) Dependency { get; } +} + +[CreateFunction(typeof(Wrapper), "Create")] +internal partial class Container +{ + private int _i; + + private int DIE_Counter() => _i++; +} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var valueTupleBase = container.Create(); + Assert.Equal(25, valueTupleBase.Dependency._25); + } +} \ No newline at end of file diff --git a/Test/ValueTuple/ValueTupleTests.cs b/Test/ValueTuple/ValueTupleTests.cs new file mode 100644 index 00000000..fb0acf1d --- /dev/null +++ b/Test/ValueTuple/ValueTupleTests.cs @@ -0,0 +1,35 @@ +using System; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.ValueTuple.NonSyntaxVariantDoubleItem; + +internal class Wrapper +{ + public Wrapper( + ValueTuple + dependency) => + Dependency = dependency; + + public ValueTuple + Dependency { get; } +} + +[CreateFunction(typeof(Wrapper), "Create")] +internal partial class Container +{ + private int _i; + + private int DIE_Counter() => _i++; +} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var wrapper = container.Create(); + Assert.Equal(1, wrapper.Dependency.Item2); + } +} \ No newline at end of file diff --git a/Test/ValueTupleTests.cs b/Test/ValueTupleTests.cs deleted file mode 100644 index 8a740ab1..00000000 --- a/Test/ValueTupleTests.cs +++ /dev/null @@ -1,170 +0,0 @@ -using System; -using MrMeeseeks.DIE.Configuration; -using Xunit; - -namespace MrMeeseeks.DIE.Test; - -internal interface IValueTupleBase -{ - (int _0, int _1, int _2, int _3, int _4, - int _5, int _6, int _7, int _8, int _9, - int _10, int _11, int _12, int _13, int _14, - int _15, int _16, int _17, int _18, int _19, - int _20, int _21, int _22, int _23, int _24, - int _25) Dependency { get; } -} - -internal class ValueTupleBase : IValueTupleBase -{ - public ValueTupleBase( - (int _0, int _1, int _2, int _3, int _4, - int _5, int _6, int _7, int _8, int _9, - int _10, int _11, int _12, int _13, int _14, - int _15, int _16, int _17, int _18, int _19, - int _20, int _21, int _22, int _23, int _24, - int _25) dependency) => - Dependency = dependency; - - public (int _0, int _1, int _2, int _3, int _4, - int _5, int _6, int _7, int _8, int _9, - int _10, int _11, int _12, int _13, int _14, - int _15, int _16, int _17, int _18, int _19, - int _20, int _21, int _22, int _23, int _24, - int _25) Dependency { get; } -} - -[CreateFunction(typeof(IValueTupleBase), "CreateDep")] -internal partial class ValueTupleContainer -{ - private int _i; - - private int DIE_Counter() => _i++; -} - -public partial class ValueTupleTests -{ - [Fact] - public void ResolveValueTuple() - { - var container = new ValueTupleContainer(); - var valueTupleBase = container.CreateDep(); - Assert.Equal(25, valueTupleBase.Dependency._25); - } -} - -internal interface INonSyntaxValueTupleBase -{ - ValueTuple>>> - Dependency { get; } -} - -internal class NonSyntaxValueTupleBase : INonSyntaxValueTupleBase -{ - public NonSyntaxValueTupleBase( - ValueTuple>>> - dependency) => - Dependency = dependency; - - public ValueTuple>>> - Dependency { get; } -} - -[CreateFunction(typeof(INonSyntaxValueTupleBase), "CreateDep")] -internal partial class NonSyntaxValueTupleContainer -{ - private int _i; - - private int DIE_Counter() => _i++; -} - -public partial class ValueTupleTests -{ - [Fact] - public void ResolveNonSyntaxValueTuple() - { - var container = new NonSyntaxValueTupleContainer(); - var nonSyntaxValueTupleBase = container.CreateDep(); - Assert.Equal(25, nonSyntaxValueTupleBase.Dependency.Item26); - } -} - -internal interface INonSyntaxSingleItemValueTupleBase -{ - ValueTuple - Dependency { get; } -} - -internal class NonSyntaxSingleItemValueTupleBase : INonSyntaxSingleItemValueTupleBase -{ - public NonSyntaxSingleItemValueTupleBase( - ValueTuple - dependency) => - Dependency = dependency; - - public ValueTuple - Dependency { get; } -} - -[CreateFunction(typeof(INonSyntaxSingleItemValueTupleBase), "CreateDep")] -internal partial class NonSyntaxSingleItemValueTupleContainer -{ - private int _i; - - private int DIE_Counter() => _i++; -} - -public partial class ValueTupleTests -{ - [Fact] - public void ResolveNonSyntaxSingleItemValueTuple() - { - var container = new NonSyntaxSingleItemValueTupleContainer(); - var NonSyntaxSingleItemValueTupleBase = container.CreateDep(); - Assert.Equal(0, NonSyntaxSingleItemValueTupleBase.Dependency.Item1); - } -} - -internal interface INonSyntaxDoubleItemValueTupleBase -{ - ValueTuple - Dependency { get; } -} - -internal class NonSyntaxDoubleItemValueTupleBase : INonSyntaxDoubleItemValueTupleBase -{ - public NonSyntaxDoubleItemValueTupleBase( - ValueTuple - dependency) => - Dependency = dependency; - - public ValueTuple - Dependency { get; } -} - -[CreateFunction(typeof(INonSyntaxDoubleItemValueTupleBase), "CreateDep")] -internal partial class NonSyntaxDoubleItemValueTupleContainer -{ - private int _i; - - private int DIE_Counter() => _i++; -} - -public partial class ValueTupleTests -{ - [Fact] - public void ResolveNonSyntaxDoubleItemValueTuple() - { - var container = new NonSyntaxDoubleItemValueTupleContainer(); - var NonSyntaxDoubleItemValueTupleBase = container.CreateDep(); - Assert.Equal(1, NonSyntaxDoubleItemValueTupleBase.Dependency.Item2); - } -} \ No newline at end of file From 10754e506c01f5af9761211b2824b08577e1b820 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Mon, 25 Apr 2022 22:15:40 +0200 Subject: [PATCH 066/162] =?UTF-8?q?Initial=20generics=20support=20implemen?= =?UTF-8?q?tation.=20To=20be=20continued=20=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Main/Configuration/Attributes.cs | 24 +++++++ Main/Configuration/CheckTypeProperties.cs | 72 +++++++++++++++++-- .../Configuration/CurrentlyConsideredTypes.cs | 38 ++++------ Main/Extensions/INamedTypeSymbolExtensions.cs | 24 +++++++ Main/Properties/launchSettings.json | 6 +- .../Function/FunctionResolutionBuilder.cs | 7 +- Main/ResolutionBuilding/ResolutionDtos.cs | 2 +- Main/WellKnownTypes.cs | 24 +++++++ Sample/Context.cs | 28 +++----- Test/Generics/Implementation/Double.cs | 20 ++++++ Test/Generics/Implementation/Single.cs | 20 ++++++ Test/Generics/Interface/Double.cs | 22 ++++++ Test/Generics/Interface/DoubleAndOneFixed.cs | 22 ++++++ Test/Generics/Interface/DoubleAndSetToSame.cs | 22 ++++++ Test/Generics/Interface/DoubleSwitched.cs | 22 ++++++ Test/Generics/Interface/Single.cs | 22 ++++++ ...eAndBaseImplementationDoubleButOneFixed.cs | 24 +++++++ 17 files changed, 346 insertions(+), 53 deletions(-) create mode 100644 Main/Extensions/INamedTypeSymbolExtensions.cs create mode 100644 Test/Generics/Implementation/Double.cs create mode 100644 Test/Generics/Implementation/Single.cs create mode 100644 Test/Generics/Interface/Double.cs create mode 100644 Test/Generics/Interface/DoubleAndOneFixed.cs create mode 100644 Test/Generics/Interface/DoubleAndSetToSame.cs create mode 100644 Test/Generics/Interface/DoubleSwitched.cs create mode 100644 Test/Generics/Interface/Single.cs create mode 100644 Test/Generics/Interface/SingleAndBaseImplementationDoubleButOneFixed.cs diff --git a/Main/Configuration/Attributes.cs b/Main/Configuration/Attributes.cs index 0f9eb6fe..388b5787 100644 --- a/Main/Configuration/Attributes.cs +++ b/Main/Configuration/Attributes.cs @@ -158,6 +158,30 @@ public class FilterCompositeAggregationAttribute : Attribute public FilterCompositeAggregationAttribute(params Type[] types) {} } +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] +public class GenericParameterSubstituteAggregationAttribute : Attribute +{ + public GenericParameterSubstituteAggregationAttribute(Type unboundGenericType, string genericArgumentName, params Type[] types) {} +} + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class FilterGenericParameterSubstituteAggregationAttribute : Attribute +{ + public FilterGenericParameterSubstituteAggregationAttribute(Type unboundGenericType, string genericArgumentName, params Type[] types) {} +} + +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] +public class GenericParameterSubstituteChoiceAttribute : Attribute +{ + public GenericParameterSubstituteChoiceAttribute(Type unboundGenericType, string genericArgumentName, Type chosenType) {} +} + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class FilterGenericParameterSubstituteChoiceAttribute : Attribute +{ + public FilterGenericParameterSubstituteChoiceAttribute(Type unboundGenericType, string genericArgumentName) {} +} + [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class DecoratorSequenceChoiceAttribute : Attribute { diff --git a/Main/Configuration/CheckTypeProperties.cs b/Main/Configuration/CheckTypeProperties.cs index 54b93c3b..38ea4b2f 100644 --- a/Main/Configuration/CheckTypeProperties.cs +++ b/Main/Configuration/CheckTypeProperties.cs @@ -1,3 +1,5 @@ +using MrMeeseeks.DIE.Extensions; + namespace MrMeeseeks.DIE.Configuration; internal enum ScopeLevel @@ -27,7 +29,7 @@ internal interface ICheckTypeProperties bool ShouldBeDecorated(INamedTypeSymbol interfaceType); IReadOnlyList GetSequenceFor(INamedTypeSymbol interfaceType, INamedTypeSymbol implementationType); - IReadOnlyList MapToImplementations(ITypeSymbol typeSymbol); + IReadOnlyList MapToImplementations(INamedTypeSymbol typeSymbol); (INamedTypeSymbol Type, IMethodSymbol Initializer)? GetInitializerFor(INamedTypeSymbol implementationType); } @@ -101,10 +103,70 @@ public IReadOnlyList GetSequenceFor(INamedTypeSymbol interface throw new Exception("Couldn't find unambiguous sequence of decorators"); } - public IReadOnlyList MapToImplementations(ITypeSymbol typeSymbol) => - _currentlyConsideredTypes.ImplementationMap.TryGetValue(typeSymbol, out var implementations) - ? implementations - : new List(); + public IReadOnlyList MapToImplementations(INamedTypeSymbol typeSymbol) => + _currentlyConsideredTypes.ImplementationMap.TryGetValue(typeSymbol.UnboundIfGeneric(), out var implementations) + ? GetClosedImplementations(typeSymbol, implementations) + : Array.Empty(); + + private IReadOnlyList GetClosedImplementations( + INamedTypeSymbol targetType, + IReadOnlyList rawImplementations) + { + var targetClosedGenericParameters = targetType + .TypeArguments + .OfType() + .ToImmutableArray(); + var unboundTargetType = targetType.UnboundIfGeneric(); + var isTargetGeneric = targetType.IsGenericType; + if (isTargetGeneric && targetType.TypeArguments.Any(tp => tp is not INamedTypeSymbol)) + throw new Exception("Target type at this point should only have closed generic parameters"); + + var ret = new List(); + foreach (var implementation in rawImplementations) + { + if (!implementation.IsGenericType) + { + ret.Add(implementation); + continue; + } + + if (implementation.AllDerivedTypes() + .FirstOrDefault(t => + SymbolEqualityComparer.Default.Equals(t.UnboundIfGeneric(), unboundTargetType)) is { } implementationsTarget) + { + var newTypeArguments = implementation.TypeArguments + .Select(ta => ta switch + { + INamedTypeSymbol nts => nts, + ITypeParameterSymbol tps => + implementationsTarget + .TypeArguments + .IndexOf(tps, SymbolEqualityComparer.Default) is int index + && index >= 0 + ? targetClosedGenericParameters[index] + : throw new Exception("huh?"), + _ => ta + }) + .OfType() + .OfType() + .ToArray(); + + + if (newTypeArguments.Length == implementation.TypeArguments.Length) + { + var closedImplementation = implementation.Construct(newTypeArguments); + if (closedImplementation + .AllDerivedTypes() + .Any(t => SymbolEqualityComparer.Default.Equals(targetType, t))) + { + ret.Add(closedImplementation); + } + } + } + } + + return ret; + } public (INamedTypeSymbol Type, IMethodSymbol Initializer)? GetInitializerFor(INamedTypeSymbol implementationType) => _currentlyConsideredTypes.ImplementationToInitializer.TryGetValue(implementationType, out var tuple) diff --git a/Main/Configuration/CurrentlyConsideredTypes.cs b/Main/Configuration/CurrentlyConsideredTypes.cs index 547b301e..4a3d6004 100644 --- a/Main/Configuration/CurrentlyConsideredTypes.cs +++ b/Main/Configuration/CurrentlyConsideredTypes.cs @@ -1,4 +1,5 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; +using MrMeeseeks.DIE.Extensions; namespace MrMeeseeks.DIE.Configuration; @@ -16,7 +17,7 @@ internal interface ICurrentlyConsideredTypes IReadOnlyDictionary> InterfaceToDecorators { get; } IReadOnlyDictionary> InterfaceSequenceChoices { get; } IReadOnlyDictionary> ImplementationSequenceChoices { get; } - IReadOnlyDictionary> ImplementationMap { get; } + IReadOnlyDictionary> ImplementationMap { get; } IReadOnlyDictionary ImplementationToInitializer { get; } } @@ -36,7 +37,8 @@ public CurrentlyConsideredTypes( .Where(e => e is ClassDeclarationSyntax or StructDeclarationSyntax or RecordDeclarationSyntax) .Select(c => t.Item2.GetDeclaredSymbol(c)) .Where(c => c is not null) - .OfType())); + .OfType() + .Where(nts => !nts.IsAbstract))); foreach (var types in typesFromAttributes) { @@ -49,7 +51,8 @@ public CurrentlyConsideredTypes( .OfType() .Where(ms => !ms.ReturnsVoid) .Select(ms => ms.ReturnType) - .OfType()); + .OfType() + .Where(nts => !nts.IsAbstract)); allImplementations.AddRange(types.Implementation .Concat(spiedImplementations)); @@ -139,10 +142,10 @@ public CurrentlyConsideredTypes( ImplementationMap = allImplementations .Where(t => !decoratorTypes.Contains(t.OriginalDefinition)) .Where(t => !compositeTypes.Contains(t.OriginalDefinition)) - .SelectMany(i => { return i.AllInterfaces.OfType().Select(ii => (ii, i)).Prepend((i, i)); }) - .GroupBy(t => t.Item1, t => t.Item2) + .SelectMany(i => { return i.AllInterfaces.OfType().Select(ii => (ii, i)).Prepend((i, i)); }) + .GroupBy(t => t.Item1.UnboundIfGeneric(), t => t.Item2) .ToDictionary(g => g.Key, g => (IReadOnlyList) g.Distinct(SymbolEqualityComparer.Default).OfType().ToList()); - + var initializers = new Dictionary(SymbolEqualityComparer.Default); foreach (var types in typesFromAttributes) @@ -153,7 +156,7 @@ public CurrentlyConsideredTypes( .ToImmutableHashSet(SymbolEqualityComparer.Default); foreach (var filterConcreteType in allImplementations - .Where(i => AllDerivedTypes(i) + .Where(i => i.AllDerivedTypes() .Select(t => t.OriginalDefinition) .Any(inter => filterInterfaceTypes.Contains(inter)))) initializers.Remove(filterConcreteType); @@ -176,7 +179,7 @@ public CurrentlyConsideredTypes( { foreach (var (interfaceType, initializer) in interfaceTypes) { - if (AllDerivedTypes(i).Select(d => d.OriginalDefinition).Contains(interfaceType, SymbolEqualityComparer.Default)) + if (i.AllDerivedTypes().Select(d => d.OriginalDefinition).Contains(interfaceType, SymbolEqualityComparer.Default)) { return ((INamedTypeSymbol, INamedTypeSymbol, IMethodSymbol)?) (i, interfaceType, initializer); } @@ -211,7 +214,7 @@ public CurrentlyConsideredTypes( ret = ret.Union(allImplementations .Where(i => { - var derivedTypes = AllDerivedTypes(i).Select(t => t.OriginalDefinition).ToList(); + var derivedTypes = i.AllDerivedTypes().Select(t => t.OriginalDefinition).ToList(); return propertyGivingTypes.Any(t => derivedTypes.Contains(t.OriginalDefinition, SymbolEqualityComparer.Default)); }) @@ -221,21 +224,6 @@ public CurrentlyConsideredTypes( return ret; } - - IEnumerable AllDerivedTypes(INamedTypeSymbol type) - { - var concreteTypes = new List(); - var temp = type; - while (temp is {}) - { - concreteTypes.Add(temp); - temp = temp.BaseType; - } - return type - .AllInterfaces - .Append(type) - .Concat(concreteTypes); - } } public IImmutableSet SyncTransientTypes { get; } @@ -250,6 +238,6 @@ IEnumerable AllDerivedTypes(INamedTypeSymbol type) public IReadOnlyDictionary> InterfaceToDecorators { get; } public IReadOnlyDictionary> InterfaceSequenceChoices { get; } public IReadOnlyDictionary> ImplementationSequenceChoices { get; } - public IReadOnlyDictionary> ImplementationMap { get; } + public IReadOnlyDictionary> ImplementationMap { get; } public IReadOnlyDictionary ImplementationToInitializer { get; } } \ No newline at end of file diff --git a/Main/Extensions/INamedTypeSymbolExtensions.cs b/Main/Extensions/INamedTypeSymbolExtensions.cs new file mode 100644 index 00000000..3341b498 --- /dev/null +++ b/Main/Extensions/INamedTypeSymbolExtensions.cs @@ -0,0 +1,24 @@ +namespace MrMeeseeks.DIE.Extensions; + +internal static class INamedTypeSymbolExtensions +{ + internal static IEnumerable AllDerivedTypes(this INamedTypeSymbol type) + { + var concreteTypes = new List(); + var temp = type; + while (temp is {}) + { + concreteTypes.Add(temp); + temp = temp.BaseType; + } + return type + .AllInterfaces + .Append(type) + .Concat(concreteTypes); + } + + internal static INamedTypeSymbol UnboundIfGeneric(this INamedTypeSymbol type) => + type.IsGenericType && !type.IsUnboundGenericType + ? type.ConstructUnboundGenericType() + : type; +} \ No newline at end of file diff --git a/Main/Properties/launchSettings.json b/Main/Properties/launchSettings.json index 048ecac2..360d8b8a 100644 --- a/Main/Properties/launchSettings.json +++ b/Main/Properties/launchSettings.json @@ -1,8 +1,12 @@ { "profiles": { - "Main": { + "Main_Sample": { "commandName": "DebugRoslynComponent", "targetProject": "..\\Sample\\Sample.csproj" + }, + "Main_Test": { + "commandName": "DebugRoslynComponent", + "targetProject": "..\\Test\\Test.csproj" } } } \ No newline at end of file diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs index 3fddbec2..7b83ea3f 100644 --- a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs @@ -335,8 +335,9 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup if (type.TypeKind == TypeKind.Interface) return SwitchInterface(new SwitchInterfaceParameter(type, currentFuncParameters)); - if (type.TypeKind is TypeKind.Class or TypeKind.Struct) - return SwitchClass(new SwitchClassParameter(type, currentFuncParameters)); + if (type.TypeKind is TypeKind.Class or TypeKind.Struct + && type is INamedTypeSymbol classOrStructType) + return SwitchClass(new SwitchClassParameter(classOrStructType, currentFuncParameters)); return ( new ErrorTreeItem($"[{type.FullName()}] Couldn't process in resolution tree creation."), @@ -450,7 +451,7 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup var (typeSymbol, currentParameters) = parameter; var interfaceType = (INamedTypeSymbol) typeSymbol; var implementations = _checkTypeProperties - .MapToImplementations(typeSymbol); + .MapToImplementations(interfaceType); var shouldBeScopeRoot = implementations.Any() ? implementations.Max(i => _checkTypeProperties.ShouldBeScopeRoot(i)) : ScopeLevel.None; diff --git a/Main/ResolutionBuilding/ResolutionDtos.cs b/Main/ResolutionBuilding/ResolutionDtos.cs index 49d0ed42..da44632e 100644 --- a/Main/ResolutionBuilding/ResolutionDtos.cs +++ b/Main/ResolutionBuilding/ResolutionDtos.cs @@ -99,7 +99,7 @@ internal record CreateInterfaceParameterAsComposition( } internal record SwitchClassParameter( - ITypeSymbol TypeSymbol, + INamedTypeSymbol TypeSymbol, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters); internal record SwitchImplementationParameter( diff --git a/Main/WellKnownTypes.cs b/Main/WellKnownTypes.cs index 7b3c80fd..4048b1c3 100644 --- a/Main/WellKnownTypes.cs +++ b/Main/WellKnownTypes.cs @@ -16,6 +16,8 @@ internal record WellKnownTypes( INamedTypeSymbol ScopeRootAggregationAttribute, INamedTypeSymbol DecoratorAggregationAttribute, INamedTypeSymbol CompositeAggregationAttribute, + INamedTypeSymbol GenericParameterSubstituteAggregationAttribute, + INamedTypeSymbol GenericParameterSubstituteChoiceAttribute, INamedTypeSymbol DecoratorSequenceChoiceAttribute, INamedTypeSymbol ConstructorChoiceAttribute, INamedTypeSymbol TypeInitializerAttribute, @@ -32,6 +34,8 @@ internal record WellKnownTypes( INamedTypeSymbol FilterScopeRootAggregationAttribute, INamedTypeSymbol FilterDecoratorAggregationAttribute, INamedTypeSymbol FilterCompositeAggregationAttribute, + INamedTypeSymbol FilterGenericParameterSubstituteAggregationAttribute, + INamedTypeSymbol FilterGenericParameterSubstituteChoiceAttribute, INamedTypeSymbol FilterDecoratorSequenceChoiceAttribute, INamedTypeSymbol FilterConstructorChoiceAttribute, INamedTypeSymbol FilterTypeInitializerAttribute, @@ -126,6 +130,18 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK var compositeAggregationAttribute = compilation .GetTypeByMetadataName(typeof(CompositeAggregationAttribute).FullName ?? ""); + var genericParameterSubstituteAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(GenericParameterSubstituteAggregationAttribute).FullName ?? ""); + + var filterGenericParameterSubstituteAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(FilterGenericParameterSubstituteAggregationAttribute).FullName ?? ""); + + var genericParameterSubstituteChoiceAttribute = compilation + .GetTypeByMetadataName(typeof(GenericParameterSubstituteChoiceAttribute).FullName ?? ""); + + var filterGenericParameterSubstituteChoiceAttribute = compilation + .GetTypeByMetadataName(typeof(FilterGenericParameterSubstituteChoiceAttribute).FullName ?? ""); + var decoratorSequenceChoiceAttribute = compilation .GetTypeByMetadataName(typeof(DecoratorSequenceChoiceAttribute).FullName ?? ""); @@ -202,6 +218,8 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK && scopeRootAggregationAttribute is not null && decoratorAggregationAttribute is not null && compositeAggregationAttribute is not null + && genericParameterSubstituteAggregationAttribute is not null + && genericParameterSubstituteChoiceAttribute is not null && decoratorSequenceChoiceAttribute is not null && constructorChoiceAttribute is not null && typeInitializerAttribute is not null @@ -218,6 +236,8 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK && filterScopeRootAggregationAttribute is not null && filterDecoratorAggregationAttribute is not null && filterCompositeAggregationAttribute is not null + && filterGenericParameterSubstituteAggregationAttribute is not null + && filterGenericParameterSubstituteChoiceAttribute is not null && filterDecoratorSequenceChoiceAttribute is not null && filterConstructorChoiceAttribute is not null && filterTypeInitializerAttribute is not null @@ -257,6 +277,8 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK ScopeRootAggregationAttribute: scopeRootAggregationAttribute, DecoratorAggregationAttribute: decoratorAggregationAttribute, CompositeAggregationAttribute: compositeAggregationAttribute, + GenericParameterSubstituteAggregationAttribute: genericParameterSubstituteAggregationAttribute, + GenericParameterSubstituteChoiceAttribute: genericParameterSubstituteChoiceAttribute, DecoratorSequenceChoiceAttribute: decoratorSequenceChoiceAttribute, ConstructorChoiceAttribute: constructorChoiceAttribute, TypeInitializerAttribute: typeInitializerAttribute, @@ -273,6 +295,8 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK FilterScopeRootAggregationAttribute: filterScopeRootAggregationAttribute, FilterDecoratorAggregationAttribute: filterDecoratorAggregationAttribute, FilterCompositeAggregationAttribute: filterCompositeAggregationAttribute, + FilterGenericParameterSubstituteAggregationAttribute: filterGenericParameterSubstituteAggregationAttribute, + FilterGenericParameterSubstituteChoiceAttribute: filterGenericParameterSubstituteChoiceAttribute, FilterDecoratorSequenceChoiceAttribute: filterDecoratorSequenceChoiceAttribute, FilterConstructorChoiceAttribute: filterConstructorChoiceAttribute, FilterTypeInitializerAttribute: filterTypeInitializerAttribute, diff --git a/Sample/Context.cs b/Sample/Context.cs index 8a750ad1..a60f1ab9 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -1,22 +1,14 @@ -using MrMeeseeks.DIE.Configuration; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Sample; + +namespace MrMeeseeks.DIE.Test.Generics.Interface_SingleAndImplementationDoubleButOneFixed; -namespace MrMeeseeks.DIE.Test.Nullability.MultipleConstructors; +internal interface IInterface {} -internal class Dependency -{ - internal Dependency() {} - internal Dependency(int _) {} -} +internal abstract class BaseClass : IInterface {} -internal class Wrapper -{ - public Dependency? Dependency { get; } +internal class Class : BaseClass {} - internal Wrapper(Dependency? dependency) => Dependency = dependency; -} - -[CreateFunction(typeof(Wrapper), "Create")] -internal partial class Container -{ - private int DIE_Counter() => 69; -} +[CreateFunction(typeof(IInterface), "Create")] +internal partial class Container {} \ No newline at end of file diff --git a/Test/Generics/Implementation/Double.cs b/Test/Generics/Implementation/Double.cs new file mode 100644 index 00000000..ba57cfe9 --- /dev/null +++ b/Test/Generics/Implementation/Double.cs @@ -0,0 +1,20 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Generics.Implementation.Double; + +internal class Class {} + +[CreateFunction(typeof(Class), "Create")] +internal partial class Container {} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var instance = container.Create(); + Assert.IsType>(instance); + } +} \ No newline at end of file diff --git a/Test/Generics/Implementation/Single.cs b/Test/Generics/Implementation/Single.cs new file mode 100644 index 00000000..2f764587 --- /dev/null +++ b/Test/Generics/Implementation/Single.cs @@ -0,0 +1,20 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Generics.Implementation.Single; + +internal class Class {} + +[CreateFunction(typeof(Class), "Create")] +internal partial class Container {} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var instance = container.Create(); + Assert.IsType>(instance); + } +} \ No newline at end of file diff --git a/Test/Generics/Interface/Double.cs b/Test/Generics/Interface/Double.cs new file mode 100644 index 00000000..194e11a8 --- /dev/null +++ b/Test/Generics/Interface/Double.cs @@ -0,0 +1,22 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Generics.Interface.Double; + +internal interface IInterface {} + +internal class Class : IInterface {} + +[CreateFunction(typeof(IInterface), "Create")] +internal partial class Container {} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var instance = container.Create(); + Assert.IsType>(instance); + } +} \ No newline at end of file diff --git a/Test/Generics/Interface/DoubleAndOneFixed.cs b/Test/Generics/Interface/DoubleAndOneFixed.cs new file mode 100644 index 00000000..746a71d9 --- /dev/null +++ b/Test/Generics/Interface/DoubleAndOneFixed.cs @@ -0,0 +1,22 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Generics.Interface.DoubleAndOneFixed; + +internal interface IInterface {} + +internal class Class : IInterface {} + +[CreateFunction(typeof(IInterface), "Create")] +internal partial class Container {} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var instance = container.Create(); + Assert.IsType>(instance); + } +} \ No newline at end of file diff --git a/Test/Generics/Interface/DoubleAndSetToSame.cs b/Test/Generics/Interface/DoubleAndSetToSame.cs new file mode 100644 index 00000000..f512baef --- /dev/null +++ b/Test/Generics/Interface/DoubleAndSetToSame.cs @@ -0,0 +1,22 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Generics.Interface.DoubleAndSetToSame; + +internal interface IInterface {} + +internal class Class : IInterface {} + +[CreateFunction(typeof(IInterface), "Create")] +internal partial class Container {} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var instance = container.Create(); + Assert.IsType>(instance); + } +} \ No newline at end of file diff --git a/Test/Generics/Interface/DoubleSwitched.cs b/Test/Generics/Interface/DoubleSwitched.cs new file mode 100644 index 00000000..eea62625 --- /dev/null +++ b/Test/Generics/Interface/DoubleSwitched.cs @@ -0,0 +1,22 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Generics.Interface.DoubleSwitched; + +internal interface IInterface {} + +internal class Class : IInterface {} + +[CreateFunction(typeof(IInterface), "Create")] +internal partial class Container {} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var instance = container.Create(); + Assert.IsType>(instance); + } +} \ No newline at end of file diff --git a/Test/Generics/Interface/Single.cs b/Test/Generics/Interface/Single.cs new file mode 100644 index 00000000..0262cc46 --- /dev/null +++ b/Test/Generics/Interface/Single.cs @@ -0,0 +1,22 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Generics.Interface.Single; + +internal interface IInterface {} + +internal class Class : IInterface {} + +[CreateFunction(typeof(IInterface), "Create")] +internal partial class Container {} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var instance = container.Create(); + Assert.IsType>(instance); + } +} \ No newline at end of file diff --git a/Test/Generics/Interface/SingleAndBaseImplementationDoubleButOneFixed.cs b/Test/Generics/Interface/SingleAndBaseImplementationDoubleButOneFixed.cs new file mode 100644 index 00000000..470d1817 --- /dev/null +++ b/Test/Generics/Interface/SingleAndBaseImplementationDoubleButOneFixed.cs @@ -0,0 +1,24 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Generics.Interface.SingleAndBaseImplementationDoubleButOneFixed; + +internal interface IInterface {} + +internal abstract class BaseClass : IInterface {} + +internal class Class : BaseClass {} + +[CreateFunction(typeof(IInterface), "Create")] +internal partial class Container {} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var instance = container.Create(); + Assert.IsType>(instance); + } +} \ No newline at end of file From a67901c67acead86b4918faab20a5c9693c67ec9 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sun, 1 May 2022 14:57:01 +0200 Subject: [PATCH 067/162] Implemented support for generic implementations --- Main/Configuration/Attributes.cs | 8 +- Main/Configuration/CheckTypeProperties.cs | 119 +++++- .../Configuration/CurrentlyConsideredTypes.cs | 60 ++- Main/Configuration/TypesFromAttributes.cs | 124 +++++- .../ContainerResolutionBuilder.cs | 4 +- .../Function/FunctionResolutionBuilder.cs | 150 ++------ ...copeRootCreateFunctionResolutionBuilder.cs | 18 +- .../RangeResolutionBaseBuilder.cs | 8 +- Main/ResolutionBuilding/ResolutionDtos.cs | 48 +-- .../ScopeResolutionBuilder.cs | 14 +- .../TransientScopeResolutionBuilder.cs | 14 +- Main/RoslynExtensions.cs | 4 +- Main/SourceGenerator.cs | 4 +- Main/WellKnownTypes.cs | 20 +- Sample/Context.cs | 14 +- SampleChild/Class1.cs | 30 -- SampleChild/Public.cs | 124 ++++++ SampleChild/lnternal.cs | 125 ++++++ Test/Composite/Container.cs | 69 ++++ Test/Composite/Decorated.cs | 96 +++++ Test/Composite/MixedScoping.cs | 69 ++++ Test/Composite/Normal.cs | 64 +++ Test/Composite/ScopeRoot.cs | 82 ++++ Test/CompositeTests.cs | 363 ------------------ Test/Generics/Choice/Double.cs | 23 ++ Test/Generics/Choice/DoubleBothChosen.cs | 24 ++ ...ubleBothChosenWithSingleOtherSubstitute.cs | 26 ++ .../Choice/DoubleWithSingleOtherSubstitute.cs | 24 ++ Test/Generics/Choice/Single.cs | 23 ++ .../Choice/SingleWithSingleOtherSubstitute.cs | 24 ++ .../Double.cs | 23 ++ .../Single.cs | 23 ++ Test/Generics/SubstituteCollection/Double.cs | 26 ++ .../DoubleBothSubstituted.cs | 29 ++ .../DoubleBothSubstitutedWithChoice.cs | 31 ++ .../SubstituteCollection/DoubleWithChoice.cs | 27 ++ Test/Generics/SubstituteCollection/Single.cs | 28 ++ .../SubstituteCollection/SingleWithChoice.cs | 29 ++ .../SubstituteCollection/TripleInsanity.cs | 26 ++ .../ScopeSpecificAttributes/Decorator.cs} | 4 +- .../Implementation.cs} | 2 +- .../ImplementationCollection.cs} | 2 +- .../TransientScopeInstance/InContainer.cs | 25 ++ .../Scoping/TransientScopeInstance/InScope.cs | 31 ++ .../TransientScopeInstance/InScopeInScope.cs | 37 ++ .../InTransientScope.cs | 50 +++ .../InTransientScopeWithScopes.cs | 79 ++++ Test/Test.csproj | 4 + Test/TransientScopeInstanceTests.cs | 142 ------- 49 files changed, 1610 insertions(+), 783 deletions(-) delete mode 100644 SampleChild/Class1.cs create mode 100644 SampleChild/Public.cs create mode 100644 SampleChild/lnternal.cs create mode 100644 Test/Composite/Container.cs create mode 100644 Test/Composite/Decorated.cs create mode 100644 Test/Composite/MixedScoping.cs create mode 100644 Test/Composite/Normal.cs create mode 100644 Test/Composite/ScopeRoot.cs delete mode 100644 Test/CompositeTests.cs create mode 100644 Test/Generics/Choice/Double.cs create mode 100644 Test/Generics/Choice/DoubleBothChosen.cs create mode 100644 Test/Generics/Choice/DoubleBothChosenWithSingleOtherSubstitute.cs create mode 100644 Test/Generics/Choice/DoubleWithSingleOtherSubstitute.cs create mode 100644 Test/Generics/Choice/Single.cs create mode 100644 Test/Generics/Choice/SingleWithSingleOtherSubstitute.cs create mode 100644 Test/Generics/ChoiceIndirectlyBySingleSubstitute/Double.cs create mode 100644 Test/Generics/ChoiceIndirectlyBySingleSubstitute/Single.cs create mode 100644 Test/Generics/SubstituteCollection/Double.cs create mode 100644 Test/Generics/SubstituteCollection/DoubleBothSubstituted.cs create mode 100644 Test/Generics/SubstituteCollection/DoubleBothSubstitutedWithChoice.cs create mode 100644 Test/Generics/SubstituteCollection/DoubleWithChoice.cs create mode 100644 Test/Generics/SubstituteCollection/Single.cs create mode 100644 Test/Generics/SubstituteCollection/SingleWithChoice.cs create mode 100644 Test/Generics/SubstituteCollection/TripleInsanity.cs rename Test/{ScopeSpecificAttributesTestsWithDecorator.cs => Scoping/ScopeSpecificAttributes/Decorator.cs} (97%) rename Test/{ScopeSpecificAttributesTestsWithImplementations.cs => Scoping/ScopeSpecificAttributes/Implementation.cs} (96%) rename Test/{ScopeSpecificAttributesTestsWithImplementationLists.cs => Scoping/ScopeSpecificAttributes/ImplementationCollection.cs} (96%) create mode 100644 Test/Scoping/TransientScopeInstance/InContainer.cs create mode 100644 Test/Scoping/TransientScopeInstance/InScope.cs create mode 100644 Test/Scoping/TransientScopeInstance/InScopeInScope.cs create mode 100644 Test/Scoping/TransientScopeInstance/InTransientScope.cs create mode 100644 Test/Scoping/TransientScopeInstance/InTransientScopeWithScopes.cs delete mode 100644 Test/TransientScopeInstanceTests.cs diff --git a/Main/Configuration/Attributes.cs b/Main/Configuration/Attributes.cs index 388b5787..dc8f1f2d 100644 --- a/Main/Configuration/Attributes.cs +++ b/Main/Configuration/Attributes.cs @@ -171,15 +171,15 @@ public FilterGenericParameterSubstituteAggregationAttribute(Type unboundGenericT } [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] -public class GenericParameterSubstituteChoiceAttribute : Attribute +public class GenericParameterChoiceAttribute : Attribute { - public GenericParameterSubstituteChoiceAttribute(Type unboundGenericType, string genericArgumentName, Type chosenType) {} + public GenericParameterChoiceAttribute(Type unboundGenericType, string genericArgumentName, Type chosenType) {} } [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] -public class FilterGenericParameterSubstituteChoiceAttribute : Attribute +public class FilterGenericParameterChoiceAttribute : Attribute { - public FilterGenericParameterSubstituteChoiceAttribute(Type unboundGenericType, string genericArgumentName) {} + public FilterGenericParameterChoiceAttribute(Type unboundGenericType, string genericArgumentName) {} } [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] diff --git a/Main/Configuration/CheckTypeProperties.cs b/Main/Configuration/CheckTypeProperties.cs index 38ea4b2f..9c714ba5 100644 --- a/Main/Configuration/CheckTypeProperties.cs +++ b/Main/Configuration/CheckTypeProperties.cs @@ -28,7 +28,8 @@ internal interface ICheckTypeProperties bool ShouldBeDecorated(INamedTypeSymbol interfaceType); IReadOnlyList GetSequenceFor(INamedTypeSymbol interfaceType, INamedTypeSymbol implementationType); - + + INamedTypeSymbol? MapToSingleFittingImplementation(INamedTypeSymbol type); IReadOnlyList MapToImplementations(INamedTypeSymbol typeSymbol); (INamedTypeSymbol Type, IMethodSymbol Initializer)? GetInitializerFor(INamedTypeSymbol implementationType); } @@ -102,15 +103,27 @@ public IReadOnlyList GetSequenceFor(INamedTypeSymbol interface return allDecorators; throw new Exception("Couldn't find unambiguous sequence of decorators"); } - + + public INamedTypeSymbol? MapToSingleFittingImplementation(INamedTypeSymbol type) + { + var possibleImplementations = _currentlyConsideredTypes.ImplementationMap.TryGetValue(type.UnboundIfGeneric(), out var implementations) + ? GetClosedImplementations(type, implementations, true) + : Array.Empty(); + + return possibleImplementations.Count == 1 + ? possibleImplementations.FirstOrDefault() + : null; + } + public IReadOnlyList MapToImplementations(INamedTypeSymbol typeSymbol) => _currentlyConsideredTypes.ImplementationMap.TryGetValue(typeSymbol.UnboundIfGeneric(), out var implementations) - ? GetClosedImplementations(typeSymbol, implementations) + ? GetClosedImplementations(typeSymbol, implementations, false) : Array.Empty(); private IReadOnlyList GetClosedImplementations( INamedTypeSymbol targetType, - IReadOnlyList rawImplementations) + IReadOnlyList rawImplementations, + bool preferChoicesForOpenGenericParameters) { var targetClosedGenericParameters = targetType .TypeArguments @@ -134,25 +147,40 @@ private IReadOnlyList GetClosedImplementations( .FirstOrDefault(t => SymbolEqualityComparer.Default.Equals(t.UnboundIfGeneric(), unboundTargetType)) is { } implementationsTarget) { + var unboundImplementation = implementation.UnboundIfGeneric(); var newTypeArguments = implementation.TypeArguments .Select(ta => ta switch { INamedTypeSymbol nts => nts, - ITypeParameterSymbol tps => - implementationsTarget - .TypeArguments - .IndexOf(tps, SymbolEqualityComparer.Default) is int index - && index >= 0 - ? targetClosedGenericParameters[index] - : throw new Exception("huh?"), + ITypeParameterSymbol tps => ForTypeParameterSymbol(tps), _ => ta }) - .OfType() - .OfType() .ToArray(); + ITypeSymbol ForTypeParameterSymbol(ITypeParameterSymbol tps) + { + if (implementationsTarget + .TypeArguments + .IndexOf(tps, SymbolEqualityComparer.Default) is var index and >= 0) + return targetClosedGenericParameters[index]; + + if (preferChoicesForOpenGenericParameters) + { + if (_currentlyConsideredTypes.GenericParameterChoices.TryGetValue( + (unboundImplementation, tps), out var choice)) + return choice; + if (_currentlyConsideredTypes.GenericParameterSubstitutes.TryGetValue( + (unboundImplementation, tps), out var substitutes) + && substitutes.Count == 1) + return substitutes[0]; + } + + return tps; + } + - if (newTypeArguments.Length == implementation.TypeArguments.Length) + if (newTypeArguments.Length == implementation.TypeArguments.Length + && newTypeArguments.All(ta => ta is INamedTypeSymbol)) { var closedImplementation = implementation.Construct(newTypeArguments); if (closedImplementation @@ -162,6 +190,69 @@ private IReadOnlyList GetClosedImplementations( ret.Add(closedImplementation); } } + else if (newTypeArguments.Length == implementation.TypeArguments.Length + && newTypeArguments.All(ta => ta is INamedTypeSymbol or ITypeParameterSymbol)) + { + var openTypeParameters = newTypeArguments.OfType().ToImmutableArray(); + var queue = ImmutableQueue.CreateRange(openTypeParameters + .Select(tp => + { + IImmutableSet substitutes = ImmutableHashSet.CreateRange( + _currentlyConsideredTypes.GenericParameterSubstitutes.TryGetValue( + (unboundImplementation, tp), out var subs) + ? subs + : Array.Empty()); + if (_currentlyConsideredTypes.GenericParameterChoices.TryGetValue( + (unboundImplementation, tp), out var choice)) + substitutes = substitutes.Add(choice); + return (tp, substitutes); + })); + if (queue.All(t => t.substitutes.Count > 0)) + { + foreach (var combination in GetAllSubstituteCombinations(queue, ImmutableDictionary.Empty)) + { + var veryNewTypeArguments = newTypeArguments + .Select(ta => ta switch + { + INamedTypeSymbol nts => nts, + ITypeParameterSymbol tps => combination.TryGetValue(tps, out var sub) ? sub : tps, + _ => ta + }) + .ToArray(); + if (veryNewTypeArguments.Length == implementation.TypeArguments.Length + && veryNewTypeArguments.All(ta => ta is INamedTypeSymbol)) + { + var closedImplementation = implementation.Construct(veryNewTypeArguments); + if (closedImplementation + .AllDerivedTypes() + .Any(t => SymbolEqualityComparer.Default.Equals(targetType, t))) + { + ret.Add(closedImplementation); + } + } + } + + IEnumerable> GetAllSubstituteCombinations( + IImmutableQueue<(ITypeParameterSymbol, IImmutableSet)> currentSubstituteQueue, + IImmutableDictionary currentCombination) + { + if (currentSubstituteQueue.IsEmpty) + yield return currentCombination; + else + { + currentSubstituteQueue = currentSubstituteQueue.Dequeue(out var tuple); + foreach (var substitute in tuple.Item2) + { + var newCurrentCombination = currentCombination.Add(tuple.Item1, substitute); + foreach (var combination in GetAllSubstituteCombinations(currentSubstituteQueue, newCurrentCombination)) + { + yield return combination; + } + } + } + } + } + } } } diff --git a/Main/Configuration/CurrentlyConsideredTypes.cs b/Main/Configuration/CurrentlyConsideredTypes.cs index 4a3d6004..7bfe8953 100644 --- a/Main/Configuration/CurrentlyConsideredTypes.cs +++ b/Main/Configuration/CurrentlyConsideredTypes.cs @@ -15,10 +15,12 @@ internal interface ICurrentlyConsideredTypes IReadOnlyDictionary InterfaceToComposite { get; } IReadOnlyDictionary ImplementationToConstructorChoice { get; } IReadOnlyDictionary> InterfaceToDecorators { get; } - IReadOnlyDictionary> InterfaceSequenceChoices { get; } - IReadOnlyDictionary> ImplementationSequenceChoices { get; } + IReadOnlyDictionary> InterfaceSequenceChoices { get; } + IReadOnlyDictionary> ImplementationSequenceChoices { get; } IReadOnlyDictionary> ImplementationMap { get; } IReadOnlyDictionary ImplementationToInitializer { get; } + IReadOnlyDictionary<(INamedTypeSymbol, ITypeParameterSymbol), IReadOnlyList> GenericParameterSubstitutes { get; } + IReadOnlyDictionary<(INamedTypeSymbol, ITypeParameterSymbol), INamedTypeSymbol> GenericParameterChoices { get; } } internal class CurrentlyConsideredTypes : ICurrentlyConsideredTypes @@ -200,6 +202,58 @@ public CurrentlyConsideredTypes( } ImplementationToInitializer = initializers; + + var genericParameterSubstitutes = + new Dictionary<(INamedTypeSymbol, ITypeParameterSymbol), IReadOnlyList>(); + + foreach (var typesFromAttribute in typesFromAttributes) + { + foreach (var tuple in typesFromAttribute.FilterGenericParameterSubstitutes) + { + var key = (tuple.Item1, tuple.Item2); + if (genericParameterSubstitutes.TryGetValue(key, out var currentGenericTypes)) + { + var newGenericTypes = currentGenericTypes + .Where(gt => !tuple.Item3.Contains(gt, SymbolEqualityComparer.Default)).ToImmutableList(); + if (newGenericTypes.Any()) + genericParameterSubstitutes[key] = newGenericTypes; + else + genericParameterSubstitutes.Remove(key); + } + } + + foreach (var tuple in typesFromAttribute.GenericParameterSubstitutes) + { + var key = (tuple.Item1, tuple.Item2); + var list = new List( + genericParameterSubstitutes.TryGetValue(key, out var currentGenericTypes) + ? currentGenericTypes + : Array.Empty()); + foreach (var newGenericType in tuple.Item3) + { + if (!list.Contains(newGenericType, SymbolEqualityComparer.Default)) + list.Add(newGenericType); + } + + genericParameterSubstitutes[key] = list; + } + } + + GenericParameterSubstitutes = genericParameterSubstitutes; + + var genericParameterChoices = + new Dictionary<(INamedTypeSymbol, ITypeParameterSymbol), INamedTypeSymbol>(); + + foreach (var typesFromAttribute in typesFromAttributes) + { + foreach (var tuple in typesFromAttribute.FilterGenericParameterChoices) + genericParameterChoices.Remove((tuple.Item1, tuple.Item2)); + + foreach (var tuple in typesFromAttribute.GenericParameterChoices) + genericParameterChoices[(tuple.Item1, tuple.Item2)] = tuple.Item3; + } + + GenericParameterChoices = genericParameterChoices; IImmutableSet GetSetOfTypesWithProperties( Func> propertyGivingTypesGetter, @@ -240,4 +294,6 @@ public CurrentlyConsideredTypes( public IReadOnlyDictionary> ImplementationSequenceChoices { get; } public IReadOnlyDictionary> ImplementationMap { get; } public IReadOnlyDictionary ImplementationToInitializer { get; } + public IReadOnlyDictionary<(INamedTypeSymbol, ITypeParameterSymbol), IReadOnlyList> GenericParameterSubstitutes { get; } + public IReadOnlyDictionary<(INamedTypeSymbol, ITypeParameterSymbol), INamedTypeSymbol> GenericParameterChoices { get; } } \ No newline at end of file diff --git a/Main/Configuration/TypesFromAttributes.cs b/Main/Configuration/TypesFromAttributes.cs index 77792aa4..fa35f7bc 100644 --- a/Main/Configuration/TypesFromAttributes.cs +++ b/Main/Configuration/TypesFromAttributes.cs @@ -17,6 +17,8 @@ internal interface ITypesFromAttributes IReadOnlyList<(INamedTypeSymbol, IReadOnlyList)> DecoratorSequenceChoices { get; } IReadOnlyList<(INamedTypeSymbol, IMethodSymbol)> ConstructorChoices { get; } IReadOnlyList<(INamedTypeSymbol, IMethodSymbol)> TypeInitializers { get; } + IReadOnlyList<(INamedTypeSymbol, ITypeParameterSymbol, IReadOnlyList)> GenericParameterSubstitutes { get; } + IReadOnlyList<(INamedTypeSymbol, ITypeParameterSymbol, INamedTypeSymbol)> GenericParameterChoices { get; } IReadOnlyList FilterSpy { get; } IReadOnlyList FilterImplementation { get; } IReadOnlyList FilterTransient { get; } @@ -32,6 +34,8 @@ internal interface ITypesFromAttributes IReadOnlyList FilterDecoratorSequenceChoices { get; } IReadOnlyList FilterConstructorChoices { get; } IReadOnlyList FilterTypeInitializers { get; } + IReadOnlyList<(INamedTypeSymbol, ITypeParameterSymbol, IReadOnlyList)> FilterGenericParameterSubstitutes { get; } + IReadOnlyList<(INamedTypeSymbol, ITypeParameterSymbol)> FilterGenericParameterChoices { get; } } internal class TypesFromAttributes : ScopeTypesFromAttributes @@ -98,7 +102,7 @@ internal ScopeTypesFromAttributes( { if (ad.ConstructorArguments.Length < 2) return null; - var decoratedType = ad.ConstructorArguments[0].Value; + var decoratedType = ad.ConstructorArguments[0].Value as INamedTypeSymbol; var decorators = ad .ConstructorArguments[1] .Values @@ -179,7 +183,7 @@ internal ScopeTypesFromAttributes( }) .OfType<(INamedTypeSymbol, IMethodSymbol)>() .ToList(); - + FilterConstructorChoices = (AttributeDictionary.TryGetValue(wellKnownTypes.FilterConstructorChoiceAttribute, out var group2) ? group2 : Enumerable.Empty()) .Concat(GetTypesFromAttribute(wellKnownTypes.FilterSpyConstructorChoiceAggregationAttribute) .Select(t => t.GetAttributes().FirstOrDefault(ad => ad.AttributeClass?.Name == nameof(ConstructorChoiceAttribute))) @@ -237,6 +241,118 @@ internal ScopeTypesFromAttributes( }) .OfType() .ToList(); + + GenericParameterSubstitutes = (AttributeDictionary.TryGetValue(wellKnownTypes.GenericParameterSubstituteAggregationAttribute, out var group5) ? group5 : Enumerable.Empty()) + .Select(ad => + { + if (ad.ConstructorArguments.Length < 3) + return null; + var genericType = ad.ConstructorArguments[0].Value as INamedTypeSymbol; + + if (genericType is not { IsGenericType: true, IsUnboundGenericType: true } + || ad.ConstructorArguments[1].Value is not string nameOfGenericParameter) + return null; + + var typeParameterSymbol = genericType + .OriginalDefinition + .TypeArguments + .OfType() + .FirstOrDefault(tps => tps.Name == nameOfGenericParameter); + + var substitutes = ad + .ConstructorArguments[2] + .Values + .Select(tc => tc.Value) + .OfType() + .ToList(); + + return typeParameterSymbol is null + ? null + : ((INamedTypeSymbol, ITypeParameterSymbol, IReadOnlyList)?) (genericType, typeParameterSymbol, substitutes); + }) + .OfType<(INamedTypeSymbol, ITypeParameterSymbol, IReadOnlyList)>() + .ToList(); + + GenericParameterChoices = (AttributeDictionary.TryGetValue(wellKnownTypes.GenericParameterChoiceAttribute, out var group6) ? group6 : Enumerable.Empty()) + .Select(ad => + { + if (ad.ConstructorArguments.Length < 3) + return null; + var genericType = ad.ConstructorArguments[0].Value as INamedTypeSymbol; + var typeChoice = ad.ConstructorArguments[2].Value as INamedTypeSymbol; + + if (genericType is not { IsGenericType: true, IsUnboundGenericType: true } + || ad.ConstructorArguments[1].Value is not string nameOfGenericParameter + || typeChoice is null) + return null; + + var typeParameterSymbol = genericType + .OriginalDefinition + .TypeArguments + .OfType() + .FirstOrDefault(tps => tps.Name == nameOfGenericParameter); + + return typeParameterSymbol is null + ? null + : ((INamedTypeSymbol, ITypeParameterSymbol, INamedTypeSymbol)?) (genericType, typeParameterSymbol, typeChoice); + }) + .OfType<(INamedTypeSymbol, ITypeParameterSymbol, INamedTypeSymbol)>() + .ToList(); + + FilterGenericParameterSubstitutes = (AttributeDictionary.TryGetValue(wellKnownTypes.FilterGenericParameterSubstituteAggregationAttribute, out var group7) ? group7 : Enumerable.Empty()) + .Select(ad => + { + if (ad.ConstructorArguments.Length < 3) + return null; + var genericType = ad.ConstructorArguments[0].Value as INamedTypeSymbol; + + if (genericType is not { IsGenericType: true, IsUnboundGenericType: true } + || ad.ConstructorArguments[1].Value is not string nameOfGenericParameter) + return null; + + var typeParameterSymbol = genericType + .OriginalDefinition + .TypeArguments + .OfType() + .FirstOrDefault(tps => tps.Name == nameOfGenericParameter); + + var substitutes = ad + .ConstructorArguments[2] + .Values + .Select(tc => tc.Value) + .OfType() + .ToList(); + + return typeParameterSymbol is null + ? null + : ((INamedTypeSymbol, ITypeParameterSymbol, IReadOnlyList)?) (genericType, typeParameterSymbol, substitutes); + }) + .OfType<(INamedTypeSymbol, ITypeParameterSymbol, IReadOnlyList)>() + .ToList(); + + FilterGenericParameterChoices = (AttributeDictionary.TryGetValue(wellKnownTypes.FilterGenericParameterChoiceAttribute, out var group8) ? group8 : Enumerable.Empty()) + .Select(ad => + { + if (ad.ConstructorArguments.Length < 2) + return null; + var genericType = ad.ConstructorArguments[0].Value as INamedTypeSymbol; + + if (genericType is not { IsGenericType: true, IsUnboundGenericType: true } + || ad.ConstructorArguments[1].Value is not string nameOfGenericParameter) + return null; + + var typeParameterSymbol = genericType + .OriginalDefinition + .TypeArguments + .OfType() + .FirstOrDefault(tps => tps.Name == nameOfGenericParameter); + + return typeParameterSymbol is null + ? null + : ((INamedTypeSymbol, ITypeParameterSymbol)?) (genericType, typeParameterSymbol); + }) + .OfType<(INamedTypeSymbol, ITypeParameterSymbol)>() + .ToList(); } private IReadOnlyDictionary> AttributeDictionary { get; } @@ -278,6 +394,8 @@ bool CheckValidType(TypedConstant typedConstant, out INamedTypeSymbol type) public IReadOnlyList<(INamedTypeSymbol, IReadOnlyList)> DecoratorSequenceChoices { get; } public IReadOnlyList<(INamedTypeSymbol, IMethodSymbol)> ConstructorChoices { get; } public IReadOnlyList<(INamedTypeSymbol, IMethodSymbol)> TypeInitializers { get; } + public IReadOnlyList<(INamedTypeSymbol, ITypeParameterSymbol, IReadOnlyList)> GenericParameterSubstitutes { get; } + public IReadOnlyList<(INamedTypeSymbol, ITypeParameterSymbol, INamedTypeSymbol)> GenericParameterChoices { get; } public IReadOnlyList FilterSpy { get; } public IReadOnlyList FilterImplementation { get; } public IReadOnlyList FilterTransient { get; } @@ -293,4 +411,6 @@ bool CheckValidType(TypedConstant typedConstant, out INamedTypeSymbol type) public IReadOnlyList FilterDecoratorSequenceChoices { get; } public IReadOnlyList FilterConstructorChoices { get; } public IReadOnlyList FilterTypeInitializers { get; } + public IReadOnlyList<(INamedTypeSymbol, ITypeParameterSymbol, IReadOnlyList)> FilterGenericParameterSubstitutes { get; } + public IReadOnlyList<(INamedTypeSymbol, ITypeParameterSymbol)> FilterGenericParameterChoices { get; } } \ No newline at end of file diff --git a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs index cdecaed0..d0e5b0db 100644 --- a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs @@ -81,7 +81,7 @@ public override MultiSynchronicityFunctionCallResolution CreateTransientScopeIns _transientScopeInterfaceResolutionBuilder.CreateTransientScopeInstanceReferenceResolution(parameter, _transientScopeAdapterReference); public override TransientScopeRootResolution CreateTransientScopeRootResolution( - IScopeRootParameter parameter, + SwitchImplementationParameter parameter, INamedTypeSymbol rootType, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) => _scopeManager @@ -93,7 +93,7 @@ public override TransientScopeRootResolution CreateTransientScopeRootResolution( currentParameters); public override ScopeRootResolution CreateScopeRootResolution( - IScopeRootParameter parameter, + SwitchImplementationParameter parameter, INamedTypeSymbol rootType, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) => _scopeManager diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs index 7b83ea3f..8face208 100644 --- a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs @@ -311,8 +311,7 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup .Select(i => { var itemResolution = itemTypeIsInterface - ? SwitchInterfaceForSpecificImplementation( - new SwitchInterfaceForSpecificImplementationParameter(unwrappedItemType, i, currentFuncParameters)) + ? SwitchInterfaceWithoutComposition(new CreateInterfaceParameter(unwrappedItemType, i, currentFuncParameters)) : SwitchClass(new SwitchClassParameter(i, currentFuncParameters)); return (taskType switch { @@ -332,11 +331,12 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup null); } - if (type.TypeKind == TypeKind.Interface) - return SwitchInterface(new SwitchInterfaceParameter(type, currentFuncParameters)); + if (type is { TypeKind: TypeKind.Interface} + or { TypeKind: TypeKind.Class, IsAbstract: true } + && type is INamedTypeSymbol interfaceOrAbstractType) + return SwitchInterface(new SwitchInterfaceAfterScopeRootParameter(interfaceOrAbstractType, currentFuncParameters)); - if (type.TypeKind is TypeKind.Class or TypeKind.Struct - && type is INamedTypeSymbol classOrStructType) + if (type is INamedTypeSymbol { TypeKind: TypeKind.Class or TypeKind.Struct} classOrStructType) return SwitchClass(new SwitchClassParameter(classOrStructType, currentFuncParameters)); return ( @@ -446,57 +446,15 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup return (new TaskFromSyncResolution(resolution.Item1, wrappedValueTaskReference, boundValueTaskTypeFullName), resolution.Item2); } - private (Resolvable, ITaskConsumableResolution?) SwitchInterface(SwitchInterfaceParameter parameter) - { - var (typeSymbol, currentParameters) = parameter; - var interfaceType = (INamedTypeSymbol) typeSymbol; - var implementations = _checkTypeProperties - .MapToImplementations(interfaceType); - var shouldBeScopeRoot = implementations.Any() - ? implementations.Max(i => _checkTypeProperties.ShouldBeScopeRoot(i)) - : ScopeLevel.None; - - var nextParameter = new SwitchInterfaceAfterScopeRootParameter( - interfaceType, - implementations, - currentParameters); - - var ret = shouldBeScopeRoot switch - { - ScopeLevel.TransientScope => (_rangeResolutionBaseBuilder.CreateTransientScopeRootResolution( - nextParameter, - interfaceType, - currentParameters), null), - ScopeLevel.Scope => (_rangeResolutionBaseBuilder.CreateScopeRootResolution( - nextParameter, - interfaceType, - currentParameters), null), - _ => SwitchInterfaceAfterScopeRoot(nextParameter) - }; - - if (ret.Item1 is ScopeRootResolution { ScopeRootFunction: IAwaitableResolution awaitableResolution }) - _synchronicityDecisionMaker.Register(awaitableResolution); - - if (ret.Item1 is TransientScopeRootResolution { ScopeRootFunction: IAwaitableResolution awaitableResolution0 }) - _synchronicityDecisionMaker.Register(awaitableResolution0); - - if (ret.Item1 is ScopeRootResolution { ScopeRootFunction: ITaskConsumableResolution taskConsumableResolution }) - ret.Item2 = taskConsumableResolution; - - if (ret.Item1 is TransientScopeRootResolution { ScopeRootFunction: ITaskConsumableResolution taskConsumableResolution0 }) - ret.Item2 = taskConsumableResolution0; - - return ret; - } - - protected (Resolvable, ITaskConsumableResolution?) SwitchInterfaceAfterScopeRoot( + private (Resolvable, ITaskConsumableResolution?) SwitchInterface( SwitchInterfaceAfterScopeRootParameter parameter) { - var (interfaceType, implementations, currentParameters) = parameter; + var (interfaceType, currentParameters) = parameter; if (_checkTypeProperties.ShouldBeComposite(interfaceType)) { + var implementations = _checkTypeProperties.MapToImplementations(interfaceType); var compositeImplementationType = _checkTypeProperties.GetCompositeFor(interfaceType); - var interfaceResolutions = implementations.Select(i => CreateInterface(new CreateInterfaceParameter( + var interfaceResolutions = implementations.Select(i => SwitchInterfaceWithoutComposition(new CreateInterfaceParameter( interfaceType, i, currentParameters))).ToList(); @@ -505,90 +463,45 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup implementations.ToList(), compositeImplementationType, interfaceResolutions.Select(ir => ir.Item1).ToList()); - return CreateInterface(new CreateInterfaceParameterAsComposition( + return SwitchInterfaceWithoutComposition(new CreateInterfaceParameterAsComposition( interfaceType, compositeImplementationType, currentParameters, composition)); } - if (implementations.FirstOrDefault() is not { } implementationType || implementations.Count > 1) + if (_checkTypeProperties.MapToSingleFittingImplementation(interfaceType) is not { } implementationType) { return interfaceType.NullableAnnotation == NullableAnnotation.Annotated - ? (new NullResolution(RootReferenceGenerator.Generate(interfaceType), interfaceType.FullName()), null) // todo warning - : (new ErrorTreeItem(implementations.Count switch - { - 0 => $"[{interfaceType.FullName()}] Interface: No implementation found", - > 1 => $"[{interfaceType.FullName()}] Interface: more than one implementation found", - _ => - $"[{interfaceType.FullName()}] Interface: Found single implementation {implementations[0].FullName()} is not a named type symbol" - }), - null); + ? (new NullResolution(RootReferenceGenerator.Generate(interfaceType), interfaceType.FullName()), null) // todo warning + : (new ErrorTreeItem($"[{interfaceType.FullName()}] Interface: Multiple or no implementations where a single is required"), null); } - return CreateInterface(new CreateInterfaceParameter( + return SwitchInterfaceWithoutComposition(new CreateInterfaceParameter( interfaceType, implementationType, currentParameters)); } - private (Resolvable, ITaskConsumableResolution?) SwitchInterfaceForSpecificImplementation( - SwitchInterfaceForSpecificImplementationParameter parameter) - { - var (interfaceType, implementationType, currentParameters) = parameter; - - var nextParameter = new CreateInterfaceParameter( - interfaceType, - implementationType, - currentParameters); - - (Resolvable, ITaskConsumableResolution?) ret = _checkTypeProperties.ShouldBeScopeRoot(implementationType) switch - { - ScopeLevel.TransientScope => (_rangeResolutionBaseBuilder.CreateTransientScopeRootResolution( - nextParameter, - interfaceType, - currentParameters), null), - ScopeLevel.Scope => (_rangeResolutionBaseBuilder.CreateScopeRootResolution( - nextParameter, - interfaceType, - currentParameters), null), - _ => CreateInterface(nextParameter) - }; - - if (ret.Item1 is ScopeRootResolution { ScopeRootFunction: IAwaitableResolution awaitableResolution }) - _synchronicityDecisionMaker.Register(awaitableResolution); - - if (ret.Item1 is TransientScopeRootResolution { ScopeRootFunction: IAwaitableResolution awaitableResolution0 }) - _synchronicityDecisionMaker.Register(awaitableResolution0); - - if (ret.Item1 is ScopeRootResolution { ScopeRootFunction: ITaskConsumableResolution taskConsumableResolution }) - ret.Item2 = taskConsumableResolution; - - if (ret.Item1 is TransientScopeRootResolution { ScopeRootFunction: ITaskConsumableResolution taskConsumableResolution0 }) - ret.Item2 = taskConsumableResolution0; - - return ret; - } - - protected (InterfaceResolution, ITaskConsumableResolution?) CreateInterface(CreateInterfaceParameter parameter) + private (InterfaceResolution, ITaskConsumableResolution?) SwitchInterfaceWithoutComposition(CreateInterfaceParameter parameter) { var (interfaceType, implementationType, currentParameters) = parameter; var shouldBeDecorated = _checkTypeProperties.ShouldBeDecorated(interfaceType); - var nextParameter = parameter switch + var (nextResolvable, _) = parameter switch { - CreateInterfaceParameterAsComposition asComposition => new SwitchImplementationParameterWithComposition( + CreateInterfaceParameterAsComposition asComposition => SwitchImplementation(new SwitchImplementationParameterWithComposition( asComposition.Composition.CompositeType, currentParameters, - asComposition.Composition), - _ => new SwitchImplementationParameter( + asComposition.Composition)), + _ => SwitchClass(new SwitchClassParameter( implementationType, - currentParameters) + currentParameters)) }; var currentInterfaceResolution = new InterfaceResolution( RootReferenceGenerator.Generate(interfaceType), interfaceType.FullName(), - SwitchImplementation(nextParameter).Item1); + nextResolvable); if (shouldBeDecorated) { @@ -617,22 +530,7 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup private (Resolvable, ITaskConsumableResolution?) SwitchClass(SwitchClassParameter parameter) { - var (typeSymbol, currentParameters) = parameter; - var implementations = _checkTypeProperties - .MapToImplementations(typeSymbol); - var implementationType = implementations.FirstOrDefault(); - if (implementationType is not { } || implementations.Count > 1) - { - return typeSymbol.NullableAnnotation == NullableAnnotation.Annotated - ? (new NullResolution(RootReferenceGenerator.Generate(typeSymbol), typeSymbol.FullName()), null) // todo warning - : (new ErrorTreeItem(implementations.Count switch - { - 0 => $"[{typeSymbol.FullName()}] Class: No implementation found", - > 1 => $"[{typeSymbol.FullName()}] Class: more than one implementation found", - _ => $"[{typeSymbol.FullName()}] Class: Found single implementation{implementations[0].FullName()} is not a named type symbol" - }), - null); - } + var (implementationType, currentParameters) = parameter; var nextParameter = new SwitchImplementationParameter( implementationType, @@ -785,7 +683,7 @@ false when initializationMethod.ReturnType.Equals(_wellKnownTypes.ValueTask, Sym var resolution = new ConstructorResolution( RootReferenceGenerator.Generate(implementationType), - implementationType.FullName(), + implementationType.FullName(SymbolDisplayMiscellaneousOptions.None), GetDisposalTypeFor(implementationType), new ReadOnlyCollection<(string Name, Resolvable Dependency)>(constructor .Parameters diff --git a/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs index 522219e5..c61bb184 100644 --- a/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs @@ -6,13 +6,12 @@ internal interface IScopeRootCreateFunctionResolutionBuilder : IFunctionResoluti internal class ScopeRootCreateFunctionResolutionBuilder : FunctionResolutionBuilder, IScopeRootCreateFunctionResolutionBuilder { - private readonly IRangeResolutionBaseBuilder _rangeResolutionBaseBuilder; - private readonly IScopeRootParameter _scopeRootParameter; + private readonly SwitchImplementationParameter _parameter; public ScopeRootCreateFunctionResolutionBuilder( // parameter IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, - IScopeRootParameter scopeRootParameter, + SwitchImplementationParameter parameter, IFunctionResolutionSynchronicityDecisionMaker synchronicityDecisionMaker, @@ -20,23 +19,16 @@ public ScopeRootCreateFunctionResolutionBuilder( WellKnownTypes wellKnownTypes, IReferenceGeneratorFactory referenceGeneratorFactory, Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) - : base(rangeResolutionBaseBuilder, scopeRootParameter.ReturnType, scopeRootParameter.CurrentParameters, synchronicityDecisionMaker, wellKnownTypes, referenceGeneratorFactory, localFunctionResolutionBuilderFactory) + : base(rangeResolutionBaseBuilder, parameter.ReturnType, parameter.CurrentParameters, synchronicityDecisionMaker, wellKnownTypes, referenceGeneratorFactory, localFunctionResolutionBuilderFactory) { - _rangeResolutionBaseBuilder = rangeResolutionBaseBuilder; - _scopeRootParameter = scopeRootParameter; + _parameter = parameter; Name = RootReferenceGenerator.Generate("Create"); } protected override string Name { get; } - protected override Resolvable CreateResolvable() => _scopeRootParameter switch - { - CreateInterfaceParameter createInterfaceParameter => CreateInterface(createInterfaceParameter).Item1, - SwitchImplementationParameter switchImplementationParameter => SwitchImplementation(switchImplementationParameter).Item1, - SwitchInterfaceAfterScopeRootParameter switchInterfaceAfterScopeRootParameter => SwitchInterfaceAfterScopeRoot(switchInterfaceAfterScopeRootParameter).Item1, - _ => throw new ArgumentOutOfRangeException(nameof(_scopeRootParameter)) - }; + protected override Resolvable CreateResolvable() => SwitchImplementation(_parameter).Item1; public override FunctionResolution Build() { diff --git a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs index 9ee40ef0..b45dcca5 100644 --- a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs +++ b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs @@ -18,12 +18,12 @@ MultiSynchronicityFunctionCallResolution CreateScopeInstanceReferenceResolution( ForConstructorParameter parameter); TransientScopeRootResolution CreateTransientScopeRootResolution( - IScopeRootParameter parameter, + SwitchImplementationParameter parameter, INamedTypeSymbol rootType, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters); ScopeRootResolution CreateScopeRootResolution( - IScopeRootParameter parameter, + SwitchImplementationParameter parameter, INamedTypeSymbol rootType, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters); @@ -81,12 +81,12 @@ public MultiSynchronicityFunctionCallResolution CreateScopeInstanceReferenceReso new (_synchronicityDecisionMakerFactory)); public abstract TransientScopeRootResolution CreateTransientScopeRootResolution( - IScopeRootParameter parameter, + SwitchImplementationParameter parameter, INamedTypeSymbol rootType, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters); public abstract ScopeRootResolution CreateScopeRootResolution( - IScopeRootParameter parameter, + SwitchImplementationParameter parameter, INamedTypeSymbol rootType, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters); diff --git a/Main/ResolutionBuilding/ResolutionDtos.cs b/Main/ResolutionBuilding/ResolutionDtos.cs index da44632e..bb8e894c 100644 --- a/Main/ResolutionBuilding/ResolutionDtos.cs +++ b/Main/ResolutionBuilding/ResolutionDtos.cs @@ -45,27 +45,9 @@ internal record SwitchInterfaceParameter( IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentFuncParameters) : Parameter; -internal interface IScopeRootParameter -{ - INamedTypeSymbol ReturnType { get; } - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters { get; } - - string KeySuffix(); - string RootFunctionSuffix(); -} - internal record SwitchInterfaceAfterScopeRootParameter( - INamedTypeSymbol InterfaceType, - IReadOnlyList ImplementationTypes, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters) - : IScopeRootParameter -{ - public INamedTypeSymbol ReturnType => InterfaceType; - - public string KeySuffix() => ":::InterfaceAfterRoot"; - - public string RootFunctionSuffix() => "_InterfaceAfterRoot"; -} + INamedTypeSymbol InterfaceType, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters); internal record SwitchInterfaceForSpecificImplementationParameter( @@ -74,29 +56,16 @@ internal record SwitchInterfaceForSpecificImplementationParameter( IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters); internal record CreateInterfaceParameter( - INamedTypeSymbol InterfaceType, - INamedTypeSymbol ImplementationType, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters) - : IScopeRootParameter -{ - public INamedTypeSymbol ReturnType => InterfaceType; - - public virtual string KeySuffix() => ":::NormalInterface"; - - public virtual string RootFunctionSuffix() => "_NormalInterface"; -} + INamedTypeSymbol InterfaceType, + INamedTypeSymbol ImplementationType, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters); internal record CreateInterfaceParameterAsComposition( INamedTypeSymbol InterfaceType, INamedTypeSymbol ImplementationType, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters, CompositionInterfaceExtension Composition) - : CreateInterfaceParameter(InterfaceType, ImplementationType, CurrentParameters) -{ - public override string KeySuffix() => ":::CompositeInterface"; - - public override string RootFunctionSuffix() => "_CompositeInterface"; -} + : CreateInterfaceParameter(InterfaceType, ImplementationType, CurrentParameters); internal record SwitchClassParameter( INamedTypeSymbol TypeSymbol, @@ -105,13 +74,8 @@ internal record SwitchClassParameter( internal record SwitchImplementationParameter( INamedTypeSymbol ImplementationType, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters) - : IScopeRootParameter { public INamedTypeSymbol ReturnType => ImplementationType; - - public virtual string KeySuffix() => ":::Implementation"; - - public virtual string RootFunctionSuffix() => ""; } internal record SwitchImplementationParameterWithDecoration( diff --git a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs index c489d3b9..392d67ca 100644 --- a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs @@ -6,7 +6,7 @@ namespace MrMeeseeks.DIE.ResolutionBuilding; internal interface IScopeResolutionBuilder : IRangeResolutionBaseBuilder, IResolutionBuilder { ScopeRootResolution AddCreateResolveFunction( - IScopeRootParameter parameter, + SwitchImplementationParameter parameter, INamedTypeSymbol rootType, string containerInstanceScopeReference, string transientInstanceScopeReference, @@ -18,7 +18,7 @@ internal class ScopeResolutionBuilder : RangeResolutionBaseBuilder, IScopeResolu private readonly IContainerResolutionBuilder _containerResolutionBuilder; private readonly ITransientScopeInterfaceResolutionBuilder _transientScopeInterfaceResolutionBuilder; private readonly IScopeManager _scopeManager; - private readonly Func _scopeRootCreateFunctionResolutionBuilderFactory; + private readonly Func _scopeRootCreateFunctionResolutionBuilderFactory; private readonly string _containerReference; private readonly string _containerParameterReference; private readonly string _transientScopeReference; @@ -38,7 +38,7 @@ internal ScopeResolutionBuilder( // dependencies WellKnownTypes wellKnownTypes, IReferenceGeneratorFactory referenceGeneratorFactory, - Func scopeRootCreateFunctionResolutionBuilderFactory, + Func scopeRootCreateFunctionResolutionBuilderFactory, Func rangedFunctionGroupResolutionBuilderFactory, Func synchronicityDecisionMakerFactory) : base( @@ -67,7 +67,7 @@ public override MultiSynchronicityFunctionCallResolution CreateTransientScopeIns _transientScopeInterfaceResolutionBuilder.CreateTransientScopeInstanceReferenceResolution(parameter, _transientScopeReference); public override TransientScopeRootResolution CreateTransientScopeRootResolution( - IScopeRootParameter parameter, + SwitchImplementationParameter parameter, INamedTypeSymbol rootType, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) => _scopeManager @@ -79,7 +79,7 @@ public override TransientScopeRootResolution CreateTransientScopeRootResolution( currentParameters); public override ScopeRootResolution CreateScopeRootResolution( - IScopeRootParameter parameter, + SwitchImplementationParameter parameter, INamedTypeSymbol rootType, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) => _scopeManager @@ -98,13 +98,13 @@ public override ScopeRootResolution CreateScopeRootResolution( || RangedInstanceReferenceResolutions.Values.Any(r => r.HasWorkToDo); public ScopeRootResolution AddCreateResolveFunction( - IScopeRootParameter parameter, + SwitchImplementationParameter parameter, INamedTypeSymbol rootType, string containerInstanceScopeReference, string transientInstanceScopeReference, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) { - var key = $"{rootType.FullName()}{parameter.KeySuffix()}"; + var key = rootType.FullName(); if (!_scopeRootFunctionResolutions.TryGetValue( key, out var function)) diff --git a/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs b/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs index 4a05eda7..74838d0d 100644 --- a/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs @@ -6,7 +6,7 @@ namespace MrMeeseeks.DIE.ResolutionBuilding; internal interface ITransientScopeResolutionBuilder : ITransientScopeImplementationResolutionBuilder, IRangeResolutionBaseBuilder, IResolutionBuilder { TransientScopeRootResolution AddCreateResolveFunction( - IScopeRootParameter parameter, + SwitchImplementationParameter parameter, INamedTypeSymbol rootType, string containerInstanceScopeReference, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters); @@ -17,7 +17,7 @@ internal class TransientScopeResolutionBuilder : RangeResolutionBaseBuilder, ITr private readonly IContainerResolutionBuilder _containerResolutionBuilder; private readonly ITransientScopeInterfaceResolutionBuilder _transientScopeInterfaceResolutionBuilder; private readonly IScopeManager _scopeManager; - private readonly Func _scopeRootCreateFunctionResolutionBuilderFactory; + private readonly Func _scopeRootCreateFunctionResolutionBuilderFactory; private readonly string _containerReference; private readonly string _containerParameterReference; @@ -35,7 +35,7 @@ internal TransientScopeResolutionBuilder( // dependencies WellKnownTypes wellKnownTypes, IReferenceGeneratorFactory referenceGeneratorFactory, - Func scopeRootCreateFunctionResolutionBuilderFactory, + Func scopeRootCreateFunctionResolutionBuilderFactory, Func rangedFunctionGroupResolutionBuilderFactory, Func synchronicityDecisionMakerFactory) : base( @@ -62,7 +62,7 @@ public override MultiSynchronicityFunctionCallResolution CreateTransientScopeIns _transientScopeInterfaceResolutionBuilder.CreateTransientScopeInstanceReferenceResolution(parameter, "this"); public override TransientScopeRootResolution CreateTransientScopeRootResolution( - IScopeRootParameter parameter, + SwitchImplementationParameter parameter, INamedTypeSymbol rootType, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) => _scopeManager @@ -74,7 +74,7 @@ public override TransientScopeRootResolution CreateTransientScopeRootResolution( currentParameters); public override ScopeRootResolution CreateScopeRootResolution( - IScopeRootParameter parameter, + SwitchImplementationParameter parameter, INamedTypeSymbol rootType, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) => _scopeManager @@ -93,12 +93,12 @@ public override ScopeRootResolution CreateScopeRootResolution( || RangedInstanceReferenceResolutions.Values.Any(r => r.HasWorkToDo); public TransientScopeRootResolution AddCreateResolveFunction( - IScopeRootParameter parameter, + SwitchImplementationParameter parameter, INamedTypeSymbol rootType, string containerInstanceScopeReference, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) { - var key = $"{rootType.FullName()}{parameter.KeySuffix()}"; + var key = rootType.FullName(); if (!_transientScopeRootFunctionResolutions.TryGetValue( key, out var function)) diff --git a/Main/RoslynExtensions.cs b/Main/RoslynExtensions.cs index 5c71d4c4..a57dbef6 100644 --- a/Main/RoslynExtensions.cs +++ b/Main/RoslynExtensions.cs @@ -40,14 +40,14 @@ internal static bool IsAccessibleInternally(this ITypeSymbol type) } // Picked from https://github.com/YairHalberstadt/stronginject Thank you! - public static string FullName(this ITypeSymbol type) => + public static string FullName(this ITypeSymbol type, SymbolDisplayMiscellaneousOptions miscellaneousOptions = SymbolDisplayMiscellaneousOptions.IncludeNullableReferenceTypeModifier) => type.ToDisplayString(new SymbolDisplayFormat( globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Included, typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces, genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters, parameterOptions: SymbolDisplayParameterOptions.IncludeType | SymbolDisplayParameterOptions.IncludeParamsRefOut, memberOptions: SymbolDisplayMemberOptions.IncludeRef, - miscellaneousOptions: SymbolDisplayMiscellaneousOptions.IncludeNullableReferenceTypeModifier)); + miscellaneousOptions: miscellaneousOptions)); // Picked from https://github.com/YairHalberstadt/stronginject Thank you! internal static string FullName(this INamespaceSymbol @namespace) => diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index a51bf743..834238a0 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -133,9 +133,9 @@ IContainerCreateFunctionResolutionBuilder ContainerCreateFunctionResolutionBuild IScopeRootCreateFunctionResolutionBuilder ScopeRootCreateFunctionResolutionBuilderFactory( IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, - IScopeRootParameter scopeRootParameter) => new ScopeRootCreateFunctionResolutionBuilder( + SwitchImplementationParameter parameter) => new ScopeRootCreateFunctionResolutionBuilder( rangeResolutionBaseBuilder, - scopeRootParameter, + parameter, FunctionResolutionSynchronicityDecisionMakerFactory(), wellKnownTypes, diff --git a/Main/WellKnownTypes.cs b/Main/WellKnownTypes.cs index 4048b1c3..2aeee846 100644 --- a/Main/WellKnownTypes.cs +++ b/Main/WellKnownTypes.cs @@ -17,7 +17,7 @@ internal record WellKnownTypes( INamedTypeSymbol DecoratorAggregationAttribute, INamedTypeSymbol CompositeAggregationAttribute, INamedTypeSymbol GenericParameterSubstituteAggregationAttribute, - INamedTypeSymbol GenericParameterSubstituteChoiceAttribute, + INamedTypeSymbol GenericParameterChoiceAttribute, INamedTypeSymbol DecoratorSequenceChoiceAttribute, INamedTypeSymbol ConstructorChoiceAttribute, INamedTypeSymbol TypeInitializerAttribute, @@ -35,7 +35,7 @@ internal record WellKnownTypes( INamedTypeSymbol FilterDecoratorAggregationAttribute, INamedTypeSymbol FilterCompositeAggregationAttribute, INamedTypeSymbol FilterGenericParameterSubstituteAggregationAttribute, - INamedTypeSymbol FilterGenericParameterSubstituteChoiceAttribute, + INamedTypeSymbol FilterGenericParameterChoiceAttribute, INamedTypeSymbol FilterDecoratorSequenceChoiceAttribute, INamedTypeSymbol FilterConstructorChoiceAttribute, INamedTypeSymbol FilterTypeInitializerAttribute, @@ -136,11 +136,11 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK var filterGenericParameterSubstituteAggregationAttribute = compilation .GetTypeByMetadataName(typeof(FilterGenericParameterSubstituteAggregationAttribute).FullName ?? ""); - var genericParameterSubstituteChoiceAttribute = compilation - .GetTypeByMetadataName(typeof(GenericParameterSubstituteChoiceAttribute).FullName ?? ""); + var genericParameterChoiceAttribute = compilation + .GetTypeByMetadataName(typeof(GenericParameterChoiceAttribute).FullName ?? ""); - var filterGenericParameterSubstituteChoiceAttribute = compilation - .GetTypeByMetadataName(typeof(FilterGenericParameterSubstituteChoiceAttribute).FullName ?? ""); + var filterGenericParameterChoiceAttribute = compilation + .GetTypeByMetadataName(typeof(FilterGenericParameterChoiceAttribute).FullName ?? ""); var decoratorSequenceChoiceAttribute = compilation .GetTypeByMetadataName(typeof(DecoratorSequenceChoiceAttribute).FullName ?? ""); @@ -219,7 +219,7 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK && decoratorAggregationAttribute is not null && compositeAggregationAttribute is not null && genericParameterSubstituteAggregationAttribute is not null - && genericParameterSubstituteChoiceAttribute is not null + && genericParameterChoiceAttribute is not null && decoratorSequenceChoiceAttribute is not null && constructorChoiceAttribute is not null && typeInitializerAttribute is not null @@ -237,7 +237,7 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK && filterDecoratorAggregationAttribute is not null && filterCompositeAggregationAttribute is not null && filterGenericParameterSubstituteAggregationAttribute is not null - && filterGenericParameterSubstituteChoiceAttribute is not null + && filterGenericParameterChoiceAttribute is not null && filterDecoratorSequenceChoiceAttribute is not null && filterConstructorChoiceAttribute is not null && filterTypeInitializerAttribute is not null @@ -278,7 +278,7 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK DecoratorAggregationAttribute: decoratorAggregationAttribute, CompositeAggregationAttribute: compositeAggregationAttribute, GenericParameterSubstituteAggregationAttribute: genericParameterSubstituteAggregationAttribute, - GenericParameterSubstituteChoiceAttribute: genericParameterSubstituteChoiceAttribute, + GenericParameterChoiceAttribute: genericParameterChoiceAttribute, DecoratorSequenceChoiceAttribute: decoratorSequenceChoiceAttribute, ConstructorChoiceAttribute: constructorChoiceAttribute, TypeInitializerAttribute: typeInitializerAttribute, @@ -296,7 +296,7 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK FilterDecoratorAggregationAttribute: filterDecoratorAggregationAttribute, FilterCompositeAggregationAttribute: filterCompositeAggregationAttribute, FilterGenericParameterSubstituteAggregationAttribute: filterGenericParameterSubstituteAggregationAttribute, - FilterGenericParameterSubstituteChoiceAttribute: filterGenericParameterSubstituteChoiceAttribute, + FilterGenericParameterChoiceAttribute: filterGenericParameterChoiceAttribute, FilterDecoratorSequenceChoiceAttribute: filterDecoratorSequenceChoiceAttribute, FilterConstructorChoiceAttribute: filterConstructorChoiceAttribute, FilterTypeInitializerAttribute: filterTypeInitializerAttribute, diff --git a/Sample/Context.cs b/Sample/Context.cs index a60f1ab9..dd0f2803 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -1,14 +1,14 @@ -using System.Threading.Tasks; +using System.Collections.Generic; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration; using MrMeeseeks.DIE.Sample; - -namespace MrMeeseeks.DIE.Test.Generics.Interface_SingleAndImplementationDoubleButOneFixed; -internal interface IInterface {} +namespace MrMeeseeks.DIE.Test.Generics.SubstituteCollection.Double; -internal abstract class BaseClass : IInterface {} +internal interface IInterface {} -internal class Class : BaseClass {} +internal class Class : IInterface {} -[CreateFunction(typeof(IInterface), "Create")] +[GenericParameterSubstituteAggregation(typeof(Class<,>), "T1", typeof(int), typeof(string))] +[CreateFunction(typeof(IReadOnlyList>), "Create")] internal partial class Container {} \ No newline at end of file diff --git a/SampleChild/Class1.cs b/SampleChild/Class1.cs deleted file mode 100644 index 2fdda502..00000000 --- a/SampleChild/Class1.cs +++ /dev/null @@ -1,30 +0,0 @@ -namespace MrMeeseeks.DIE.SampleChild; - -public interface IClass {} - -public class Class : IClass -{ - public Class() - { - } - - public Class(int i) - { - - } -} - -public interface IClassToo {} - -public class ClassToo : IClassToo -{ - public ClassToo() - { - - } - - public ClassToo(int i) - { - - } -} \ No newline at end of file diff --git a/SampleChild/Public.cs b/SampleChild/Public.cs new file mode 100644 index 00000000..338213e8 --- /dev/null +++ b/SampleChild/Public.cs @@ -0,0 +1,124 @@ +namespace MrMeeseeks.DIE.SampleChild; + +public interface IClass {} + +public class Class : IClass +{ + public Class() + { + } + + public Class(int i) + { + + } +} + +public interface IClassToo {} + +public class ClassToo : IClassToo +{ + public ClassToo() + { + + } + + public ClassToo(int i) + { + + } +} + +public interface IClass {} + +public class Class : IClass +{ + public Class() + { + } + + public Class(int i) + { + + } +} + +public static class StaticParent +{ + public class Class : IClass + { + public Class() + { + } + + public Class(int i) + { + + } + } + + public class ClassToo : IClassToo + { + public ClassToo() + { + + } + + public ClassToo(int i) + { + + } + } + + public class Class : IClass + { + public Class() + { + } + + public Class(int i) + { + + } + } +} + +public class Parent +{ + public class Class : IClass + { + public Class() + { + } + + public Class(int i) + { + + } + } + + public class ClassToo : IClassToo + { + public ClassToo() + { + + } + + public ClassToo(int i) + { + + } + } + + public class Class : IClass + { + public Class() + { + } + + public Class(int i) + { + + } + } +} \ No newline at end of file diff --git a/SampleChild/lnternal.cs b/SampleChild/lnternal.cs new file mode 100644 index 00000000..0fe66251 --- /dev/null +++ b/SampleChild/lnternal.cs @@ -0,0 +1,125 @@ +namespace MrMeeseeks.DIE.SampleChild.Internal; + +internal interface IClass {} + +internal class Class : IClass +{ + internal Class() + { + } + + internal Class(int i) + { + + } +} + +internal interface IClassToo {} + +internal class ClassToo : IClassToo +{ + internal ClassToo() + { + + } + + internal ClassToo(int i) + { + + } +} + +internal interface IClass {} + +internal class Class : IClass +{ + internal Class() + { + } + + internal Class(int i) + { + + } +} + +internal static class StaticParent +{ + internal class Class : IClass + { + internal Class() + { + } + + internal Class(int i) + { + + } + } + + internal class ClassToo : IClassToo + { + internal ClassToo() + { + + } + + internal ClassToo(int i) + { + + } + } + + internal class Class : IClass + { + internal Class() + { + } + + internal Class(int i) + { + + } + } +} + +internal class Parent +{ + internal Parent() {} + internal class Class : IClass + { + internal Class() + { + } + + internal Class(int i) + { + + } + } + + internal class ClassToo : IClassToo + { + internal ClassToo() + { + + } + + internal ClassToo(int i) + { + + } + } + + internal class Class : IClass + { + internal Class() + { + } + + internal Class(int i) + { + + } + } +} \ No newline at end of file diff --git a/Test/Composite/Container.cs b/Test/Composite/Container.cs new file mode 100644 index 00000000..dadaefe3 --- /dev/null +++ b/Test/Composite/Container.cs @@ -0,0 +1,69 @@ +using System.Collections.Generic; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Composite.Container; + +internal interface IInterface +{ + IReadOnlyList Composites { get; } +} + +internal class BasisA : IInterface, IContainerInstance +{ + public IReadOnlyList Composites => new List { this }; +} + +internal class BasisB : IInterface, IContainerInstance +{ + public IReadOnlyList Composites => new List { this }; +} + +internal class Composite : IInterface, IComposite +{ + public Composite(IReadOnlyList composites) => + Composites = composites; + + public IReadOnlyList Composites { get; } +} + +[CreateFunction(typeof(IInterface), "CreateDep")] +[CreateFunction(typeof(IReadOnlyList), "CreateCollection")] +internal partial class Container +{ + +} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var composite = container.CreateDep(); + foreach (var compositeComposite in composite.Composites) + { + Assert.NotEqual(composite, compositeComposite); + var type = compositeComposite.GetType(); + Assert.True(type == typeof(BasisA) || type == typeof(BasisB)); + } + var nextComposite = container.CreateDep(); + Assert.Equal(composite, nextComposite); + } + + [Fact] + public void TestList() + { + var container = new Container(); + var composites = container.CreateCollection(); + foreach (var compositeComposite in composites) + { + var type = compositeComposite.GetType(); + Assert.True(type == typeof(BasisA) || type == typeof(BasisB)); + } + Assert.Equal(2, composites.Count); + var nextComposites = container.CreateCollection(); + Assert.Equal(composites[0], nextComposites[0]); + Assert.Equal(composites[1], nextComposites[1]); + } +} \ No newline at end of file diff --git a/Test/Composite/Decorated.cs b/Test/Composite/Decorated.cs new file mode 100644 index 00000000..20c81567 --- /dev/null +++ b/Test/Composite/Decorated.cs @@ -0,0 +1,96 @@ +using System.Collections.Generic; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Composite.Decorated; + +internal interface IInterface +{ + IReadOnlyList Composites { get; } + IInterface Decorated { get; } +} + +internal class DecoratorA : IInterface, IDecorator +{ + public IReadOnlyList Composites => Decorated.Composites; + public IInterface Decorated { get; } + + public DecoratorA( + IInterface decorated) => + Decorated = decorated; +} + +internal class DecoratorB : IInterface, IDecorator +{ + public IReadOnlyList Composites => Decorated.Composites; + public IInterface Decorated { get; } + + public DecoratorB( + IInterface decorated) => + Decorated = decorated; +} + +internal class BasisA : IInterface +{ + public IReadOnlyList Composites => new List { this }; + public IInterface Decorated => this; +} + +internal class BasisB : IInterface +{ + public IReadOnlyList Composites => new List { this }; + public IInterface Decorated => this; +} + +internal class Composite : IInterface, IComposite +{ + public Composite(IReadOnlyList composites) => + Composites = composites; + + public IReadOnlyList Composites { get; } + public IInterface Decorated => this; +} + +[DecoratorSequenceChoice(typeof(IInterface), typeof(DecoratorA), typeof(DecoratorB))] +[DecoratorSequenceChoice(typeof(Composite), typeof(DecoratorB))] +[CreateFunction(typeof(IInterface), "CreateDep")] +[CreateFunction(typeof(IReadOnlyList), "CreateCollection")] +internal partial class Container +{ + +} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var composite = container.CreateDep(); + Assert.IsType(composite); + Assert.IsType(composite.Decorated); + foreach (var compositeComposite in composite.Composites) + { + Assert.NotEqual(composite, compositeComposite); + Assert.IsType(compositeComposite); + Assert.IsType(compositeComposite.Decorated); + var baseImpl = compositeComposite.Decorated.Decorated; + Assert.True(baseImpl.GetType() == typeof(BasisA) || baseImpl.GetType() == typeof(BasisB)); + } + } + + [Fact] + public void TestList() + { + var container = new Container(); + var composites = container.CreateCollection(); + foreach (var compositeComposite in composites) + { + Assert.IsType(compositeComposite); + Assert.IsType(compositeComposite.Decorated); + var baseImpl = compositeComposite.Decorated.Decorated; + Assert.True(baseImpl.GetType() == typeof(BasisA) || baseImpl.GetType() == typeof(BasisB)); + } + Assert.Equal(2, composites.Count); + } +} \ No newline at end of file diff --git a/Test/Composite/MixedScoping.cs b/Test/Composite/MixedScoping.cs new file mode 100644 index 00000000..ba5fe20b --- /dev/null +++ b/Test/Composite/MixedScoping.cs @@ -0,0 +1,69 @@ +using System.Collections.Generic; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Composite.MixedScoping; + +internal interface IInterface +{ + IReadOnlyList Composites { get; } +} + +internal class BasisA : IInterface, IContainerInstance +{ + public IReadOnlyList Composites => new List { this }; +} + +internal class BasisB : IInterface +{ + public IReadOnlyList Composites => new List { this }; +} + +internal class Composite : IInterface, IComposite +{ + public Composite(IReadOnlyList composites) => + Composites = composites; + + public IReadOnlyList Composites { get; } +} + +[CreateFunction(typeof(IInterface), "CreateDep")] +[CreateFunction(typeof(IReadOnlyList), "CreateCollection")] +internal partial class Container +{ + +} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var composite = container.CreateDep(); + foreach (var compositeComposite in composite.Composites) + { + Assert.NotEqual(composite, compositeComposite); + var type = compositeComposite.GetType(); + Assert.True(type == typeof(BasisA) || type == typeof(BasisB)); + } + var nextComposite = container.CreateDep(); + Assert.NotEqual(composite, nextComposite); + } + + [Fact] + public void TestList() + { + var container = new Container(); + var composites = container.CreateCollection(); + foreach (var compositeComposite in composites) + { + var type = compositeComposite.GetType(); + Assert.True(type == typeof(BasisA) || type == typeof(BasisB)); + } + Assert.Equal(2, composites.Count); + var nextComposites = container.CreateCollection(); + Assert.True(composites[0].Equals(nextComposites[0]) && !composites[1].Equals(nextComposites[1]) + || composites[1].Equals(nextComposites[1]) && !composites[0].Equals(nextComposites[0])); + } +} \ No newline at end of file diff --git a/Test/Composite/Normal.cs b/Test/Composite/Normal.cs new file mode 100644 index 00000000..5555287e --- /dev/null +++ b/Test/Composite/Normal.cs @@ -0,0 +1,64 @@ +using System.Collections.Generic; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Composite.Normal; + +internal interface IInterface +{ + IReadOnlyList Composites { get; } +} + +internal class BasisA : IInterface +{ + public IReadOnlyList Composites => new List { this }; +} + +internal class BasisB : IInterface +{ + public IReadOnlyList Composites => new List { this }; +} + +internal class Composite : IInterface, IComposite +{ + public Composite(IReadOnlyList composites) => + Composites = composites; + + public IReadOnlyList Composites { get; } +} + +[CreateFunction(typeof(IInterface), "CreateDep")] +[CreateFunction(typeof(IReadOnlyList), "CreateCollection")] +internal partial class Container +{ + +} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var composite = container.CreateDep(); + foreach (var compositeComposite in composite.Composites) + { + Assert.NotEqual(composite, compositeComposite); + var type = compositeComposite.GetType(); + Assert.True(type == typeof(BasisA) || type == typeof(BasisB)); + } + } + + [Fact] + public void TestList() + { + var container = new Container(); + var composites = container.CreateCollection(); + foreach (var compositeComposite in composites) + { + var type = compositeComposite.GetType(); + Assert.True(type == typeof(BasisA) || type == typeof(BasisB)); + } + Assert.Equal(2, composites.Count); + } +} \ No newline at end of file diff --git a/Test/Composite/ScopeRoot.cs b/Test/Composite/ScopeRoot.cs new file mode 100644 index 00000000..ac396bc6 --- /dev/null +++ b/Test/Composite/ScopeRoot.cs @@ -0,0 +1,82 @@ +using System.Collections.Generic; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Composite.ScopeRoot; + +internal interface IInterface +{ + IReadOnlyList Composites { get; } + IDependency Dependency { get; } +} + +internal interface IDependency { } + +internal class Dependency : IDependency, IScopeInstance { } + +internal class BasisA : IInterface, IScopeRoot +{ + public BasisA(IDependency dependency) => Dependency = dependency; + + public IReadOnlyList Composites => new List { this }; + public IDependency Dependency { get; } +} + +internal class BasisB : IInterface +{ + public BasisB(IDependency dependency) => Dependency = dependency; + + public IReadOnlyList Composites => new List { this }; + public IDependency Dependency { get; } +} + +internal class Composite : IInterface, IComposite +{ + public Composite(IReadOnlyList composites, IDependency dependency) + { + Composites = composites; + Dependency = dependency; + } + + public IReadOnlyList Composites { get; } + public IDependency Dependency { get; } +} + +[CreateFunction(typeof(IInterface), "CreateDep")] +[CreateFunction(typeof(IReadOnlyList), "CreateCollection")] +internal partial class Container +{ + +} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var composite = container.CreateDep(); + foreach (var compositeComposite in composite.Composites) + { + Assert.NotEqual(composite, compositeComposite); + var type = compositeComposite.GetType(); + Assert.True(type == typeof(BasisA) || type == typeof(BasisB)); + } + Assert.Equal(2, composite.Composites.Count); + Assert.NotEqual(composite.Composites[0].Dependency, composite.Composites[1].Dependency); + } + + [Fact] + public void TestList() + { + var container = new Container(); + var composites = container.CreateCollection(); + foreach (var compositeComposite in composites) + { + var type = compositeComposite.GetType(); + Assert.True(type == typeof(BasisA) || type == typeof(BasisB)); + } + Assert.Equal(2, composites.Count); + Assert.NotEqual(composites[0].Dependency, composites[1].Dependency); + } +} \ No newline at end of file diff --git a/Test/CompositeTests.cs b/Test/CompositeTests.cs deleted file mode 100644 index 2e6d192f..00000000 --- a/Test/CompositeTests.cs +++ /dev/null @@ -1,363 +0,0 @@ -using System.Collections.Generic; -using MrMeeseeks.DIE.Configuration; -using MrMeeseeks.DIE.Test; -using Xunit; - -[assembly:DecoratorSequenceChoice(typeof(ICompositeDecorated), typeof(CompositeDecoratedDecoratorA), typeof(CompositeDecoratedDecoratorB))] -[assembly:DecoratorSequenceChoice(typeof(CompositeDecorated), typeof(CompositeDecoratedDecoratorB))] - -namespace MrMeeseeks.DIE.Test; - -internal interface ICompositeNormal -{ - IReadOnlyList Composites { get; } -} - -internal class CompositeNormalBasisA : ICompositeNormal -{ - public IReadOnlyList Composites => new List { this }; -} - -internal class CompositeNormalBasisB : ICompositeNormal -{ - public IReadOnlyList Composites => new List { this }; -} - -internal class CompositeNormal : ICompositeNormal, IComposite -{ - public CompositeNormal(IReadOnlyList composites) => - Composites = composites; - - public IReadOnlyList Composites { get; } -} - -[CreateFunction(typeof(ICompositeNormal), "CreateDep")] -[CreateFunction(typeof(IReadOnlyList), "CreateCollection")] -internal partial class CompositeNormalContainer -{ - -} - -public partial class CompositeTests -{ - [Fact] - public void Normal() - { - var container = new CompositeNormalContainer(); - var composite = container.CreateDep(); - foreach (var compositeComposite in composite.Composites) - { - Assert.NotEqual(composite, compositeComposite); - var type = compositeComposite.GetType(); - Assert.True(type == typeof(CompositeNormalBasisA) || type == typeof(CompositeNormalBasisB)); - } - } - - [Fact] - public void NormalList() - { - var container = new CompositeNormalContainer(); - var composites = container.CreateCollection(); - foreach (var compositeComposite in composites) - { - var type = compositeComposite.GetType(); - Assert.True(type == typeof(CompositeNormalBasisA) || type == typeof(CompositeNormalBasisB)); - } - Assert.Equal(2, composites.Count); - } -} - -internal interface ICompositeContainerInstance -{ - IReadOnlyList Composites { get; } -} - -internal class CompositeContainerInstanceBasisA : ICompositeContainerInstance, IContainerInstance -{ - public IReadOnlyList Composites => new List { this }; -} - -internal class CompositeContainerInstanceBasisB : ICompositeContainerInstance, IContainerInstance -{ - public IReadOnlyList Composites => new List { this }; -} - -internal class CompositeContainerInstance : ICompositeContainerInstance, IComposite -{ - public CompositeContainerInstance(IReadOnlyList composites) => - Composites = composites; - - public IReadOnlyList Composites { get; } -} - -[CreateFunction(typeof(ICompositeContainerInstance), "CreateDep")] -[CreateFunction(typeof(IReadOnlyList), "CreateCollection")] -internal partial class CompositeContainerInstanceContainer -{ - -} - -public partial class CompositeTests -{ - [Fact] - public void ContainerInstance() - { - var container = new CompositeContainerInstanceContainer(); - var composite = container.CreateDep(); - foreach (var compositeComposite in composite.Composites) - { - Assert.NotEqual(composite, compositeComposite); - var type = compositeComposite.GetType(); - Assert.True(type == typeof(CompositeContainerInstanceBasisA) || type == typeof(CompositeContainerInstanceBasisB)); - } - var nextComposite = container.CreateDep(); - Assert.Equal(composite, nextComposite); - } - - [Fact] - public void ContainerInstanceList() - { - var container = new CompositeContainerInstanceContainer(); - var composites = container.CreateCollection(); - foreach (var compositeComposite in composites) - { - var type = compositeComposite.GetType(); - Assert.True(type == typeof(CompositeContainerInstanceBasisA) || type == typeof(CompositeContainerInstanceBasisB)); - } - Assert.Equal(2, composites.Count); - var nextComposites = container.CreateCollection(); - Assert.Equal(composites[0], nextComposites[0]); - Assert.Equal(composites[1], nextComposites[1]); - } -} - -internal interface ICompositeMixedScoping -{ - IReadOnlyList Composites { get; } -} - -internal class CompositeMixedScopingBasisA : ICompositeMixedScoping, IContainerInstance -{ - public IReadOnlyList Composites => new List { this }; -} - -internal class CompositeMixedScopingBasisB : ICompositeMixedScoping -{ - public IReadOnlyList Composites => new List { this }; -} - -internal class CompositeMixedScoping : ICompositeMixedScoping, IComposite -{ - public CompositeMixedScoping(IReadOnlyList composites) => - Composites = composites; - - public IReadOnlyList Composites { get; } -} - -[CreateFunction(typeof(ICompositeMixedScoping), "CreateDep")] -[CreateFunction(typeof(IReadOnlyList), "CreateCollection")] -internal partial class CompositeMixedScopingContainer -{ - -} - -public partial class CompositeTests -{ - [Fact] - public void MixedScoping() - { - var container = new CompositeMixedScopingContainer(); - var composite = container.CreateDep(); - foreach (var compositeComposite in composite.Composites) - { - Assert.NotEqual(composite, compositeComposite); - var type = compositeComposite.GetType(); - Assert.True(type == typeof(CompositeMixedScopingBasisA) || type == typeof(CompositeMixedScopingBasisB)); - } - var nextComposite = container.CreateDep(); - Assert.NotEqual(composite, nextComposite); - } - - [Fact] - public void MixedScopingList() - { - var container = new CompositeMixedScopingContainer(); - var composites = container.CreateCollection(); - foreach (var compositeComposite in composites) - { - var type = compositeComposite.GetType(); - Assert.True(type == typeof(CompositeMixedScopingBasisA) || type == typeof(CompositeMixedScopingBasisB)); - } - Assert.Equal(2, composites.Count); - var nextComposites = container.CreateCollection(); - Assert.True(composites[0].Equals(nextComposites[0]) && !composites[1].Equals(nextComposites[1]) - || composites[1].Equals(nextComposites[1]) && !composites[0].Equals(nextComposites[0])); - } -} - -internal interface ICompositeScopeRoot -{ - IReadOnlyList Composites { get; } - ICompositeScopeRootDependency Dependency { get; } -} - -internal interface ICompositeScopeRootDependency { } - -internal class CompositeScopeRootDependency : ICompositeScopeRootDependency, IScopeInstance { } - -internal class CompositeScopeRootBasisA : ICompositeScopeRoot, IScopeRoot -{ - public CompositeScopeRootBasisA(ICompositeScopeRootDependency dependency) => Dependency = dependency; - - public IReadOnlyList Composites => new List { this }; - public ICompositeScopeRootDependency Dependency { get; } -} - -internal class CompositeScopeRootBasisB : ICompositeScopeRoot -{ - public CompositeScopeRootBasisB(ICompositeScopeRootDependency dependency) => Dependency = dependency; - - public IReadOnlyList Composites => new List { this }; - public ICompositeScopeRootDependency Dependency { get; } -} - -internal class CompositeScopeRoot : ICompositeScopeRoot, IComposite -{ - public CompositeScopeRoot(IReadOnlyList composites, ICompositeScopeRootDependency dependency) - { - Composites = composites; - Dependency = dependency; - } - - public IReadOnlyList Composites { get; } - public ICompositeScopeRootDependency Dependency { get; } -} - -[CreateFunction(typeof(ICompositeScopeRoot), "CreateDep")] -[CreateFunction(typeof(IReadOnlyList), "CreateCollection")] -internal partial class CompositeScopeRootContainer -{ - -} - -public partial class CompositeTests -{ - [Fact] - public void ScopeRoot() - { - var container = new CompositeScopeRootContainer(); - var composite = container.CreateDep(); - foreach (var compositeComposite in composite.Composites) - { - Assert.NotEqual(composite, compositeComposite); - var type = compositeComposite.GetType(); - Assert.True(type == typeof(CompositeScopeRootBasisA) || type == typeof(CompositeScopeRootBasisB)); - Assert.Equal(composite.Dependency, compositeComposite.Dependency); - } - var next = container.CreateDep(); - Assert.NotEqual(composite.Dependency, next.Dependency); - } - - [Fact] - public void ScopeRootList() - { - var container = new CompositeScopeRootContainer(); - var composites = container.CreateCollection(); - foreach (var compositeComposite in composites) - { - var type = compositeComposite.GetType(); - Assert.True(type == typeof(CompositeScopeRootBasisA) || type == typeof(CompositeScopeRootBasisB)); - } - Assert.Equal(2, composites.Count); - Assert.NotEqual(composites[0].Dependency, composites[1].Dependency); - } -} - -internal interface ICompositeDecorated -{ - IReadOnlyList Composites { get; } - ICompositeDecorated Decorated { get; } -} - -internal class CompositeDecoratedDecoratorA : ICompositeDecorated, IDecorator -{ - public IReadOnlyList Composites => Decorated.Composites; - public ICompositeDecorated Decorated { get; } - - public CompositeDecoratedDecoratorA( - ICompositeDecorated decorated) => - Decorated = decorated; -} - -internal class CompositeDecoratedDecoratorB : ICompositeDecorated, IDecorator -{ - public IReadOnlyList Composites => Decorated.Composites; - public ICompositeDecorated Decorated { get; } - - public CompositeDecoratedDecoratorB( - ICompositeDecorated decorated) => - Decorated = decorated; -} - -internal class CompositeDecoratedBasisA : ICompositeDecorated -{ - public IReadOnlyList Composites => new List { this }; - public ICompositeDecorated Decorated => this; -} - -internal class CompositeDecoratedBasisB : ICompositeDecorated -{ - public IReadOnlyList Composites => new List { this }; - public ICompositeDecorated Decorated => this; -} - -internal class CompositeDecorated : ICompositeDecorated, IComposite -{ - public CompositeDecorated(IReadOnlyList composites) => - Composites = composites; - - public IReadOnlyList Composites { get; } - public ICompositeDecorated Decorated => this; -} - -[CreateFunction(typeof(ICompositeDecorated), "CreateDep")] -[CreateFunction(typeof(IReadOnlyList), "CreateCollection")] -internal partial class CompositeDecoratedContainer -{ - -} - -public partial class CompositeTests -{ - [Fact] - public void Decorated() - { - var container = new CompositeDecoratedContainer(); - var composite = container.CreateDep(); - Assert.IsType(composite); - Assert.IsType(composite.Decorated); - foreach (var compositeComposite in composite.Composites) - { - Assert.NotEqual(composite, compositeComposite); - Assert.IsType(compositeComposite); - Assert.IsType(compositeComposite.Decorated); - var baseImpl = compositeComposite.Decorated.Decorated; - Assert.True(baseImpl.GetType() == typeof(CompositeDecoratedBasisA) || baseImpl.GetType() == typeof(CompositeDecoratedBasisB)); - } - } - - [Fact] - public void DecoratedList() - { - var container = new CompositeDecoratedContainer(); - var composites = container.CreateCollection(); - foreach (var compositeComposite in composites) - { - Assert.IsType(compositeComposite); - Assert.IsType(compositeComposite.Decorated); - var baseImpl = compositeComposite.Decorated.Decorated; - Assert.True(baseImpl.GetType() == typeof(CompositeDecoratedBasisA) || baseImpl.GetType() == typeof(CompositeDecoratedBasisB)); - } - Assert.Equal(2, composites.Count); - } -} \ No newline at end of file diff --git a/Test/Generics/Choice/Double.cs b/Test/Generics/Choice/Double.cs new file mode 100644 index 00000000..63846c7f --- /dev/null +++ b/Test/Generics/Choice/Double.cs @@ -0,0 +1,23 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Generics.Choice.Double; + +internal interface IInterface {} + +internal class Class : IInterface {} + +[GenericParameterChoice(typeof(Class<,>), "T1", typeof(string))] +[CreateFunction(typeof(IInterface), "Create")] +internal partial class Container {} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var instance = container.Create(); + Assert.IsType>(instance); + } +} \ No newline at end of file diff --git a/Test/Generics/Choice/DoubleBothChosen.cs b/Test/Generics/Choice/DoubleBothChosen.cs new file mode 100644 index 00000000..b603bb8e --- /dev/null +++ b/Test/Generics/Choice/DoubleBothChosen.cs @@ -0,0 +1,24 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Generics.Choice.DoubleBothChosen; + +internal interface IInterface {} + +internal class Class : IInterface {} + +[GenericParameterChoice(typeof(Class<,>), "T0", typeof(int))] +[GenericParameterChoice(typeof(Class<,>), "T1", typeof(string))] +[CreateFunction(typeof(IInterface), "Create")] +internal partial class Container {} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var instance = container.Create(); + Assert.IsType>(instance); + } +} \ No newline at end of file diff --git a/Test/Generics/Choice/DoubleBothChosenWithSingleOtherSubstitute.cs b/Test/Generics/Choice/DoubleBothChosenWithSingleOtherSubstitute.cs new file mode 100644 index 00000000..1368b9b4 --- /dev/null +++ b/Test/Generics/Choice/DoubleBothChosenWithSingleOtherSubstitute.cs @@ -0,0 +1,26 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Generics.Choice.DoubleBothChosenWithSingleOtherSubstitute; + +internal interface IInterface {} + +internal class Class : IInterface {} + +[GenericParameterSubstituteAggregation(typeof(Class<,>), "T0", typeof(uint))] +[GenericParameterChoice(typeof(Class<,>), "T0", typeof(int))] +[GenericParameterSubstituteAggregation(typeof(Class<,>), "T1", typeof(bool))] +[GenericParameterChoice(typeof(Class<,>), "T1", typeof(string))] +[CreateFunction(typeof(IInterface), "Create")] +internal partial class Container {} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var instance = container.Create(); + Assert.IsType>(instance); + } +} \ No newline at end of file diff --git a/Test/Generics/Choice/DoubleWithSingleOtherSubstitute.cs b/Test/Generics/Choice/DoubleWithSingleOtherSubstitute.cs new file mode 100644 index 00000000..e9a50dfe --- /dev/null +++ b/Test/Generics/Choice/DoubleWithSingleOtherSubstitute.cs @@ -0,0 +1,24 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Generics.Choice.DoubleWithSingleOtherSubstitute; + +internal interface IInterface {} + +internal class Class : IInterface {} + +[GenericParameterSubstituteAggregation(typeof(Class<,>), "T1", typeof(bool))] +[GenericParameterChoice(typeof(Class<,>), "T1", typeof(string))] +[CreateFunction(typeof(IInterface), "Create")] +internal partial class Container {} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var instance = container.Create(); + Assert.IsType>(instance); + } +} \ No newline at end of file diff --git a/Test/Generics/Choice/Single.cs b/Test/Generics/Choice/Single.cs new file mode 100644 index 00000000..887a31bc --- /dev/null +++ b/Test/Generics/Choice/Single.cs @@ -0,0 +1,23 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Generics.Choice.Single; + +internal interface IInterface {} + +internal class Class : IInterface {} + +[GenericParameterChoice(typeof(Class<>), "T0", typeof(int))] +[CreateFunction(typeof(IInterface), "Create")] +internal partial class Container {} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var instance = container.Create(); + Assert.IsType>(instance); + } +} \ No newline at end of file diff --git a/Test/Generics/Choice/SingleWithSingleOtherSubstitute.cs b/Test/Generics/Choice/SingleWithSingleOtherSubstitute.cs new file mode 100644 index 00000000..7f55954a --- /dev/null +++ b/Test/Generics/Choice/SingleWithSingleOtherSubstitute.cs @@ -0,0 +1,24 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Generics.Choice.SingleWithSingleOtherSubstitute; + +internal interface IInterface {} + +internal class Class : IInterface {} + +[GenericParameterSubstituteAggregation(typeof(Class<>), "T0", typeof(bool))] +[GenericParameterChoice(typeof(Class<>), "T0", typeof(int))] +[CreateFunction(typeof(IInterface), "Create")] +internal partial class Container {} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var instance = container.Create(); + Assert.IsType>(instance); + } +} \ No newline at end of file diff --git a/Test/Generics/ChoiceIndirectlyBySingleSubstitute/Double.cs b/Test/Generics/ChoiceIndirectlyBySingleSubstitute/Double.cs new file mode 100644 index 00000000..0ec7d0aa --- /dev/null +++ b/Test/Generics/ChoiceIndirectlyBySingleSubstitute/Double.cs @@ -0,0 +1,23 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Generics.ChoiceIndirectlyBySingleSubstitute.Double; + +internal interface IInterface {} + +internal class Class : IInterface {} + +[GenericParameterSubstituteAggregation(typeof(Class<,>), "T1", typeof(string))] +[CreateFunction(typeof(IInterface), "Create")] +internal partial class Container {} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var instance = container.Create(); + Assert.IsType>(instance); + } +} \ No newline at end of file diff --git a/Test/Generics/ChoiceIndirectlyBySingleSubstitute/Single.cs b/Test/Generics/ChoiceIndirectlyBySingleSubstitute/Single.cs new file mode 100644 index 00000000..cd00e904 --- /dev/null +++ b/Test/Generics/ChoiceIndirectlyBySingleSubstitute/Single.cs @@ -0,0 +1,23 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Generics.ChoiceIndirectlyBySingleSubstitute.Single; + +internal interface IInterface {} + +internal class Class : IInterface {} + +[GenericParameterSubstituteAggregation(typeof(Class<>), "T0", typeof(int))] +[CreateFunction(typeof(IInterface), "Create")] +internal partial class Container {} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var instance = container.Create(); + Assert.IsType>(instance); + } +} \ No newline at end of file diff --git a/Test/Generics/SubstituteCollection/Double.cs b/Test/Generics/SubstituteCollection/Double.cs new file mode 100644 index 00000000..c34e9ef8 --- /dev/null +++ b/Test/Generics/SubstituteCollection/Double.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Generics.SubstituteCollection.Double; + +internal interface IInterface {} + +internal class Class : IInterface {} + +[GenericParameterSubstituteAggregation(typeof(Class<,>), "T1", typeof(int), typeof(string))] +[CreateFunction(typeof(IReadOnlyList>), "Create")] +internal partial class Container {} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var list = container.Create(); + Assert.Equal(2, list.Count); + Assert.Contains(list, i => i.GetType() == typeof(Class)); + Assert.Contains(list, i => i.GetType() == typeof(Class)); + } +} \ No newline at end of file diff --git a/Test/Generics/SubstituteCollection/DoubleBothSubstituted.cs b/Test/Generics/SubstituteCollection/DoubleBothSubstituted.cs new file mode 100644 index 00000000..94b3103e --- /dev/null +++ b/Test/Generics/SubstituteCollection/DoubleBothSubstituted.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Generics.SubstituteCollection.BothSubstituted; + +internal interface IInterface {} + +internal class Class : IInterface {} + +[GenericParameterSubstituteAggregation(typeof(Class<,>), "T0", typeof(bool), typeof(byte))] +[GenericParameterSubstituteAggregation(typeof(Class<,>), "T1", typeof(int), typeof(string))] +[CreateFunction(typeof(IReadOnlyList), "Create")] +internal partial class Container {} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var list = container.Create(); + Assert.Equal(4, list.Count); + Assert.Contains(list, i => i.GetType() == typeof(Class)); + Assert.Contains(list, i => i.GetType() == typeof(Class)); + Assert.Contains(list, i => i.GetType() == typeof(Class)); + Assert.Contains(list, i => i.GetType() == typeof(Class)); + } +} \ No newline at end of file diff --git a/Test/Generics/SubstituteCollection/DoubleBothSubstitutedWithChoice.cs b/Test/Generics/SubstituteCollection/DoubleBothSubstitutedWithChoice.cs new file mode 100644 index 00000000..d513e614 --- /dev/null +++ b/Test/Generics/SubstituteCollection/DoubleBothSubstitutedWithChoice.cs @@ -0,0 +1,31 @@ +using System.Collections.Generic; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Generics.SubstituteCollection.BothSubstitutedWithChoice; + +internal interface IInterface {} + +internal class Class : IInterface {} + +[GenericParameterSubstituteAggregation(typeof(Class<,>), "T0", typeof(bool))] +[GenericParameterSubstituteAggregation(typeof(Class<,>), "T1", typeof(int))] +[GenericParameterChoice(typeof(Class<,>), "T0", typeof(byte))] +[GenericParameterChoice(typeof(Class<,>), "T1", typeof(string))] +[CreateFunction(typeof(IReadOnlyList), "Create")] +internal partial class Container {} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var list = container.Create(); + Assert.Equal(4, list.Count); + Assert.Contains(list, i => i.GetType() == typeof(Class)); + Assert.Contains(list, i => i.GetType() == typeof(Class)); + Assert.Contains(list, i => i.GetType() == typeof(Class)); + Assert.Contains(list, i => i.GetType() == typeof(Class)); + } +} \ No newline at end of file diff --git a/Test/Generics/SubstituteCollection/DoubleWithChoice.cs b/Test/Generics/SubstituteCollection/DoubleWithChoice.cs new file mode 100644 index 00000000..066ecde4 --- /dev/null +++ b/Test/Generics/SubstituteCollection/DoubleWithChoice.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Generics.SubstituteCollection.DoubleWithChoice; + +internal interface IInterface {} + +internal class Class : IInterface {} + +[GenericParameterSubstituteAggregation(typeof(Class<,>), "T1", typeof(int))] +[GenericParameterChoice(typeof(Class<,>), "T1", typeof(string))] +[CreateFunction(typeof(IReadOnlyList>), "Create")] +internal partial class Container {} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var list = container.Create(); + Assert.Equal(2, list.Count); + Assert.Contains(list, i => i.GetType() == typeof(Class)); + Assert.Contains(list, i => i.GetType() == typeof(Class)); + } +} \ No newline at end of file diff --git a/Test/Generics/SubstituteCollection/Single.cs b/Test/Generics/SubstituteCollection/Single.cs new file mode 100644 index 00000000..daaa749d --- /dev/null +++ b/Test/Generics/SubstituteCollection/Single.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Generics.SubstituteCollection.SingleWithChoice; + +internal interface IInterface {} + +internal class Class : IInterface {} + +[GenericParameterSubstituteAggregation(typeof(Class<>), "T0", typeof(int), typeof(string))] +[CreateFunction(typeof(IReadOnlyList), "Create")] +internal partial class Container {} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var list = container.Create(); + Assert.Equal(2, list.Count); + Assert.Contains(list, i => i.GetType() == typeof(Class)); + Assert.Contains(list, i => i.GetType() == typeof(Class)); + } +} \ No newline at end of file diff --git a/Test/Generics/SubstituteCollection/SingleWithChoice.cs b/Test/Generics/SubstituteCollection/SingleWithChoice.cs new file mode 100644 index 00000000..21c40b91 --- /dev/null +++ b/Test/Generics/SubstituteCollection/SingleWithChoice.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Generics.SubstituteCollection.Single; + +internal interface IInterface {} + +internal class Class : IInterface {} + +[GenericParameterSubstituteAggregation(typeof(Class<>), "T0", typeof(int))] +[GenericParameterChoice(typeof(Class<>), "T0", typeof(string))] +[CreateFunction(typeof(IReadOnlyList), "Create")] +internal partial class Container {} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var list = container.Create(); + Assert.Equal(2, list.Count); + Assert.Contains(list, i => i.GetType() == typeof(Class)); + Assert.Contains(list, i => i.GetType() == typeof(Class)); + } +} \ No newline at end of file diff --git a/Test/Generics/SubstituteCollection/TripleInsanity.cs b/Test/Generics/SubstituteCollection/TripleInsanity.cs new file mode 100644 index 00000000..70c5a326 --- /dev/null +++ b/Test/Generics/SubstituteCollection/TripleInsanity.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Generics.SubstituteCollection.TripleInsanity; + +internal interface IInterface {} + +internal class Class : IInterface {} + +[GenericParameterSubstituteAggregation(typeof(Class<,,>), "T0", typeof(int), typeof(string), typeof(uint), typeof(bool), typeof(byte))] +[GenericParameterSubstituteAggregation(typeof(Class<,,>), "T1", typeof(int), typeof(string), typeof(uint), typeof(bool), typeof(byte))] +[GenericParameterSubstituteAggregation(typeof(Class<,,>), "T2", typeof(int), typeof(string), typeof(uint), typeof(bool), typeof(byte))] +[CreateFunction(typeof(IReadOnlyList), "Create")] +internal partial class Container {} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var list = container.Create(); + Assert.Equal(125, list.Count); + } +} \ No newline at end of file diff --git a/Test/ScopeSpecificAttributesTestsWithDecorator.cs b/Test/Scoping/ScopeSpecificAttributes/Decorator.cs similarity index 97% rename from Test/ScopeSpecificAttributesTestsWithDecorator.cs rename to Test/Scoping/ScopeSpecificAttributes/Decorator.cs index b121c24c..df23fac2 100644 --- a/Test/ScopeSpecificAttributesTestsWithDecorator.cs +++ b/Test/Scoping/ScopeSpecificAttributes/Decorator.cs @@ -1,7 +1,7 @@ using MrMeeseeks.DIE.Configuration; using Xunit; -namespace MrMeeseeks.DIE.Test.ScopeSpecificAttributesTestsWithDecorator; +namespace MrMeeseeks.DIE.Test.Scoping.ScopeSpecificAttributes.Decorator; internal interface IInterface { @@ -123,7 +123,7 @@ partial class DIE_Scope_A } } -public class ScopeSpecificAttributesTests +public class Tests { [Fact] public void Container() diff --git a/Test/ScopeSpecificAttributesTestsWithImplementations.cs b/Test/Scoping/ScopeSpecificAttributes/Implementation.cs similarity index 96% rename from Test/ScopeSpecificAttributesTestsWithImplementations.cs rename to Test/Scoping/ScopeSpecificAttributes/Implementation.cs index 3ac58d11..0e4ad6fa 100644 --- a/Test/ScopeSpecificAttributesTestsWithImplementations.cs +++ b/Test/Scoping/ScopeSpecificAttributes/Implementation.cs @@ -1,7 +1,7 @@ using MrMeeseeks.DIE.Configuration; using Xunit; -namespace MrMeeseeks.DIE.Test.ScopeSpecificAttributesTestsWithImplementations; +namespace MrMeeseeks.DIE.Test.Scoping.ScopeSpecificAttributes.Implementation; internal interface IDependency {} diff --git a/Test/ScopeSpecificAttributesTestsWithImplementationLists.cs b/Test/Scoping/ScopeSpecificAttributes/ImplementationCollection.cs similarity index 96% rename from Test/ScopeSpecificAttributesTestsWithImplementationLists.cs rename to Test/Scoping/ScopeSpecificAttributes/ImplementationCollection.cs index 3a9c261e..31f0a4b9 100644 --- a/Test/ScopeSpecificAttributesTestsWithImplementationLists.cs +++ b/Test/Scoping/ScopeSpecificAttributes/ImplementationCollection.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration; using Xunit; -namespace MrMeeseeks.DIE.Test.ScopeSpecificAttributesTestsWithImplementationLists; +namespace MrMeeseeks.DIE.Test.Scoping.ScopeSpecificAttributes.ImplementationCollection; internal interface IDependency {} diff --git a/Test/Scoping/TransientScopeInstance/InContainer.cs b/Test/Scoping/TransientScopeInstance/InContainer.cs new file mode 100644 index 00000000..6e0b4109 --- /dev/null +++ b/Test/Scoping/TransientScopeInstance/InContainer.cs @@ -0,0 +1,25 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Scoping.TransientScopeInstance.InContainer; + +internal interface IInterface {} + +internal class Dependency : IInterface, ITransientScopeInstance {} + +[CreateFunction(typeof(IInterface), "Create")] +internal partial class Container +{ + +} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var instance = container.Create(); + Assert.IsType(instance); + } +} \ No newline at end of file diff --git a/Test/Scoping/TransientScopeInstance/InScope.cs b/Test/Scoping/TransientScopeInstance/InScope.cs new file mode 100644 index 00000000..1ced8047 --- /dev/null +++ b/Test/Scoping/TransientScopeInstance/InScope.cs @@ -0,0 +1,31 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Scoping.TransientScopeInstance.InContainer.InScope; + +internal interface IInterface {} + +internal class Dependency : IInterface, ITransientScopeInstance {} + +internal class ScopeRoot : IScopeRoot +{ + public IInterface Dependency { get; } + public ScopeRoot(IInterface dependency) => Dependency = dependency; +} + +[CreateFunction(typeof(ScopeRoot), "Create")] +internal partial class Container +{ + +} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var scopeRoot = container.Create(); + Assert.IsType(scopeRoot.Dependency); + } +} \ No newline at end of file diff --git a/Test/Scoping/TransientScopeInstance/InScopeInScope.cs b/Test/Scoping/TransientScopeInstance/InScopeInScope.cs new file mode 100644 index 00000000..79c64d5e --- /dev/null +++ b/Test/Scoping/TransientScopeInstance/InScopeInScope.cs @@ -0,0 +1,37 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Scoping.TransientScopeInstance.InContainer.InScopeInScope; + +internal interface IInterface {} + +internal class Dependency : IInterface, ITransientScopeInstance {} + +internal class ScopeRoot : IScopeRoot +{ + public IInterface Dependency { get; } + public ScopeRoot(IInterface dependency) => Dependency = dependency; +} + +internal class ScopeWithTransientScopeInstanceAbove : IScopeRoot +{ + public ScopeRoot InnerScope { get; } + public ScopeWithTransientScopeInstanceAbove(ScopeRoot innerScope) => InnerScope = innerScope; +} + +[CreateFunction(typeof(ScopeWithTransientScopeInstanceAbove), "Create")] +internal partial class Container +{ + +} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var scopeRoot = container.Create(); + Assert.IsType(scopeRoot.InnerScope.Dependency); + } +} \ No newline at end of file diff --git a/Test/Scoping/TransientScopeInstance/InTransientScope.cs b/Test/Scoping/TransientScopeInstance/InTransientScope.cs new file mode 100644 index 00000000..501f200e --- /dev/null +++ b/Test/Scoping/TransientScopeInstance/InTransientScope.cs @@ -0,0 +1,50 @@ +using System; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Scoping.TransientScopeInstance.InContainer.InTransientScope; + +internal interface IInterface +{ + bool IsDisposed { get; } +} + +internal class Dependency : IInterface, ITransientScopeInstance, IDisposable +{ + public bool IsDisposed { get; private set; } + + public void Dispose() => IsDisposed = true; +} + +internal class TransientScope : ITransientScopeRoot +{ + private readonly IDisposable _scopeDisposal; + public IInterface Dependency { get; } + public TransientScope(IDisposable scopeDisposal, IInterface dependency) + { + _scopeDisposal = scopeDisposal; + Dependency = dependency; + } + + public void Cleanup() => _scopeDisposal.Dispose(); +} + +[CreateFunction(typeof(TransientScope), "Create")] +internal partial class Container +{ + +} + +public class Tests +{ + [Fact] + public void Test() + { + using var container = new Container(); + var transientScopeRoot = container.Create(); + Assert.IsType(transientScopeRoot.Dependency); + Assert.False(transientScopeRoot.Dependency.IsDisposed); + transientScopeRoot.Cleanup(); + Assert.True(transientScopeRoot.Dependency.IsDisposed); + } +} \ No newline at end of file diff --git a/Test/Scoping/TransientScopeInstance/InTransientScopeWithScopes.cs b/Test/Scoping/TransientScopeInstance/InTransientScopeWithScopes.cs new file mode 100644 index 00000000..01657ebd --- /dev/null +++ b/Test/Scoping/TransientScopeInstance/InTransientScopeWithScopes.cs @@ -0,0 +1,79 @@ +using System; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Scoping.TransientScopeInstance.InContainer.InTransientScopeWithScopes; + +internal interface IInterface +{ + bool IsDisposed { get; } +} + +internal class Dependency : IInterface, ITransientScopeInstance, IDisposable +{ + public bool IsDisposed { get; private set; } + + public void Dispose() => IsDisposed = false; +} + +internal interface ITransientScopeChild +{ + IInterface TransientScopeInstance { get; } + bool Disposed { get; } +} + +internal class TransientScopeChild : ITransientScopeChild, IScopeRoot, IDisposable +{ + public TransientScopeChild(IInterface transientScopeInstance) + { + TransientScopeInstance = transientScopeInstance; + } + + public IInterface TransientScopeInstance { get; } + public bool Disposed { get; private set; } + + public void Dispose() + { + Disposed = true; + } +} + +internal class TransientScopeWithScopes : ITransientScopeRoot +{ + private readonly IDisposable _scopeDisposal; + + public TransientScopeWithScopes(IDisposable scopeDisposal, ITransientScopeChild a, ITransientScopeChild b) + { + _scopeDisposal = scopeDisposal; + A = a; + B = b; + } + public ITransientScopeChild A { get; } + public ITransientScopeChild B { get; } + public void CleanUp() + { + _scopeDisposal.Dispose(); + } +} + +[CreateFunction(typeof(TransientScopeWithScopes), "Create")] +internal partial class Container +{ + +} + +public partial class Tests +{ + [Fact] + public void TransientScopeWithScopes() + { + using var container = new Container(); + var transientScopeRoot = container.Create(); + Assert.NotEqual(transientScopeRoot.A, transientScopeRoot.B); + Assert.Equal(transientScopeRoot.A.TransientScopeInstance, transientScopeRoot.B.TransientScopeInstance); + transientScopeRoot.CleanUp(); + Assert.True(transientScopeRoot.A.Disposed); + Assert.True(transientScopeRoot.B.Disposed); + container.Dispose(); + } +} \ No newline at end of file diff --git a/Test/Test.csproj b/Test/Test.csproj index 930e5eab..473c641d 100644 --- a/Test/Test.csproj +++ b/Test/Test.csproj @@ -35,4 +35,8 @@ + + + + diff --git a/Test/TransientScopeInstanceTests.cs b/Test/TransientScopeInstanceTests.cs deleted file mode 100644 index f2be4d50..00000000 --- a/Test/TransientScopeInstanceTests.cs +++ /dev/null @@ -1,142 +0,0 @@ -using System; -using MrMeeseeks.DIE.Configuration; -using Xunit; - -namespace MrMeeseeks.DIE.Test; - -internal interface ITransientScopeInstanceInner {} -internal class TransientScopeInstance : ITransientScopeInstanceInner, ITransientScopeInstance {} - -public partial class TransientScopeInstanceTests -{ - [Fact] - public void InContainer() - { - using var container = new TransientScopeInstanceContainer(); - var _ = container.Create0(); - } -} - -internal interface IScopeWithTransientScopeInstance {} - -internal class ScopeWithTransientScopeInstance : IScopeWithTransientScopeInstance, IScopeRoot -{ - public ScopeWithTransientScopeInstance(ITransientScopeInstanceInner _) {} -} - -public partial class TransientScopeInstanceTests -{ - [Fact] - public void InScope() - { - using var container = new TransientScopeInstanceContainer(); - var _ = container.Create1(); - } -} - -internal interface IScopeWithTransientScopeInstanceAbove {} - -internal class ScopeWithTransientScopeInstanceAbove : IScopeWithTransientScopeInstanceAbove, IScopeRoot -{ - public ScopeWithTransientScopeInstanceAbove(IScopeWithTransientScopeInstance _) {} -} - -public partial class TransientScopeInstanceTests -{ - [Fact] - public void InScopeInScope() - { - using var container = new TransientScopeInstanceContainer(); - var _ = container.Create2(); - } -} - -internal interface ITransientScopeWithTransientScopeInstance {} - -internal class TransientScopeWithTransientScopeInstance : ITransientScopeWithTransientScopeInstance, ITransientScopeRoot -{ - public TransientScopeWithTransientScopeInstance(IDisposable scopeDisposal, ITransientScopeInstanceInner _) {} -} - -public partial class TransientScopeInstanceTests -{ - [Fact] - public void InTransientScope() - { - using var container = new TransientScopeInstanceContainer(); - var _ = container.Create3(); - } -} - -internal interface ITransientScopeChild -{ - ITransientScopeInstanceInner TransientScopeInstance { get; } - bool Disposed { get; } -} - -internal class TransientScopeChild : ITransientScopeChild, IScopeRoot, IDisposable -{ - public TransientScopeChild(ITransientScopeInstanceInner transientScopeInstance) - { - TransientScopeInstance = transientScopeInstance; - } - - public ITransientScopeInstanceInner TransientScopeInstance { get; } - public bool Disposed { get; private set; } - - public void Dispose() - { - Disposed = true; - } -} - -internal interface ITransientScopeWithScopes -{ - ITransientScopeChild A { get; } - ITransientScopeChild B { get; } - void CleanUp(); -} - -internal class TransientScopeWithScopes : ITransientScopeWithScopes, ITransientScopeRoot -{ - private readonly IDisposable _scopeDisposal; - - public TransientScopeWithScopes(IDisposable scopeDisposal, ITransientScopeChild a, ITransientScopeChild b) - { - _scopeDisposal = scopeDisposal; - A = a; - B = b; - } - public ITransientScopeChild A { get; } - public ITransientScopeChild B { get; } - public void CleanUp() - { - _scopeDisposal.Dispose(); - } -} - -[CreateFunction(typeof(ITransientScopeInstanceInner), "Create0")] -[CreateFunction(typeof(IScopeWithTransientScopeInstance), "Create1")] -[CreateFunction(typeof(IScopeWithTransientScopeInstanceAbove), "Create2")] -[CreateFunction(typeof(ITransientScopeWithTransientScopeInstance), "Create3")] -[CreateFunction(typeof(ITransientScopeWithScopes), "Create4")] -internal partial class TransientScopeInstanceContainer -{ - -} - -public partial class TransientScopeInstanceTests -{ - [Fact] - public void TransientScopeWithScopes() - { - using var container = new TransientScopeInstanceContainer(); - var transientScopeRoot = container.Create4(); - Assert.NotEqual(transientScopeRoot.A, transientScopeRoot.B); - Assert.Equal(transientScopeRoot.A.TransientScopeInstance, transientScopeRoot.B.TransientScopeInstance); - transientScopeRoot.CleanUp(); - Assert.True(transientScopeRoot.A.Disposed); - Assert.True(transientScopeRoot.B.Disposed); - container.Dispose(); - } -} \ No newline at end of file From 0eab4773e6206f2e896503444307148382314577 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Fri, 6 May 2022 22:14:38 +0200 Subject: [PATCH 068/162] Completed support for generic implementations --- Main/Configuration/CheckTypeProperties.cs | 102 ++++++++++++------ .../Configuration/CurrentlyConsideredTypes.cs | 102 ++++++++++++------ Main/Configuration/TypesFromAttributes.cs | 5 +- Main/Extensions/INamedTypeSymbolExtensions.cs | 5 + .../Function/FunctionResolutionBuilder.cs | 3 +- Sample/Container.cs | 2 + Sample/Context.cs | 22 ++-- Sample/MarkerInterfaces.cs | 2 + Test/AssemblyInfo.cs | 3 +- Test/Generics/Configuration/AsyncTransient.cs | 41 +++++++ .../AsyncTransientWithJustTransient.cs | 41 +++++++ Test/Generics/Configuration/Composite.cs | 47 ++++++++ .../Configuration/ConstructorChoice.cs | 34 ++++++ .../Configuration/ContainerInstance.cs | 22 ++++ ...erInstanceWithDifferentGenericParameter.cs | 23 ++++ Test/Generics/Configuration/Decorator.cs | 54 ++++++++++ .../InitializerImplementationAsync.cs | 34 ++++++ .../InitializerImplementationAsyncValue.cs | 34 ++++++ .../InitializerImplementationSync.cs | 32 ++++++ .../InitializerInterfaceAsync.cs | 33 ++++++ .../InitializerInterfaceAsyncValue.cs | 33 ++++++ .../Configuration/InitializerInterfaceSync.cs | 31 ++++++ .../InterfaceGenericComposite.cs | 47 ++++++++ .../InterfaceGenericDecorator.cs | 54 ++++++++++ Test/Generics/Configuration/ScopeInstance.cs | 34 ++++++ ...peInstanceWithDifferentGenericParameter.cs | 35 ++++++ Test/Generics/Configuration/ScopeRoot.cs | 42 ++++++++ Test/Generics/Configuration/SyncTransient.cs | 35 ++++++ .../SyncTransientWithJustTransient.cs | 35 ++++++ .../Configuration/TransientScopeInstance.cs | 35 ++++++ ...peInstanceWithDifferentGenericParameter.cs | 35 ++++++ .../Configuration/TransientScopeRoot.cs | 42 ++++++++ Test/MarkerInterfaces.cs | 2 + 33 files changed, 1027 insertions(+), 74 deletions(-) create mode 100644 Test/Generics/Configuration/AsyncTransient.cs create mode 100644 Test/Generics/Configuration/AsyncTransientWithJustTransient.cs create mode 100644 Test/Generics/Configuration/Composite.cs create mode 100644 Test/Generics/Configuration/ConstructorChoice.cs create mode 100644 Test/Generics/Configuration/ContainerInstance.cs create mode 100644 Test/Generics/Configuration/ContainerInstanceWithDifferentGenericParameter.cs create mode 100644 Test/Generics/Configuration/Decorator.cs create mode 100644 Test/Generics/Configuration/InitializerImplementationAsync.cs create mode 100644 Test/Generics/Configuration/InitializerImplementationAsyncValue.cs create mode 100644 Test/Generics/Configuration/InitializerImplementationSync.cs create mode 100644 Test/Generics/Configuration/InitializerInterfaceAsync.cs create mode 100644 Test/Generics/Configuration/InitializerInterfaceAsyncValue.cs create mode 100644 Test/Generics/Configuration/InitializerInterfaceSync.cs create mode 100644 Test/Generics/Configuration/InterfaceGenericComposite.cs create mode 100644 Test/Generics/Configuration/InterfaceGenericDecorator.cs create mode 100644 Test/Generics/Configuration/ScopeInstance.cs create mode 100644 Test/Generics/Configuration/ScopeInstanceWithDifferentGenericParameter.cs create mode 100644 Test/Generics/Configuration/ScopeRoot.cs create mode 100644 Test/Generics/Configuration/SyncTransient.cs create mode 100644 Test/Generics/Configuration/SyncTransientWithJustTransient.cs create mode 100644 Test/Generics/Configuration/TransientScopeInstance.cs create mode 100644 Test/Generics/Configuration/TransientScopeInstanceWithDifferentGenericParameter.cs create mode 100644 Test/Generics/Configuration/TransientScopeRoot.cs diff --git a/Main/Configuration/CheckTypeProperties.cs b/Main/Configuration/CheckTypeProperties.cs index 9c714ba5..f8844f3d 100644 --- a/Main/Configuration/CheckTypeProperties.cs +++ b/Main/Configuration/CheckTypeProperties.cs @@ -23,7 +23,7 @@ internal interface ICheckTypeProperties ScopeLevel ShouldBeScopeRoot(INamedTypeSymbol implementationType); bool ShouldBeComposite(INamedTypeSymbol interfaceType); ScopeLevel GetScopeLevelFor(INamedTypeSymbol implementationType); - INamedTypeSymbol GetCompositeFor(INamedTypeSymbol interfaceType); + INamedTypeSymbol? GetCompositeFor(INamedTypeSymbol interfaceType); IMethodSymbol? GetConstructorChoiceFor(INamedTypeSymbol implementationType); bool ShouldBeDecorated(INamedTypeSymbol interfaceType); @@ -50,11 +50,11 @@ internal CheckTypeProperties( public DisposalType ShouldDisposalBeManaged(INamedTypeSymbol implementationType) { if (implementationType.AllInterfaces.Contains(_wellKnownTypes.AsyncDisposable) - && !_currentlyConsideredTypes.AsyncTransientTypes.Contains(implementationType)) + && !_currentlyConsideredTypes.AsyncTransientTypes.Contains(implementationType.UnboundIfGeneric())) return DisposalType.Async; if (implementationType.AllInterfaces.Contains(_wellKnownTypes.Disposable) - && !_currentlyConsideredTypes.SyncTransientTypes.Contains(implementationType)) + && !_currentlyConsideredTypes.SyncTransientTypes.Contains(implementationType.UnboundIfGeneric())) return DisposalType.Sync; return DisposalType.None; @@ -62,46 +62,72 @@ public DisposalType ShouldDisposalBeManaged(INamedTypeSymbol implementationType) public ScopeLevel ShouldBeScopeRoot(INamedTypeSymbol implementationType) { - if (_currentlyConsideredTypes.TransientScopeRootTypes.Contains(implementationType)) return ScopeLevel.TransientScope; - return _currentlyConsideredTypes.ScopeRootTypes.Contains(implementationType) ? ScopeLevel.Scope : ScopeLevel.None; + if (_currentlyConsideredTypes.TransientScopeRootTypes.Contains(implementationType.UnboundIfGeneric())) return ScopeLevel.TransientScope; + return _currentlyConsideredTypes.ScopeRootTypes.Contains(implementationType.UnboundIfGeneric()) ? ScopeLevel.Scope : ScopeLevel.None; } - public bool ShouldBeComposite(INamedTypeSymbol interfaceType) => _currentlyConsideredTypes.InterfaceToComposite.ContainsKey(interfaceType); + public bool ShouldBeComposite(INamedTypeSymbol interfaceType) => _currentlyConsideredTypes.InterfaceToComposite.ContainsKey(interfaceType.UnboundIfGeneric()); public ScopeLevel GetScopeLevelFor(INamedTypeSymbol implementationType) { - if (_currentlyConsideredTypes.ContainerInstanceTypes.Contains(implementationType)) + if (_currentlyConsideredTypes.ContainerInstanceTypes.Contains(implementationType.UnboundIfGeneric())) return ScopeLevel.Container; - if (_currentlyConsideredTypes.TransientScopeInstanceTypes.Contains(implementationType)) + if (_currentlyConsideredTypes.TransientScopeInstanceTypes.Contains(implementationType.UnboundIfGeneric())) return ScopeLevel.TransientScope; - if (_currentlyConsideredTypes.ScopeInstanceTypes.Contains(implementationType)) + if (_currentlyConsideredTypes.ScopeInstanceTypes.Contains(implementationType.UnboundIfGeneric())) return ScopeLevel.Scope; return ScopeLevel.None; } - public INamedTypeSymbol GetCompositeFor(INamedTypeSymbol interfaceType) => _currentlyConsideredTypes.InterfaceToComposite[interfaceType]; + public INamedTypeSymbol? GetCompositeFor(INamedTypeSymbol interfaceType) + { + var compositeImplementation = _currentlyConsideredTypes.InterfaceToComposite[interfaceType.UnboundIfGeneric()]; + var implementations = GetClosedImplementations( + interfaceType, + new[] { compositeImplementation }, + true); + if (implementations.Count != 1) + return null; + + return implementations[0]; + } + public IMethodSymbol? GetConstructorChoiceFor(INamedTypeSymbol implementationType) { - if (implementationType.Constructors.Length == 1 - && implementationType.Constructors.SingleOrDefault() is { } constructor) + var typeToChoseFrom = implementationType.OriginalDefinitionIfUnbound(); + if (typeToChoseFrom.Constructors.Length == 1 + && typeToChoseFrom.Constructors.SingleOrDefault() is { } constructor) return constructor; - return _currentlyConsideredTypes.ImplementationToConstructorChoice.TryGetValue(implementationType, out var constr) + return _currentlyConsideredTypes.ImplementationToConstructorChoice.TryGetValue(implementationType.UnboundIfGeneric(), out var constr) ? constr : null; } - public bool ShouldBeDecorated(INamedTypeSymbol interfaceType) => _currentlyConsideredTypes.InterfaceToDecorators.ContainsKey(interfaceType); + public bool ShouldBeDecorated(INamedTypeSymbol interfaceType) => _currentlyConsideredTypes.InterfaceToDecorators.ContainsKey(interfaceType.UnboundIfGeneric()); public IReadOnlyList GetSequenceFor(INamedTypeSymbol interfaceType, INamedTypeSymbol implementationType) { - if (_currentlyConsideredTypes.ImplementationSequenceChoices.TryGetValue(implementationType, out var implementationSequence)) - return implementationSequence; - if (_currentlyConsideredTypes.InterfaceSequenceChoices.TryGetValue(interfaceType, out var interfaceSequence)) - return interfaceSequence; - if (_currentlyConsideredTypes.InterfaceToDecorators.TryGetValue(interfaceType, out var allDecorators) + IEnumerable sequence = Array.Empty(); + if (_currentlyConsideredTypes.DecoratorImplementationSequenceChoices.TryGetValue(implementationType.UnboundIfGeneric(), out var implementationSequence)) + sequence = implementationSequence; + else if (_currentlyConsideredTypes.DecoratorInterfaceSequenceChoices.TryGetValue(interfaceType.UnboundIfGeneric(), out var interfaceSequence)) + sequence = interfaceSequence; + else if (_currentlyConsideredTypes.InterfaceToDecorators.TryGetValue(interfaceType.UnboundIfGeneric(), out var allDecorators) && allDecorators.Count == 1) - return allDecorators; - throw new Exception("Couldn't find unambiguous sequence of decorators"); + sequence = allDecorators; + return sequence + .Select(imp => + { + var implementations = GetClosedImplementations( + interfaceType, + new[] { imp }, + true); + if (implementations.Count != 1) + return null; + return implementations[0]; + }) + .OfType() + .ToList(); } public INamedTypeSymbol? MapToSingleFittingImplementation(INamedTypeSymbol type) @@ -143,12 +169,14 @@ private IReadOnlyList GetClosedImplementations( continue; } - if (implementation.AllDerivedTypes() + var unboundImplementation = implementation.UnboundIfGeneric(); + var originalImplementation = implementation.OriginalDefinitionIfUnbound(); + + if (originalImplementation.AllDerivedTypes() .FirstOrDefault(t => SymbolEqualityComparer.Default.Equals(t.UnboundIfGeneric(), unboundTargetType)) is { } implementationsTarget) { - var unboundImplementation = implementation.UnboundIfGeneric(); - var newTypeArguments = implementation.TypeArguments + var newTypeArguments = originalImplementation.TypeArguments .Select(ta => ta switch { INamedTypeSymbol nts => nts, @@ -179,10 +207,10 @@ ITypeSymbol ForTypeParameterSymbol(ITypeParameterSymbol tps) } - if (newTypeArguments.Length == implementation.TypeArguments.Length + if (newTypeArguments.Length == originalImplementation.TypeArguments.Length && newTypeArguments.All(ta => ta is INamedTypeSymbol)) { - var closedImplementation = implementation.Construct(newTypeArguments); + var closedImplementation = originalImplementation.Construct(newTypeArguments); if (closedImplementation .AllDerivedTypes() .Any(t => SymbolEqualityComparer.Default.Equals(targetType, t))) @@ -190,7 +218,7 @@ ITypeSymbol ForTypeParameterSymbol(ITypeParameterSymbol tps) ret.Add(closedImplementation); } } - else if (newTypeArguments.Length == implementation.TypeArguments.Length + else if (newTypeArguments.Length == originalImplementation.TypeArguments.Length && newTypeArguments.All(ta => ta is INamedTypeSymbol or ITypeParameterSymbol)) { var openTypeParameters = newTypeArguments.OfType().ToImmutableArray(); @@ -219,10 +247,10 @@ ITypeSymbol ForTypeParameterSymbol(ITypeParameterSymbol tps) _ => ta }) .ToArray(); - if (veryNewTypeArguments.Length == implementation.TypeArguments.Length + if (veryNewTypeArguments.Length == originalImplementation.TypeArguments.Length && veryNewTypeArguments.All(ta => ta is INamedTypeSymbol)) { - var closedImplementation = implementation.Construct(veryNewTypeArguments); + var closedImplementation = originalImplementation.Construct(veryNewTypeArguments); if (closedImplementation .AllDerivedTypes() .Any(t => SymbolEqualityComparer.Default.Equals(targetType, t))) @@ -259,8 +287,16 @@ IEnumerable> GetAll return ret; } - public (INamedTypeSymbol Type, IMethodSymbol Initializer)? GetInitializerFor(INamedTypeSymbol implementationType) => - _currentlyConsideredTypes.ImplementationToInitializer.TryGetValue(implementationType, out var tuple) - ? tuple - : null; + public (INamedTypeSymbol Type, IMethodSymbol Initializer)? GetInitializerFor(INamedTypeSymbol implementationType) + { + if (_currentlyConsideredTypes.ImplementationToInitializer.TryGetValue(implementationType.UnboundIfGeneric(), out var tuple)) + { + return SymbolEqualityComparer.Default.Equals( + tuple.Item1.UnboundIfGeneric(), + implementationType.UnboundIfGeneric()) + ? (implementationType, tuple.Item2) + : tuple; + } + return null; + } } \ No newline at end of file diff --git a/Main/Configuration/CurrentlyConsideredTypes.cs b/Main/Configuration/CurrentlyConsideredTypes.cs index 7bfe8953..fcd9836e 100644 --- a/Main/Configuration/CurrentlyConsideredTypes.cs +++ b/Main/Configuration/CurrentlyConsideredTypes.cs @@ -15,8 +15,8 @@ internal interface ICurrentlyConsideredTypes IReadOnlyDictionary InterfaceToComposite { get; } IReadOnlyDictionary ImplementationToConstructorChoice { get; } IReadOnlyDictionary> InterfaceToDecorators { get; } - IReadOnlyDictionary> InterfaceSequenceChoices { get; } - IReadOnlyDictionary> ImplementationSequenceChoices { get; } + IReadOnlyDictionary> DecoratorInterfaceSequenceChoices { get; } + IReadOnlyDictionary> DecoratorImplementationSequenceChoices { get; } IReadOnlyDictionary> ImplementationMap { get; } IReadOnlyDictionary ImplementationToInitializer { get; } IReadOnlyDictionary<(INamedTypeSymbol, ITypeParameterSymbol), IReadOnlyList> GenericParameterSubstitutes { get; } @@ -41,7 +41,33 @@ public CurrentlyConsideredTypes( .Where(c => c is not null) .OfType() .Where(nts => !nts.IsAbstract))); - + + var immutableHashSet = context + .Compilation + .SourceModule + .ReferencedAssemblySymbols + .SelectMany(a => GetAllNamespaces(a.GlobalNamespace)) + .SelectMany(ns => ns.GetTypeMembers()) + .Where(nts => nts is + { + IsAbstract: false, + IsStatic: false, + IsImplicitClass: false, + IsScriptClass: false, + TypeKind: TypeKind.Class or TypeKind.Struct or TypeKind.Structure, + DeclaredAccessibility: Accessibility.Public or Accessibility.Internal + }) + .Where(nts => !nts.Name.StartsWith("<") && nts.IsAccessibleInternally()) + .ToImmutableHashSet(SymbolEqualityComparer.Default); + + IEnumerable GetAllNamespaces(INamespaceSymbol root) + { + yield return root; + foreach(var child in root.GetNamespaceMembers()) + foreach(var next in GetAllNamespaces(child)) + yield return next; + } + foreach (var types in typesFromAttributes) { foreach (var filterType in types.FilterSpy.Concat(types.FilterImplementation)) @@ -75,8 +101,8 @@ public CurrentlyConsideredTypes( var compositeInterfaces = ImmutableHashSet.Empty; foreach (var types in typesFromAttributes) { - compositeInterfaces = compositeInterfaces.Except(types.FilterComposite); - compositeInterfaces = compositeInterfaces.Union(types.Composite); + compositeInterfaces = compositeInterfaces.Except(types.FilterComposite.Select(c => c.UnboundIfGeneric())); + compositeInterfaces = compositeInterfaces.Union(types.Composite.Select(c => c.UnboundIfGeneric())); } var compositeTypes = GetSetOfTypesWithProperties(t => t.Composite, t => t.FilterComposite); @@ -84,9 +110,11 @@ public CurrentlyConsideredTypes( .OfType() .GroupBy(nts => { - var namedTypeSymbol = nts.AllInterfaces - .Single(t => compositeInterfaces.Contains(t.OriginalDefinition, SymbolEqualityComparer.Default)); - return namedTypeSymbol.TypeArguments.First(); + var namedTypeSymbol = nts.OriginalDefinition.AllInterfaces + .Single(t => compositeInterfaces.Contains(t.UnboundIfGeneric(), SymbolEqualityComparer.Default)); + return namedTypeSymbol.TypeArguments.FirstOrDefault() is INamedTypeSymbol interfaceTypeSymbol + ? interfaceTypeSymbol.UnboundIfGeneric() + : throw new Exception("Composite should implement composite interface"); }, SymbolEqualityComparer.Default) .Where(g => g.Count() == 1) .ToDictionary(g => g.Key, g => g.Single(), SymbolEqualityComparer.Default); @@ -99,7 +127,7 @@ public CurrentlyConsideredTypes( constructorChoices.Remove(filterConstructorChoice); foreach (var (implementationType, constructor) in types.ConstructorChoices) - constructorChoices[implementationType] = constructor; + constructorChoices[implementationType.UnboundIfGeneric()] = constructor; } ImplementationToConstructorChoice = constructorChoices; @@ -107,18 +135,22 @@ public CurrentlyConsideredTypes( var decoratorInterfaces = ImmutableHashSet.Empty; foreach (var types in typesFromAttributes) { - decoratorInterfaces = decoratorInterfaces.Except(types.FilterDecorator); - decoratorInterfaces = decoratorInterfaces.Union(types.Decorator); + decoratorInterfaces = decoratorInterfaces.Except(types.FilterDecorator.Select(c => c.UnboundIfGeneric())); + decoratorInterfaces = decoratorInterfaces.Union(types.Decorator.Select(c => c.UnboundIfGeneric())); } - var decoratorTypes = GetSetOfTypesWithProperties(t => t.Decorator, t => t.FilterDecorator); + var decoratorTypes = GetSetOfTypesWithProperties( + t => t.Decorator, + t => t.FilterDecorator); InterfaceToDecorators = decoratorTypes .OfType() .GroupBy(nts => { - var namedTypeSymbol = nts.AllInterfaces - .Single(t => decoratorInterfaces.Contains(t.OriginalDefinition, SymbolEqualityComparer.Default)); - return namedTypeSymbol.TypeArguments.First(); + var namedTypeSymbol = nts.OriginalDefinition.AllInterfaces + .Single(t => decoratorInterfaces.Contains(t.UnboundIfGeneric(), SymbolEqualityComparer.Default)); + return namedTypeSymbol.TypeArguments.FirstOrDefault() is INamedTypeSymbol interfaceTypeSymbol + ? interfaceTypeSymbol.UnboundIfGeneric() + : throw new Exception("Decorator should implement decorator interface"); }, SymbolEqualityComparer.Default) .ToDictionary(g => g.Key, g => (IReadOnlyList) g.ToList(), SymbolEqualityComparer.Default); @@ -133,17 +165,17 @@ public CurrentlyConsideredTypes( decoratorSequenceChoices[decoratedType] = decoratorSequence; } - InterfaceSequenceChoices = decoratorSequenceChoices + DecoratorInterfaceSequenceChoices = decoratorSequenceChoices .Where(kvp => kvp.Key.TypeKind == TypeKind.Interface) .ToDictionary(kvp => kvp.Key, kvp => kvp.Value); - ImplementationSequenceChoices = decoratorSequenceChoices + DecoratorImplementationSequenceChoices = decoratorSequenceChoices .Where(kvp => kvp.Key.TypeKind is TypeKind.Class or TypeKind.Struct) .ToDictionary(kvp => kvp.Key, kvp => kvp.Value); ImplementationMap = allImplementations - .Where(t => !decoratorTypes.Contains(t.OriginalDefinition)) - .Where(t => !compositeTypes.Contains(t.OriginalDefinition)) + .Where(t => !decoratorTypes.Contains(t.UnboundIfGeneric())) + .Where(t => !compositeTypes.Contains(t.UnboundIfGeneric())) .SelectMany(i => { return i.AllInterfaces.OfType().Select(ii => (ii, i)).Prepend((i, i)); }) .GroupBy(t => t.Item1.UnboundIfGeneric(), t => t.Item2) .ToDictionary(g => g.Key, g => (IReadOnlyList) g.Distinct(SymbolEqualityComparer.Default).OfType().ToList()); @@ -158,8 +190,7 @@ public CurrentlyConsideredTypes( .ToImmutableHashSet(SymbolEqualityComparer.Default); foreach (var filterConcreteType in allImplementations - .Where(i => i.AllDerivedTypes() - .Select(t => t.OriginalDefinition) + .Where(i => i.OriginalDefinitionIfUnbound().AllDerivedTypes() .Any(inter => filterInterfaceTypes.Contains(inter)))) initializers.Remove(filterConcreteType); @@ -169,7 +200,7 @@ public CurrentlyConsideredTypes( .ToList(); foreach (var filterConcreteType in filterConcreteTypes) - initializers.Remove(filterConcreteType); + initializers.Remove(filterConcreteType.UnboundIfGeneric()); var interfaceTypes = types .TypeInitializers @@ -181,7 +212,7 @@ public CurrentlyConsideredTypes( { foreach (var (interfaceType, initializer) in interfaceTypes) { - if (i.AllDerivedTypes().Select(d => d.OriginalDefinition).Contains(interfaceType, SymbolEqualityComparer.Default)) + if (i.OriginalDefinitionIfUnbound().AllDerivedTypes().Contains(interfaceType, SymbolEqualityComparer.Default)) { return ((INamedTypeSymbol, INamedTypeSymbol, IMethodSymbol)?) (i, interfaceType, initializer); } @@ -190,7 +221,7 @@ public CurrentlyConsideredTypes( return null; }) .OfType<(INamedTypeSymbol, INamedTypeSymbol, IMethodSymbol)>()) - initializers[implementationType] = (interfaceType, initializerMethod); + initializers[implementationType.UnboundIfGeneric()] = (interfaceType, initializerMethod); var concreteTypes = types .TypeInitializers @@ -198,7 +229,7 @@ public CurrentlyConsideredTypes( .ToList(); foreach (var (implementation, initializer) in concreteTypes) - initializers[implementation] = (implementation, initializer); + initializers[implementation.UnboundIfGeneric()] = (implementation.UnboundIfGeneric(), initializer); } ImplementationToInitializer = initializers; @@ -262,17 +293,26 @@ public CurrentlyConsideredTypes( var ret = ImmutableHashSet.Empty; foreach (var types in typesFromAttributes) { - ret = ret.Except(filteredPropertyGivingTypesGetter(types)); + var filterPropertyGivingTypes = filteredPropertyGivingTypesGetter(types); + ret = ret.Except(allImplementations + .Where(i => + { + var derivedTypes = i.AllDerivedTypes().Select(t => t.UnboundIfGeneric()).ToList(); + return filterPropertyGivingTypes.Any(t => + derivedTypes.Contains(t.UnboundIfGeneric(), SymbolEqualityComparer.Default)); + }) + .Select(i => i.UnboundIfGeneric()) + .ToImmutableHashSet(SymbolEqualityComparer.Default)); var propertyGivingTypes = propertyGivingTypesGetter(types); ret = ret.Union(allImplementations .Where(i => { - var derivedTypes = i.AllDerivedTypes().Select(t => t.OriginalDefinition).ToList(); + var derivedTypes = i.AllDerivedTypes().Select(t => t.UnboundIfGeneric()).ToList(); return propertyGivingTypes.Any(t => - derivedTypes.Contains(t.OriginalDefinition, SymbolEqualityComparer.Default)); + derivedTypes.Contains(t.UnboundIfGeneric(), SymbolEqualityComparer.Default)); }) - .Distinct(SymbolEqualityComparer.Default) + .Select(i => i.UnboundIfGeneric()) .ToImmutableHashSet(SymbolEqualityComparer.Default)); } @@ -290,8 +330,8 @@ public CurrentlyConsideredTypes( public IReadOnlyDictionary InterfaceToComposite { get; } public IReadOnlyDictionary ImplementationToConstructorChoice { get; } public IReadOnlyDictionary> InterfaceToDecorators { get; } - public IReadOnlyDictionary> InterfaceSequenceChoices { get; } - public IReadOnlyDictionary> ImplementationSequenceChoices { get; } + public IReadOnlyDictionary> DecoratorInterfaceSequenceChoices { get; } + public IReadOnlyDictionary> DecoratorImplementationSequenceChoices { get; } public IReadOnlyDictionary> ImplementationMap { get; } public IReadOnlyDictionary ImplementationToInitializer { get; } public IReadOnlyDictionary<(INamedTypeSymbol, ITypeParameterSymbol), IReadOnlyList> GenericParameterSubstitutes { get; } diff --git a/Main/Configuration/TypesFromAttributes.cs b/Main/Configuration/TypesFromAttributes.cs index fa35f7bc..f6a2e712 100644 --- a/Main/Configuration/TypesFromAttributes.cs +++ b/Main/Configuration/TypesFromAttributes.cs @@ -1,3 +1,5 @@ +using MrMeeseeks.DIE.Extensions; + namespace MrMeeseeks.DIE.Configuration; internal interface ITypesFromAttributes @@ -164,7 +166,7 @@ internal ScopeTypesFromAttributes( { if (t is null) return null; - var implementationType = t.Value.Item1; + var implementationType = t.Value.Item1.OriginalDefinitionIfUnbound(); var parameterTypes = t.Value.Item2; if (implementationType is null) return null; @@ -218,6 +220,7 @@ internal ScopeTypesFromAttributes( return ((INamedTypeSymbol, IMethodSymbol)?) null; var initializationMethod = type + .OriginalDefinitionIfUnbound() .GetMembers(methodName) .OfType() .FirstOrDefault(m => m.Parameters.Length == 0); diff --git a/Main/Extensions/INamedTypeSymbolExtensions.cs b/Main/Extensions/INamedTypeSymbolExtensions.cs index 3341b498..e92a6ebe 100644 --- a/Main/Extensions/INamedTypeSymbolExtensions.cs +++ b/Main/Extensions/INamedTypeSymbolExtensions.cs @@ -21,4 +21,9 @@ internal static INamedTypeSymbol UnboundIfGeneric(this INamedTypeSymbol type) => type.IsGenericType && !type.IsUnboundGenericType ? type.ConstructUnboundGenericType() : type; + + internal static INamedTypeSymbol OriginalDefinitionIfUnbound(this INamedTypeSymbol type) => + type.IsUnboundGenericType + ? type.OriginalDefinition + : type; } \ No newline at end of file diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs index 8face208..1158b3a3 100644 --- a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs @@ -453,7 +453,8 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup if (_checkTypeProperties.ShouldBeComposite(interfaceType)) { var implementations = _checkTypeProperties.MapToImplementations(interfaceType); - var compositeImplementationType = _checkTypeProperties.GetCompositeFor(interfaceType); + var compositeImplementationType = _checkTypeProperties.GetCompositeFor(interfaceType) + ?? throw new Exception("No or multiple composite implementations"); var interfaceResolutions = implementations.Select(i => SwitchInterfaceWithoutComposition(new CreateInterfaceParameter( interfaceType, i, diff --git a/Sample/Container.cs b/Sample/Container.cs index b5ebb3b9..370f4afe 100644 --- a/Sample/Container.cs +++ b/Sample/Container.cs @@ -7,6 +7,8 @@ [assembly:TransientScopeRootAggregation(typeof(ITransientScopeRoot))] [assembly:ScopeRootAggregation(typeof(IScopeRoot))] [assembly:TransientAggregation(typeof(ITransient))] +[assembly:SyncTransientAggregation(typeof(ISyncTransient))] +[assembly:AsyncTransientAggregation(typeof(IAsyncTransient))] [assembly:DecoratorAggregation(typeof(IDecorator<>))] [assembly:CompositeAggregation(typeof(IComposite<>))] [assembly:TypeInitializer(typeof(ITypeInitializer), nameof(ITypeInitializer.Initialize))] diff --git a/Sample/Context.cs b/Sample/Context.cs index dd0f2803..bce43d59 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -1,14 +1,22 @@ using System.Collections.Generic; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration; using MrMeeseeks.DIE.Sample; -namespace MrMeeseeks.DIE.Test.Generics.SubstituteCollection.Double; +namespace MrMeeseeks.DIE.Test.Generics.Configuration.InitializerImplementationSync; -internal interface IInterface {} +internal class Dependency +{ + internal void Initialize() + { + IsInitialized = true; + } -internal class Class : IInterface {} + public bool IsInitialized { get; private set; } +} -[GenericParameterSubstituteAggregation(typeof(Class<,>), "T1", typeof(int), typeof(string))] -[CreateFunction(typeof(IReadOnlyList>), "Create")] -internal partial class Container {} \ No newline at end of file +[TypeInitializer(typeof(Dependency<>), nameof(Dependency.Initialize))] +[CreateFunction(typeof(Dependency), "Create")] +internal partial class Container +{ + +} \ No newline at end of file diff --git a/Sample/MarkerInterfaces.cs b/Sample/MarkerInterfaces.cs index 870e169d..121a865e 100644 --- a/Sample/MarkerInterfaces.cs +++ b/Sample/MarkerInterfaces.cs @@ -8,6 +8,8 @@ public interface IScopeInstance { } public interface ITransientScopeRoot { } public interface IScopeRoot { } public interface ITransient { } +public interface ISyncTransient { } +public interface IAsyncTransient { } public interface IDecorator { } public interface IComposite { } public interface ITypeInitializer diff --git a/Test/AssemblyInfo.cs b/Test/AssemblyInfo.cs index 25e97b5b..7a478ec0 100644 --- a/Test/AssemblyInfo.cs +++ b/Test/AssemblyInfo.cs @@ -1,6 +1,5 @@ using MrMeeseeks.DIE.Configuration; using MrMeeseeks.DIE.Test; -using TestChild; [assembly:ContainerInstanceAggregation(typeof(IContainerInstance))] [assembly:TransientScopeInstanceAggregation(typeof(ITransientScopeInstance))] @@ -8,6 +7,8 @@ [assembly:TransientScopeRootAggregation(typeof(ITransientScopeRoot))] [assembly:ScopeRootAggregation(typeof(IScopeRoot))] [assembly:TransientAggregation(typeof(ITransient))] +[assembly:SyncTransientAggregation(typeof(ISyncTransient))] +[assembly:AsyncTransientAggregation(typeof(IAsyncTransient))] [assembly:DecoratorAggregation(typeof(IDecorator<>))] [assembly:CompositeAggregation(typeof(IComposite<>))] [assembly:TypeInitializer(typeof(ITypeInitializer), nameof(ITypeInitializer.Initialize))] diff --git a/Test/Generics/Configuration/AsyncTransient.cs b/Test/Generics/Configuration/AsyncTransient.cs new file mode 100644 index 00000000..1f08c777 --- /dev/null +++ b/Test/Generics/Configuration/AsyncTransient.cs @@ -0,0 +1,41 @@ +using System; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Generics.Configuration.AsyncTransient; + +internal class Managed : IAsyncDisposable +{ + public ValueTask DisposeAsync() + { + return ValueTask.CompletedTask; + } +} + +internal class Class : IAsyncTransient, IAsyncDisposable +{ + internal Class(Managed _) { } + internal bool IsDisposed { get; private set; } + public async ValueTask DisposeAsync() + { + await Task.Delay(500); + IsDisposed = true; + } +} + +[CreateFunction(typeof(Class), "Create")] +internal partial class Container {} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + await using var instance = container.Create(); + Assert.False(instance.IsDisposed); + await container.DisposeAsync().ConfigureAwait(false); + Assert.False(instance.IsDisposed); + } +} \ No newline at end of file diff --git a/Test/Generics/Configuration/AsyncTransientWithJustTransient.cs b/Test/Generics/Configuration/AsyncTransientWithJustTransient.cs new file mode 100644 index 00000000..05605e9b --- /dev/null +++ b/Test/Generics/Configuration/AsyncTransientWithJustTransient.cs @@ -0,0 +1,41 @@ +using System; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Generics.Configuration.AsyncTransientWithJustTransient; + +internal class Managed : IAsyncDisposable +{ + public ValueTask DisposeAsync() + { + return ValueTask.CompletedTask; + } +} + +internal class Class : ITransient, IAsyncDisposable +{ + internal Class(Managed _) { } + internal bool IsDisposed { get; private set; } + public async ValueTask DisposeAsync() + { + await Task.Delay(500); + IsDisposed = true; + } +} + +[CreateFunction(typeof(Class), "Create")] +internal partial class Container {} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + await using var instance = container.Create(); + Assert.False(instance.IsDisposed); + await container.DisposeAsync().ConfigureAwait(false); + Assert.False(instance.IsDisposed); + } +} \ No newline at end of file diff --git a/Test/Generics/Configuration/Composite.cs b/Test/Generics/Configuration/Composite.cs new file mode 100644 index 00000000..c0174ae3 --- /dev/null +++ b/Test/Generics/Configuration/Composite.cs @@ -0,0 +1,47 @@ +using System.Collections.Generic; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Generics.Configuration.Composite; + +internal interface IInterface +{ + IReadOnlyList Implementations { get; } +} + +internal class BaseA : IInterface +{ + public IReadOnlyList Implementations => new[] { this }; +} + +internal class BaseB : IInterface +{ + public IReadOnlyList Implementations => new[] { this }; +} + +internal class Composite : IInterface, IComposite +{ + public IReadOnlyList Implementations { get; } + + internal Composite( + IReadOnlyList implementations) => + Implementations = implementations; +} + +[GenericParameterChoice(typeof(Composite<>), "T0", typeof(int))] +[CreateFunction(typeof(IInterface), "Create")] +internal partial class Container +{ + +} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var composite = container.Create(); + Assert.IsType>(composite); + } +} \ No newline at end of file diff --git a/Test/Generics/Configuration/ConstructorChoice.cs b/Test/Generics/Configuration/ConstructorChoice.cs new file mode 100644 index 00000000..66d00ded --- /dev/null +++ b/Test/Generics/Configuration/ConstructorChoice.cs @@ -0,0 +1,34 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Generics.Configuration.ConstructorChoiceFoo; + +internal interface IInterface {} + +internal class DependencyA : IInterface { } + +internal class DependencyB : IInterface { } + +internal class Implementation +{ + public IInterface Dependency { get; } + + internal Implementation(DependencyA a) => Dependency = a; + + internal Implementation(DependencyB b) => Dependency = b; +} + +[ConstructorChoice(typeof(Implementation<>), typeof(DependencyB))] +[CreateFunction(typeof(Implementation), "Create")] +internal partial class Container {} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var instance = container.Create(); + Assert.IsType(instance.Dependency); + } +} \ No newline at end of file diff --git a/Test/Generics/Configuration/ContainerInstance.cs b/Test/Generics/Configuration/ContainerInstance.cs new file mode 100644 index 00000000..4c9b0c3f --- /dev/null +++ b/Test/Generics/Configuration/ContainerInstance.cs @@ -0,0 +1,22 @@ +using System; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Generics.Configuration.ContainerInstance; + +internal class Class : IContainerInstance { } + +[CreateFunction(typeof(Class), "Create")] +internal partial class Container {} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var instance0 = container.Create(); + var instance1 = container.Create(); + Assert.Same(instance0, instance1); + } +} \ No newline at end of file diff --git a/Test/Generics/Configuration/ContainerInstanceWithDifferentGenericParameter.cs b/Test/Generics/Configuration/ContainerInstanceWithDifferentGenericParameter.cs new file mode 100644 index 00000000..b4b49cdd --- /dev/null +++ b/Test/Generics/Configuration/ContainerInstanceWithDifferentGenericParameter.cs @@ -0,0 +1,23 @@ +using System; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Generics.Configuration.ContainerInstanceWithDifferentGenericParameter; + +internal class Class : IContainerInstance { } + +[CreateFunction(typeof(Class), "Create")] +[CreateFunction(typeof(Class), "CreateString")] +internal partial class Container {} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var instance0 = container.Create(); + var instance1 = container.CreateString(); + Assert.NotSame(instance0, instance1); + } +} \ No newline at end of file diff --git a/Test/Generics/Configuration/Decorator.cs b/Test/Generics/Configuration/Decorator.cs new file mode 100644 index 00000000..52246c2f --- /dev/null +++ b/Test/Generics/Configuration/Decorator.cs @@ -0,0 +1,54 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Generics.Configuration.Decorator; + +internal interface IInterface +{ + IInterface Decorated { get; } +} + +internal class Implementation : IInterface +{ + public IInterface Decorated => this; +} + +internal class DecoratorA : IInterface, IDecorator +{ + public IInterface Decorated { get; } + + internal DecoratorA( + IInterface decorated) => + Decorated = decorated; +} + +internal class DecoratorB : IInterface, IDecorator +{ + public IInterface Decorated { get; } + + internal DecoratorB( + IInterface decorated) => + Decorated = decorated; +} + +[GenericParameterChoice(typeof(DecoratorA<>), "T0", typeof(int))] +[GenericParameterChoice(typeof(DecoratorB<>), "T0", typeof(string))] +[DecoratorSequenceChoice(typeof(IInterface), typeof(DecoratorA<>), typeof(DecoratorB<>))] +[CreateFunction(typeof(IInterface), "Create")] +internal partial class Container +{ + +} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var decorator = container.Create(); + Assert.IsType>(decorator); + Assert.IsType>(decorator.Decorated); + Assert.IsType(decorator.Decorated.Decorated); + } +} \ No newline at end of file diff --git a/Test/Generics/Configuration/InitializerImplementationAsync.cs b/Test/Generics/Configuration/InitializerImplementationAsync.cs new file mode 100644 index 00000000..3d5cf527 --- /dev/null +++ b/Test/Generics/Configuration/InitializerImplementationAsync.cs @@ -0,0 +1,34 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Generics.Configuration.InitializerImplementationAsync; + +internal class Dependency +{ + internal async Task InitializeAsync() + { + await Task.Delay(500).ConfigureAwait(false); + IsInitialized = true; + } + + public bool IsInitialized { get; private set; } +} + +[TypeInitializer(typeof(Dependency<>), nameof(Dependency.InitializeAsync))] +[CreateFunction(typeof(Dependency), "Create")] +internal partial class Container +{ + +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + var container = new Container(); + var instance = await container.CreateValueAsync().ConfigureAwait(false); + Assert.True(instance.IsInitialized); + } +} \ No newline at end of file diff --git a/Test/Generics/Configuration/InitializerImplementationAsyncValue.cs b/Test/Generics/Configuration/InitializerImplementationAsyncValue.cs new file mode 100644 index 00000000..24bf627c --- /dev/null +++ b/Test/Generics/Configuration/InitializerImplementationAsyncValue.cs @@ -0,0 +1,34 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Generics.Configuration.InitializerImplementationAsyncValue; + +internal class Dependency +{ + internal async ValueTask InitializeAsync() + { + await Task.Delay(500).ConfigureAwait(false); + IsInitialized = true; + } + + public bool IsInitialized { get; private set; } +} + +[TypeInitializer(typeof(Dependency<>), nameof(Dependency.InitializeAsync))] +[CreateFunction(typeof(Dependency), "Create")] +internal partial class Container +{ + +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + var container = new Container(); + var instance = await container.CreateValueAsync().ConfigureAwait(false); + Assert.True(instance.IsInitialized); + } +} \ No newline at end of file diff --git a/Test/Generics/Configuration/InitializerImplementationSync.cs b/Test/Generics/Configuration/InitializerImplementationSync.cs new file mode 100644 index 00000000..9424afb1 --- /dev/null +++ b/Test/Generics/Configuration/InitializerImplementationSync.cs @@ -0,0 +1,32 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Generics.Configuration.InitializerImplementationSync; + +internal class Dependency +{ + internal void Initialize() + { + IsInitialized = true; + } + + public bool IsInitialized { get; private set; } +} + +[TypeInitializer(typeof(Dependency<>), nameof(Dependency.Initialize))] +[CreateFunction(typeof(Dependency), "Create")] +internal partial class Container +{ + +} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var instance = container.Create(); + Assert.True(instance.IsInitialized); + } +} \ No newline at end of file diff --git a/Test/Generics/Configuration/InitializerInterfaceAsync.cs b/Test/Generics/Configuration/InitializerInterfaceAsync.cs new file mode 100644 index 00000000..d0032053 --- /dev/null +++ b/Test/Generics/Configuration/InitializerInterfaceAsync.cs @@ -0,0 +1,33 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Generics.Configuration.InitializerInterfaceAsync; + +internal class Dependency : ITaskTypeInitializer +{ + async Task ITaskTypeInitializer.InitializeAsync() + { + await Task.Delay(500).ConfigureAwait(false); + IsInitialized = true; + } + + public bool IsInitialized { get; private set; } +} + +[CreateFunction(typeof(Dependency), "Create")] +internal partial class Container +{ + +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + var container = new Container(); + var instance = await container.CreateValueAsync().ConfigureAwait(false); + Assert.True(instance.IsInitialized); + } +} \ No newline at end of file diff --git a/Test/Generics/Configuration/InitializerInterfaceAsyncValue.cs b/Test/Generics/Configuration/InitializerInterfaceAsyncValue.cs new file mode 100644 index 00000000..acb3c419 --- /dev/null +++ b/Test/Generics/Configuration/InitializerInterfaceAsyncValue.cs @@ -0,0 +1,33 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Generics.Configuration.InitializerInterfaceAsyncValue; + +internal class Dependency : IValueTaskTypeInitializer +{ + async ValueTask IValueTaskTypeInitializer.InitializeAsync() + { + await Task.Delay(500).ConfigureAwait(false); + IsInitialized = true; + } + + public bool IsInitialized { get; private set; } +} + +[CreateFunction(typeof(Dependency), "Create")] +internal partial class Container +{ + +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + var container = new Container(); + var instance = await container.CreateValueAsync().ConfigureAwait(false); + Assert.True(instance.IsInitialized); + } +} \ No newline at end of file diff --git a/Test/Generics/Configuration/InitializerInterfaceSync.cs b/Test/Generics/Configuration/InitializerInterfaceSync.cs new file mode 100644 index 00000000..152c69e5 --- /dev/null +++ b/Test/Generics/Configuration/InitializerInterfaceSync.cs @@ -0,0 +1,31 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Generics.Configuration.InitializerInterfaceSync; + +internal class Dependency : ITypeInitializer +{ + void ITypeInitializer.Initialize() + { + IsInitialized = true; + } + + public bool IsInitialized { get; private set; } +} + +[CreateFunction(typeof(Dependency), "Create")] +internal partial class Container +{ + +} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var instance = container.Create(); + Assert.True(instance.IsInitialized); + } +} \ No newline at end of file diff --git a/Test/Generics/Configuration/InterfaceGenericComposite.cs b/Test/Generics/Configuration/InterfaceGenericComposite.cs new file mode 100644 index 00000000..901e5e96 --- /dev/null +++ b/Test/Generics/Configuration/InterfaceGenericComposite.cs @@ -0,0 +1,47 @@ +using System.Collections.Generic; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Generics.Configuration.InterfaceGenericComposite; + +internal interface IInterface +{ + IReadOnlyList> Implementations { get; } +} + +internal class BaseA : IInterface +{ + public IReadOnlyList> Implementations => new[] { this }; +} + +internal class BaseB : IInterface +{ + public IReadOnlyList> Implementations => new[] { this }; +} + +internal class Composite : IInterface, IComposite> +{ + public IReadOnlyList> Implementations { get; } + + internal Composite( + IReadOnlyList> implementations) => + Implementations = implementations; +} + +[GenericParameterChoice(typeof(Composite<,>), "T1", typeof(string))] +[CreateFunction(typeof(IInterface), "Create")] +internal partial class Container +{ + +} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var composite = container.Create(); + Assert.IsType>(composite); + } +} \ No newline at end of file diff --git a/Test/Generics/Configuration/InterfaceGenericDecorator.cs b/Test/Generics/Configuration/InterfaceGenericDecorator.cs new file mode 100644 index 00000000..95219d4d --- /dev/null +++ b/Test/Generics/Configuration/InterfaceGenericDecorator.cs @@ -0,0 +1,54 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Generics.Configuration.InterfaceGenericDecorator; + +internal interface IInterface +{ + IInterface Decorated { get; } +} + +internal class Implementation : IInterface +{ + public IInterface Decorated => this; +} + +internal class DecoratorA : IInterface, IDecorator> +{ + public IInterface Decorated { get; } + + internal DecoratorA( + IInterface decorated) => + Decorated = decorated; +} + +internal class DecoratorB : IInterface, IDecorator> +{ + public IInterface Decorated { get; } + + internal DecoratorB( + IInterface decorated) => + Decorated = decorated; +} + +[GenericParameterChoice(typeof(DecoratorA<,>), "T0", typeof(int))] +[GenericParameterChoice(typeof(DecoratorB<,>), "T0", typeof(string))] +[DecoratorSequenceChoice(typeof(IInterface<>), typeof(DecoratorA<,>), typeof(DecoratorB<,>))] +[CreateFunction(typeof(IInterface), "Create")] +internal partial class Container +{ + +} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var decorator = container.Create(); + Assert.IsType>(decorator); + Assert.IsType>(decorator.Decorated); + Assert.IsType>(decorator.Decorated.Decorated); + } +} \ No newline at end of file diff --git a/Test/Generics/Configuration/ScopeInstance.cs b/Test/Generics/Configuration/ScopeInstance.cs new file mode 100644 index 00000000..757581ee --- /dev/null +++ b/Test/Generics/Configuration/ScopeInstance.cs @@ -0,0 +1,34 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Generics.Configuration.ScopeInstance; + +internal class Class : ITransientScopeInstance { } + +internal class ScopeRoot : ITransientScopeRoot +{ + public Class Dependency0 { get; } + public Class Dependency1 { get; } + + internal ScopeRoot( + Class dependency0, + Class dependency1) + { + Dependency0 = dependency0; + Dependency1 = dependency1; + } +} + +[CreateFunction(typeof(ScopeRoot), "Create")] +internal partial class Container {} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var scopeRoot = container.Create(); + Assert.Same(scopeRoot.Dependency0, scopeRoot.Dependency1); + } +} \ No newline at end of file diff --git a/Test/Generics/Configuration/ScopeInstanceWithDifferentGenericParameter.cs b/Test/Generics/Configuration/ScopeInstanceWithDifferentGenericParameter.cs new file mode 100644 index 00000000..6d27b555 --- /dev/null +++ b/Test/Generics/Configuration/ScopeInstanceWithDifferentGenericParameter.cs @@ -0,0 +1,35 @@ +using System; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Generics.Configuration.ScopeInstanceWithDifferentGenericParameter; + +internal class Class : IScopeInstance { } + +internal class ScopeRoot : IScopeRoot +{ + public Class Dependency0 { get; } + public Class Dependency1 { get; } + + internal ScopeRoot( + Class dependency0, + Class dependency1) + { + Dependency0 = dependency0; + Dependency1 = dependency1; + } +} + +[CreateFunction(typeof(ScopeRoot), "Create")] +internal partial class Container {} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var scopeRoot = container.Create(); + Assert.NotSame(scopeRoot.Dependency0, scopeRoot.Dependency1); + } +} \ No newline at end of file diff --git a/Test/Generics/Configuration/ScopeRoot.cs b/Test/Generics/Configuration/ScopeRoot.cs new file mode 100644 index 00000000..37e348c7 --- /dev/null +++ b/Test/Generics/Configuration/ScopeRoot.cs @@ -0,0 +1,42 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Generics.Configuration.ScopeRoot; + +internal class ScopeInstance : IScopeInstance {} + +internal class ScopeRoot : IScopeRoot +{ + public ScopeInstance ScopeInstance { get; } + + internal ScopeRoot(ScopeInstance scopeInstance) => ScopeInstance = scopeInstance; +} + +internal class Root +{ + public ScopeRoot ScopeRoot { get; } + public ScopeInstance ScopeInstance { get; } + + internal Root( + ScopeRoot scopeRoot, + ScopeInstance scopeInstance) + { + ScopeRoot = scopeRoot; + ScopeInstance = scopeInstance; + } +} + +[CreateFunction(typeof(Root), "Create")] +internal partial class Container {} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var root = container.Create(); + Assert.NotSame(root.ScopeInstance, root.ScopeRoot.ScopeInstance); + } +} + diff --git a/Test/Generics/Configuration/SyncTransient.cs b/Test/Generics/Configuration/SyncTransient.cs new file mode 100644 index 00000000..18a5d083 --- /dev/null +++ b/Test/Generics/Configuration/SyncTransient.cs @@ -0,0 +1,35 @@ +using System; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Generics.Configuration.SyncTransient; + +internal class Managed : IDisposable +{ + public void Dispose() + { + } +} + +internal class Class : ISyncTransient, IDisposable +{ + internal Class(Managed _) { } + internal bool IsDisposed { get; private set; } + public void Dispose() => IsDisposed = true; +} + +[CreateFunction(typeof(Class), "Create")] +internal partial class Container {} + +public class Tests +{ + [Fact] + public void Test() + { + using var container = new Container(); + using var instance = container.Create(); + Assert.False(instance.IsDisposed); + container.Dispose(); + Assert.False(instance.IsDisposed); + } +} \ No newline at end of file diff --git a/Test/Generics/Configuration/SyncTransientWithJustTransient.cs b/Test/Generics/Configuration/SyncTransientWithJustTransient.cs new file mode 100644 index 00000000..5e599db0 --- /dev/null +++ b/Test/Generics/Configuration/SyncTransientWithJustTransient.cs @@ -0,0 +1,35 @@ +using System; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Generics.Configuration.SyncTransientWithJustTransient; + +internal class Managed : IDisposable +{ + public void Dispose() + { + } +} + +internal class Class : ITransient, IDisposable +{ + internal Class(Managed _) { } + internal bool IsDisposed { get; private set; } + public void Dispose() => IsDisposed = true; +} + +[CreateFunction(typeof(Class), "Create")] +internal partial class Container {} + +public class Tests +{ + [Fact] + public void Test() + { + using var container = new Container(); + using var instance = container.Create(); + Assert.False(instance.IsDisposed); + container.Dispose(); + Assert.False(instance.IsDisposed); + } +} \ No newline at end of file diff --git a/Test/Generics/Configuration/TransientScopeInstance.cs b/Test/Generics/Configuration/TransientScopeInstance.cs new file mode 100644 index 00000000..80ff9953 --- /dev/null +++ b/Test/Generics/Configuration/TransientScopeInstance.cs @@ -0,0 +1,35 @@ +using System; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Generics.Configuration.TransientScopeInstance; + +internal class Class : ITransientScopeInstance { } + +internal class TransientScopeRoot : ITransientScopeRoot +{ + public Class Dependency0 { get; } + public Class Dependency1 { get; } + + internal TransientScopeRoot( + Class dependency0, + Class dependency1) + { + Dependency0 = dependency0; + Dependency1 = dependency1; + } +} + +[CreateFunction(typeof(TransientScopeRoot), "Create")] +internal partial class Container {} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var transientScopeRoot = container.Create(); + Assert.Same(transientScopeRoot.Dependency0, transientScopeRoot.Dependency1); + } +} \ No newline at end of file diff --git a/Test/Generics/Configuration/TransientScopeInstanceWithDifferentGenericParameter.cs b/Test/Generics/Configuration/TransientScopeInstanceWithDifferentGenericParameter.cs new file mode 100644 index 00000000..c4005714 --- /dev/null +++ b/Test/Generics/Configuration/TransientScopeInstanceWithDifferentGenericParameter.cs @@ -0,0 +1,35 @@ +using System; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Generics.Configuration.TransientScopeInstanceWithDifferentGenericParameter; + +internal class Class : ITransientScopeInstance { } + +internal class TransientScopeRoot : ITransientScopeRoot +{ + public Class Dependency0 { get; } + public Class Dependency1 { get; } + + internal TransientScopeRoot( + Class dependency0, + Class dependency1) + { + Dependency0 = dependency0; + Dependency1 = dependency1; + } +} + +[CreateFunction(typeof(TransientScopeRoot), "Create")] +internal partial class Container {} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var transientScopeRoot = container.Create(); + Assert.NotSame(transientScopeRoot.Dependency0, transientScopeRoot.Dependency1); + } +} \ No newline at end of file diff --git a/Test/Generics/Configuration/TransientScopeRoot.cs b/Test/Generics/Configuration/TransientScopeRoot.cs new file mode 100644 index 00000000..bf4ffa5d --- /dev/null +++ b/Test/Generics/Configuration/TransientScopeRoot.cs @@ -0,0 +1,42 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Generics.Configuration.TransientScopeRoot; + +internal class ScopeInstance : IScopeInstance {} + +internal class TransientScopeRoot : ITransientScopeRoot +{ + public ScopeInstance ScopeInstance { get; } + + internal TransientScopeRoot(ScopeInstance scopeInstance) => ScopeInstance = scopeInstance; +} + +internal class Root +{ + public TransientScopeRoot TransientScopeRoot { get; } + public ScopeInstance ScopeInstance { get; } + + internal Root( + TransientScopeRoot transientScopeRoot, + ScopeInstance scopeInstance) + { + TransientScopeRoot = transientScopeRoot; + ScopeInstance = scopeInstance; + } +} + +[CreateFunction(typeof(Root), "Create")] +internal partial class Container {} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var root = container.Create(); + Assert.NotSame(root.ScopeInstance, root.TransientScopeRoot.ScopeInstance); + } +} + diff --git a/Test/MarkerInterfaces.cs b/Test/MarkerInterfaces.cs index bbcc48cd..ce8d1b99 100644 --- a/Test/MarkerInterfaces.cs +++ b/Test/MarkerInterfaces.cs @@ -8,6 +8,8 @@ public interface IScopeInstance { } public interface ITransientScopeRoot { } public interface IScopeRoot { } public interface ITransient { } +public interface ISyncTransient { } +public interface IAsyncTransient { } public interface IDecorator { } public interface IComposite { } public interface ITypeInitializer From 811f9634e94550ca824f930f66cf3b8706a0192c Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sun, 8 May 2022 08:22:17 +0200 Subject: [PATCH 069/162] Implemented record support --- Main/Configuration/Attributes.cs | 16 ++++++ Main/Configuration/CheckTypeProperties.cs | 52 +++++++++++++++++-- .../Configuration/CurrentlyConsideredTypes.cs | 15 ++++++ Main/Configuration/TypesFromAttributes.cs | 42 ++++++++++++++- .../Function/FunctionResolutionBuilder.cs | 11 ++-- Main/WellKnownTypes.cs | 12 +++++ Sample/Context.cs | 27 +++++----- Sample/Program.cs | 5 +- Test/Record/CustomProperty.cs | 29 +++++++++++ Test/Record/PrimaryConstr.cs | 23 ++++++++ Test/Record/Vanilla.cs | 20 +++++++ 11 files changed, 230 insertions(+), 22 deletions(-) create mode 100644 Test/Record/CustomProperty.cs create mode 100644 Test/Record/PrimaryConstr.cs create mode 100644 Test/Record/Vanilla.cs diff --git a/Main/Configuration/Attributes.cs b/Main/Configuration/Attributes.cs index dc8f1f2d..433b19d3 100644 --- a/Main/Configuration/Attributes.cs +++ b/Main/Configuration/Attributes.cs @@ -210,6 +210,22 @@ public FilterConstructorChoiceAttribute(Type implementationType) } } +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] +public class PropertyChoiceAttribute : Attribute +{ + public PropertyChoiceAttribute(Type implementationType, params string[] propertyName) + { + } +} + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class FilterPropertyChoiceAttribute : Attribute +{ + public FilterPropertyChoiceAttribute(Type implementationType) + { + } +} + [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class CustomScopeForRootTypesAttribute : Attribute { diff --git a/Main/Configuration/CheckTypeProperties.cs b/Main/Configuration/CheckTypeProperties.cs index f8844f3d..494ecc14 100644 --- a/Main/Configuration/CheckTypeProperties.cs +++ b/Main/Configuration/CheckTypeProperties.cs @@ -32,6 +32,7 @@ internal interface ICheckTypeProperties INamedTypeSymbol? MapToSingleFittingImplementation(INamedTypeSymbol type); IReadOnlyList MapToImplementations(INamedTypeSymbol typeSymbol); (INamedTypeSymbol Type, IMethodSymbol Initializer)? GetInitializerFor(INamedTypeSymbol implementationType); + IReadOnlyList? GetPropertyChoicesFor(INamedTypeSymbol implementationType); } internal class CheckTypeProperties : ICheckTypeProperties @@ -93,14 +94,52 @@ public ScopeLevel GetScopeLevelFor(INamedTypeSymbol implementationType) public IMethodSymbol? GetConstructorChoiceFor(INamedTypeSymbol implementationType) { + if (_currentlyConsideredTypes.ImplementationToConstructorChoice.TryGetValue( + implementationType.UnboundIfGeneric(), out var constr)) + return constr; + var typeToChoseFrom = implementationType.OriginalDefinitionIfUnbound(); if (typeToChoseFrom.Constructors.Length == 1 && typeToChoseFrom.Constructors.SingleOrDefault() is { } constructor) return constructor; - return _currentlyConsideredTypes.ImplementationToConstructorChoice.TryGetValue(implementationType.UnboundIfGeneric(), out var constr) - ? constr : - null; + return typeToChoseFrom switch + { + // If reference record and two constructors, decide for the constructor which isn't the copy-constructor + { IsRecord: true, IsValueType: false, Constructors.Length: 2 } + when typeToChoseFrom + .Constructors.SingleOrDefault(c => + c.Parameters.Length != 1 || + !SymbolEqualityComparer.Default.Equals(c.Parameters[0].Type, implementationType)) + is { } constructor0 => constructor0, + + // If value record and three constructors, decide for the constructor which isn't the copy-constructor or the parameterless constructor + { IsRecord: true, IsValueType: true, Constructors.Length: 3 } + when typeToChoseFrom.Constructors + .Where(c => c.Parameters.Length > 0) + .SingleOrDefault(c => + c.Parameters.Length != 1 || + !SymbolEqualityComparer.Default.Equals(c.Parameters[0].Type, implementationType)) + is { } constructor1 => constructor1, + + // If value record and two constructors, decide for the parameterless constructor + { IsRecord: true, IsValueType: true, Constructors.Length: 2 } + when typeToChoseFrom.Constructors + .SingleOrDefault(c => c.Parameters.Length == 0) + is { } constructor2 => constructor2, + + // If value type and two constructors, decide for the constructor which isn't the parameterless constructor + { IsRecord: false, IsValueType: true, Constructors.Length: 2 } when typeToChoseFrom.Constructors + .SingleOrDefault(c => c.Parameters.Length > 0) + is { } constructor3 => constructor3, + + // If value type and one constructor, decide for the parameterless constructor + { IsRecord: false, IsValueType: true, Constructors.Length: 1 } when typeToChoseFrom.Constructors + .SingleOrDefault() + is { } constructor4 => constructor4, + + _ => null + }; } public bool ShouldBeDecorated(INamedTypeSymbol interfaceType) => _currentlyConsideredTypes.InterfaceToDecorators.ContainsKey(interfaceType.UnboundIfGeneric()); @@ -299,4 +338,11 @@ IEnumerable> GetAll } return null; } + + public IReadOnlyList? GetPropertyChoicesFor(INamedTypeSymbol implementationType) => + _currentlyConsideredTypes.PropertyChoices.TryGetValue( + implementationType.UnboundIfGeneric(), + out var properties) + ? properties + : null; } \ No newline at end of file diff --git a/Main/Configuration/CurrentlyConsideredTypes.cs b/Main/Configuration/CurrentlyConsideredTypes.cs index fcd9836e..141532b8 100644 --- a/Main/Configuration/CurrentlyConsideredTypes.cs +++ b/Main/Configuration/CurrentlyConsideredTypes.cs @@ -21,6 +21,7 @@ internal interface ICurrentlyConsideredTypes IReadOnlyDictionary ImplementationToInitializer { get; } IReadOnlyDictionary<(INamedTypeSymbol, ITypeParameterSymbol), IReadOnlyList> GenericParameterSubstitutes { get; } IReadOnlyDictionary<(INamedTypeSymbol, ITypeParameterSymbol), INamedTypeSymbol> GenericParameterChoices { get; } + IReadOnlyDictionary> PropertyChoices { get; } } internal class CurrentlyConsideredTypes : ICurrentlyConsideredTypes @@ -131,7 +132,20 @@ IEnumerable GetAllNamespaces(INamespaceSymbol root) } ImplementationToConstructorChoice = constructorChoices; + + var propertyChoices = new Dictionary>(SymbolEqualityComparer.Default); + foreach (var types in typesFromAttributes) + { + foreach (var filterPropertyChoice in types.FilterPropertyChoices) + propertyChoices.Remove(filterPropertyChoice); + + foreach (var (implementationType, properties) in types.PropertyChoices) + propertyChoices[implementationType.UnboundIfGeneric()] = properties; + } + + PropertyChoices = propertyChoices; + var decoratorInterfaces = ImmutableHashSet.Empty; foreach (var types in typesFromAttributes) { @@ -336,4 +350,5 @@ IEnumerable GetAllNamespaces(INamespaceSymbol root) public IReadOnlyDictionary ImplementationToInitializer { get; } public IReadOnlyDictionary<(INamedTypeSymbol, ITypeParameterSymbol), IReadOnlyList> GenericParameterSubstitutes { get; } public IReadOnlyDictionary<(INamedTypeSymbol, ITypeParameterSymbol), INamedTypeSymbol> GenericParameterChoices { get; } + public IReadOnlyDictionary> PropertyChoices { get; } } \ No newline at end of file diff --git a/Main/Configuration/TypesFromAttributes.cs b/Main/Configuration/TypesFromAttributes.cs index f6a2e712..9466007f 100644 --- a/Main/Configuration/TypesFromAttributes.cs +++ b/Main/Configuration/TypesFromAttributes.cs @@ -21,6 +21,7 @@ internal interface ITypesFromAttributes IReadOnlyList<(INamedTypeSymbol, IMethodSymbol)> TypeInitializers { get; } IReadOnlyList<(INamedTypeSymbol, ITypeParameterSymbol, IReadOnlyList)> GenericParameterSubstitutes { get; } IReadOnlyList<(INamedTypeSymbol, ITypeParameterSymbol, INamedTypeSymbol)> GenericParameterChoices { get; } + IReadOnlyList<(INamedTypeSymbol, IReadOnlyList)> PropertyChoices { get; } IReadOnlyList FilterSpy { get; } IReadOnlyList FilterImplementation { get; } IReadOnlyList FilterTransient { get; } @@ -37,7 +38,8 @@ internal interface ITypesFromAttributes IReadOnlyList FilterConstructorChoices { get; } IReadOnlyList FilterTypeInitializers { get; } IReadOnlyList<(INamedTypeSymbol, ITypeParameterSymbol, IReadOnlyList)> FilterGenericParameterSubstitutes { get; } - IReadOnlyList<(INamedTypeSymbol, ITypeParameterSymbol)> FilterGenericParameterChoices { get; } + IReadOnlyList<(INamedTypeSymbol, ITypeParameterSymbol)> FilterGenericParameterChoices { get; } + IReadOnlyList FilterPropertyChoices { get; } } internal class TypesFromAttributes : ScopeTypesFromAttributes @@ -211,6 +213,42 @@ internal ScopeTypesFromAttributes( .OfType() .ToList(); + PropertyChoices = (AttributeDictionary.TryGetValue(wellKnownTypes.PropertyChoiceAttribute, out var propertyChoiceGroup) ? propertyChoiceGroup : Enumerable.Empty()) + .Select(ad => + { + if (ad.ConstructorArguments.Length < 1) + return ((INamedTypeSymbol, IReadOnlyList)?) null; + if (ad.ConstructorArguments[0].Value is not INamedTypeSymbol implementationType) + return null; + var parameterTypes = ad + .ConstructorArguments[1] + .Values + .Select(tc => tc.Value) + .OfType() + .ToList(); + + var properties = implementationType + .OriginalDefinitionIfUnbound() + .GetMembers() + .OfType() + .Where(ps => parameterTypes.Contains(ps.Name)) + .ToList(); + + return (implementationType, properties); + }) + .OfType<(INamedTypeSymbol, IReadOnlyList)>() + .ToList(); + + FilterPropertyChoices = (AttributeDictionary.TryGetValue(wellKnownTypes.FilterPropertyChoiceAttribute, out var filterPropertyChoicesGroup) ? filterPropertyChoicesGroup : Enumerable.Empty()) + .Select(ad => + { + if (ad.ConstructorArguments.Length < 1) + return null; + return ad.ConstructorArguments[0].Value as INamedTypeSymbol; + }) + .OfType() + .ToList(); + TypeInitializers = (AttributeDictionary.TryGetValue(wellKnownTypes.TypeInitializerAttribute, out var group3) ? group3 : Enumerable.Empty()) .Select(ad => { @@ -399,6 +437,7 @@ bool CheckValidType(TypedConstant typedConstant, out INamedTypeSymbol type) public IReadOnlyList<(INamedTypeSymbol, IMethodSymbol)> TypeInitializers { get; } public IReadOnlyList<(INamedTypeSymbol, ITypeParameterSymbol, IReadOnlyList)> GenericParameterSubstitutes { get; } public IReadOnlyList<(INamedTypeSymbol, ITypeParameterSymbol, INamedTypeSymbol)> GenericParameterChoices { get; } + public IReadOnlyList<(INamedTypeSymbol, IReadOnlyList)> PropertyChoices { get; } public IReadOnlyList FilterSpy { get; } public IReadOnlyList FilterImplementation { get; } public IReadOnlyList FilterTransient { get; } @@ -416,4 +455,5 @@ bool CheckValidType(TypedConstant typedConstant, out INamedTypeSymbol type) public IReadOnlyList FilterTypeInitializers { get; } public IReadOnlyList<(INamedTypeSymbol, ITypeParameterSymbol, IReadOnlyList)> FilterGenericParameterSubstitutes { get; } public IReadOnlyList<(INamedTypeSymbol, ITypeParameterSymbol)> FilterGenericParameterChoices { get; } + public IReadOnlyList FilterPropertyChoices { get; } } \ No newline at end of file diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs index 1158b3a3..a6bfab9c 100644 --- a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs @@ -690,10 +690,13 @@ false when initializationMethod.ReturnType.Equals(_wellKnownTypes.ValueTask, Sym .Parameters .Select(p => ProcessChildType(p.Type, p.Name, implementationType, currentParameters)) .ToList()), - new ReadOnlyCollection<(string Name, Resolvable Dependency)>(implementationType - .GetMembers() - .OfType() - .Where(p => p.SetMethod?.IsInitOnly ?? false) + new ReadOnlyCollection<(string Name, Resolvable Dependency)>( + (_checkTypeProperties.GetPropertyChoicesFor(implementationType) + ?? implementationType + .GetMembers() + .OfType() + .Where(_ => !implementationType.IsRecord) + .Where(p => p.SetMethod?.IsInitOnly ?? false)) .Select(p => ProcessChildType(p.Type, p.Name, implementationType, currentParameters)) .ToList()), typeInitializationResolution); diff --git a/Main/WellKnownTypes.cs b/Main/WellKnownTypes.cs index 2aeee846..5a5d71b3 100644 --- a/Main/WellKnownTypes.cs +++ b/Main/WellKnownTypes.cs @@ -20,6 +20,7 @@ internal record WellKnownTypes( INamedTypeSymbol GenericParameterChoiceAttribute, INamedTypeSymbol DecoratorSequenceChoiceAttribute, INamedTypeSymbol ConstructorChoiceAttribute, + INamedTypeSymbol PropertyChoiceAttribute, INamedTypeSymbol TypeInitializerAttribute, INamedTypeSymbol FilterSpyAggregationAttribute, INamedTypeSymbol FilterSpyConstructorChoiceAggregationAttribute, @@ -38,6 +39,7 @@ internal record WellKnownTypes( INamedTypeSymbol FilterGenericParameterChoiceAttribute, INamedTypeSymbol FilterDecoratorSequenceChoiceAttribute, INamedTypeSymbol FilterConstructorChoiceAttribute, + INamedTypeSymbol FilterPropertyChoiceAttribute, INamedTypeSymbol FilterTypeInitializerAttribute, INamedTypeSymbol CustomScopeForRootTypesAttribute, INamedTypeSymbol CreateFunctionAttribute, @@ -148,6 +150,9 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK var constructorChoiceAttribute = compilation .GetTypeByMetadataName(typeof(ConstructorChoiceAttribute).FullName ?? ""); + var propertyChoiceAttribute = compilation + .GetTypeByMetadataName(typeof(PropertyChoiceAttribute).FullName ?? ""); + var filterSpyAggregationAttribute = compilation .GetTypeByMetadataName(typeof(FilterSpyAggregationAttribute).FullName ?? ""); @@ -193,6 +198,9 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK var filterConstructorChoiceAttribute = compilation .GetTypeByMetadataName(typeof(FilterConstructorChoiceAttribute).FullName ?? ""); + var filterPropertyChoiceAttribute = compilation + .GetTypeByMetadataName(typeof(FilterPropertyChoiceAttribute).FullName ?? ""); + var customScopeForRootTypesAttribute = compilation .GetTypeByMetadataName(typeof(CustomScopeForRootTypesAttribute).FullName ?? ""); @@ -222,6 +230,7 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK && genericParameterChoiceAttribute is not null && decoratorSequenceChoiceAttribute is not null && constructorChoiceAttribute is not null + && propertyChoiceAttribute is not null && typeInitializerAttribute is not null && filterSpyAggregationAttribute is not null && filterSpyConstructorChoiceAggregationAttribute is not null @@ -240,6 +249,7 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK && filterGenericParameterChoiceAttribute is not null && filterDecoratorSequenceChoiceAttribute is not null && filterConstructorChoiceAttribute is not null + && filterPropertyChoiceAttribute is not null && filterTypeInitializerAttribute is not null && customScopeForRootTypesAttribute is not null && createFunctionAttribute is not null @@ -281,6 +291,7 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK GenericParameterChoiceAttribute: genericParameterChoiceAttribute, DecoratorSequenceChoiceAttribute: decoratorSequenceChoiceAttribute, ConstructorChoiceAttribute: constructorChoiceAttribute, + PropertyChoiceAttribute: propertyChoiceAttribute, TypeInitializerAttribute: typeInitializerAttribute, FilterSpyAggregationAttribute: filterSpyAggregationAttribute, FilterSpyConstructorChoiceAggregationAttribute: filterSpyConstructorChoiceAggregationAttribute, @@ -299,6 +310,7 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK FilterGenericParameterChoiceAttribute: filterGenericParameterChoiceAttribute, FilterDecoratorSequenceChoiceAttribute: filterDecoratorSequenceChoiceAttribute, FilterConstructorChoiceAttribute: filterConstructorChoiceAttribute, + FilterPropertyChoiceAttribute: filterPropertyChoiceAttribute, FilterTypeInitializerAttribute: filterTypeInitializerAttribute, CustomScopeForRootTypesAttribute: customScopeForRootTypesAttribute, CreateFunctionAttribute: createFunctionAttribute, diff --git a/Sample/Context.cs b/Sample/Context.cs index bce43d59..f9d36e4c 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -1,22 +1,23 @@ using System.Collections.Generic; using MrMeeseeks.DIE.Configuration; -using MrMeeseeks.DIE.Sample; -namespace MrMeeseeks.DIE.Test.Generics.Configuration.InitializerImplementationSync; +namespace MrMeeseeks.DIE.Test.Record.PrimaryConstr; -internal class Dependency +internal interface IInterface {} + +internal class Implementation : IInterface {} + +internal class ImplementationA : IInterface {} + +internal class Dependency { - internal void Initialize() + public IReadOnlyList Item { get; } + + internal Dependency(IReadOnlyList item) { - IsInitialized = true; + Item = item; } - - public bool IsInitialized { get; private set; } } -[TypeInitializer(typeof(Dependency<>), nameof(Dependency.Initialize))] -[CreateFunction(typeof(Dependency), "Create")] -internal partial class Container -{ - -} \ No newline at end of file +[CreateFunction(typeof(Dependency), "Create")] +internal partial class Container{} \ No newline at end of file diff --git a/Sample/Program.cs b/Sample/Program.cs index 497ea562..1acfafea 100644 --- a/Sample/Program.cs +++ b/Sample/Program.cs @@ -1,9 +1,12 @@ using System; +using MrMeeseeks.DIE.Test.Record.PrimaryConstr; internal class Program { private static void Main() { - Console.WriteLine("Hello, world!"); + var container = new Container(); + var dependency = container.Create(); + } } \ No newline at end of file diff --git a/Test/Record/CustomProperty.cs b/Test/Record/CustomProperty.cs new file mode 100644 index 00000000..ca37247e --- /dev/null +++ b/Test/Record/CustomProperty.cs @@ -0,0 +1,29 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Record.CustomPropert; + +internal record Dependency; +internal record DependencyA; + +internal record Implementation(Dependency Dependency) +{ + internal DependencyA? DependencyA { get; init; } +} + +[PropertyChoice(typeof(Implementation), nameof(Implementation.DependencyA))] +[CreateFunction(typeof(Implementation), "Create")] +internal partial class Container{} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var instance = container.Create(); + Assert.IsType(instance); + Assert.IsType(instance.Dependency); + Assert.IsType(instance.DependencyA); + } +} \ No newline at end of file diff --git a/Test/Record/PrimaryConstr.cs b/Test/Record/PrimaryConstr.cs new file mode 100644 index 00000000..330c26b2 --- /dev/null +++ b/Test/Record/PrimaryConstr.cs @@ -0,0 +1,23 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Record.PrimaryConstr; + +internal record Dependency; + +internal record Implementation(Dependency Dependency); + +[CreateFunction(typeof(Implementation), "Create")] +internal partial class Container{} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var instance = container.Create(); + Assert.IsType(instance); + Assert.IsType(instance.Dependency); + } +} \ No newline at end of file diff --git a/Test/Record/Vanilla.cs b/Test/Record/Vanilla.cs new file mode 100644 index 00000000..fccdb594 --- /dev/null +++ b/Test/Record/Vanilla.cs @@ -0,0 +1,20 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Record.Vanilla; + +internal record Dependency; + +[CreateFunction(typeof(Dependency), "Create")] +internal partial class Container{} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var instance = container.Create(); + Assert.IsType(instance); + } +} \ No newline at end of file From 47e95af9c7f94a7ef2bae357d45b4ae828329471 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sat, 14 May 2022 16:51:27 +0200 Subject: [PATCH 070/162] Replaced Spy concept with collecting all type information from Context --- Directory.build.props | 1 - Main/Configuration/Attributes.cs | 80 +++--- Main/Configuration/CheckTypeProperties.cs | 66 ++++- .../Configuration/CurrentlyConsideredTypes.cs | 240 ++++++++++++------ Main/Configuration/TypesFromAttributes.cs | 212 +++++++++++----- Main/ContainerInfo.cs | 2 + Main/Extensions/INamedTypeSymbolExtensions.cs | 21 +- .../Function/FunctionResolutionBuilder.cs | 15 +- Main/RoslynExtensions.cs | 17 ++ Main/SourceGenerator.cs | 5 +- Main/WellKnownTypes.cs | 105 +++++--- MrMeeseeks.DIE.sln | 18 +- Sample/Container.cs | 4 +- Sample/Context.cs | 37 ++- Sample/Program.cs | 3 +- Sample/Sample.csproj | 1 + SampleChild/AssemblyInfo.cs | 17 ++ SampleChild/SampleChild.csproj | 9 +- SampleChild/lnternal.cs | 2 +- Spy/DiagLogger.cs | 24 -- Spy/ExecuteImpl.cs | 33 --- Spy/GetAllImplementations.cs | 30 --- Spy/Properties/launchSettings.json | 8 - Spy/RoslynExtensions.cs | 13 - Spy/SourceGenerator.cs | 19 -- Spy/Spy.csproj | 39 --- Spy/TypeReportGenerator.cs | 137 ---------- Test/AssemblyInfo.cs | 4 +- Test/Decorator/List.cs | 4 +- ...ubleBothChosenWithSingleOtherSubstitute.cs | 4 +- .../Choice/DoubleWithSingleOtherSubstitute.cs | 2 +- .../Choice/SingleWithSingleOtherSubstitute.cs | 2 +- .../Double.cs | 2 +- .../Single.cs | 2 +- Test/Generics/SubstituteCollection/Double.cs | 2 +- .../DoubleBothSubstituted.cs | 4 +- .../DoubleBothSubstitutedWithChoice.cs | 4 +- .../SubstituteCollection/DoubleWithChoice.cs | 2 +- Test/Generics/SubstituteCollection/Single.cs | 2 +- .../SubstituteCollection/SingleWithChoice.cs | 2 +- .../SubstituteCollection/TripleInsanity.cs | 6 +- .../AssemblyImplementationsAggregation.cs | 23 ++ .../Aggregation}/ExternalType.cs | 3 +- .../Aggregation/FilterAllImplementations.cs | 26 ++ .../Aggregation/InternalsVisibleTo.cs | 20 ++ Test/Implementation/Choice/Collection.cs | 28 ++ .../Choice/CollectionWithoutChoice.cs | 25 ++ .../Choice/SingleInCollection.cs | 23 ++ Test/Implementation/Choice/Vanilla.cs | 23 ++ .../Choice/VanillaWithoutChoice.cs | 22 ++ .../Choice/WithSingleInCollection.cs | 26 ++ Test/Spy/Implementations.cs | 29 --- Test/Test.csproj | 3 + TestChild/TestChild.csproj | 10 +- TestInternalsVisibleToChild/AssemblyInfo.cs | 17 ++ TestInternalsVisibleToChild/Public.cs | 124 +++++++++ .../TestInternalsVisibleToChild.csproj | 12 + TestInternalsVisibleToChild/lnternal.cs | 125 +++++++++ .../AssemblyInfo.cs | 4 +- TestNotInternalsVisibleToChild/Public.cs | 124 +++++++++ .../TestNotInternalsVisibleToChild.csproj | 12 + TestNotInternalsVisibleToChild/lnternal.cs | 125 +++++++++ 62 files changed, 1371 insertions(+), 633 deletions(-) create mode 100644 SampleChild/AssemblyInfo.cs delete mode 100644 Spy/DiagLogger.cs delete mode 100644 Spy/ExecuteImpl.cs delete mode 100644 Spy/GetAllImplementations.cs delete mode 100644 Spy/Properties/launchSettings.json delete mode 100644 Spy/RoslynExtensions.cs delete mode 100644 Spy/SourceGenerator.cs delete mode 100644 Spy/Spy.csproj delete mode 100644 Spy/TypeReportGenerator.cs create mode 100644 Test/Implementation/Aggregation/AssemblyImplementationsAggregation.cs rename Test/{ImplementationAggregation => Implementation/Aggregation}/ExternalType.cs (81%) create mode 100644 Test/Implementation/Aggregation/FilterAllImplementations.cs create mode 100644 Test/Implementation/Aggregation/InternalsVisibleTo.cs create mode 100644 Test/Implementation/Choice/Collection.cs create mode 100644 Test/Implementation/Choice/CollectionWithoutChoice.cs create mode 100644 Test/Implementation/Choice/SingleInCollection.cs create mode 100644 Test/Implementation/Choice/Vanilla.cs create mode 100644 Test/Implementation/Choice/VanillaWithoutChoice.cs create mode 100644 Test/Implementation/Choice/WithSingleInCollection.cs delete mode 100644 Test/Spy/Implementations.cs create mode 100644 TestInternalsVisibleToChild/AssemblyInfo.cs create mode 100644 TestInternalsVisibleToChild/Public.cs create mode 100644 TestInternalsVisibleToChild/TestInternalsVisibleToChild.csproj create mode 100644 TestInternalsVisibleToChild/lnternal.cs rename {Spy => TestNotInternalsVisibleToChild}/AssemblyInfo.cs (63%) create mode 100644 TestNotInternalsVisibleToChild/Public.cs create mode 100644 TestNotInternalsVisibleToChild/TestNotInternalsVisibleToChild.csproj create mode 100644 TestNotInternalsVisibleToChild/lnternal.cs diff --git a/Directory.build.props b/Directory.build.props index 4b3e8df4..26fdbde9 100644 --- a/Directory.build.props +++ b/Directory.build.props @@ -9,7 +9,6 @@ nullable Yeah69 Yeah69Logo_256.png - $(RootNamespace) diff --git a/Main/Configuration/Attributes.cs b/Main/Configuration/Attributes.cs index 433b19d3..50368729 100644 --- a/Main/Configuration/Attributes.cs +++ b/Main/Configuration/Attributes.cs @@ -1,31 +1,5 @@ namespace MrMeeseeks.DIE.Configuration; -// ReSharper disable UnusedParameter.Local *** The constructor parameters of the attributes will be used. Trust me, imma dev. -[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] -public class SpyAggregationAttribute : Attribute -{ - public SpyAggregationAttribute(params Type[] types) {} -} - -// ReSharper disable UnusedParameter.Local *** The constructor parameters of the attributes will be used. Trust me, imma dev. -[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] -public class FilterSpyAggregationAttribute : Attribute -{ - public FilterSpyAggregationAttribute(params Type[] types) {} -} - -[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] -public class SpyConstructorChoiceAggregationAttribute : Attribute -{ - public SpyConstructorChoiceAggregationAttribute(params Type[] references) {} -} - -[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] -public class FilterSpyConstructorChoiceAggregationAttribute : Attribute -{ - public FilterSpyConstructorChoiceAggregationAttribute(params Type[] references) {} -} - [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class ImplementationAggregationAttribute : Attribute { @@ -159,15 +133,15 @@ public FilterCompositeAggregationAttribute(params Type[] types) {} } [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] -public class GenericParameterSubstituteAggregationAttribute : Attribute +public class GenericParameterSubstitutesChoiceAttribute : Attribute { - public GenericParameterSubstituteAggregationAttribute(Type unboundGenericType, string genericArgumentName, params Type[] types) {} + public GenericParameterSubstitutesChoiceAttribute(Type unboundGenericType, string genericArgumentName, params Type[] types) {} } [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] -public class FilterGenericParameterSubstituteAggregationAttribute : Attribute +public class FilterGenericParameterSubstitutesChoiceAttribute : Attribute { - public FilterGenericParameterSubstituteAggregationAttribute(Type unboundGenericType, string genericArgumentName, params Type[] types) {} + public FilterGenericParameterSubstitutesChoiceAttribute(Type unboundGenericType, string genericArgumentName) {} } [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] @@ -257,4 +231,50 @@ public CreateFunctionAttribute(Type type, string methodNamePrefix) { } } + +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = false)] +public class AllImplementationsAggregationAttribute : Attribute +{ +} + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] +public class FilterAllImplementationsAggregationAttribute : Attribute +{ +} + +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] +public class AssemblyImplementationsAggregationAttribute : Attribute +{ + public AssemblyImplementationsAggregationAttribute(params Type[] typesFromAssemblies) {} +} + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class FilterAssemblyImplementationsAggregationAttribute : Attribute +{ + public FilterAssemblyImplementationsAggregationAttribute(params Type[] typesFromAssemblies) {} +} + +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] +public class ImplementationChoiceAttribute : Attribute +{ + public ImplementationChoiceAttribute(Type type, Type implementationChoice) {} +} + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class FilterImplementationChoiceAttribute : Attribute +{ + public FilterImplementationChoiceAttribute(Type type) {} +} + +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] +public class ImplementationCollectionChoiceAttribute : Attribute +{ + public ImplementationCollectionChoiceAttribute(Type type, params Type[] implementationChoice) {} +} + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class FilterImplementationCollectionChoiceAttribute : Attribute +{ + public FilterImplementationCollectionChoiceAttribute(Type type) {} +} // ReSharper enable UnusedParameter.Local \ No newline at end of file diff --git a/Main/Configuration/CheckTypeProperties.cs b/Main/Configuration/CheckTypeProperties.cs index 494ecc14..9614b632 100644 --- a/Main/Configuration/CheckTypeProperties.cs +++ b/Main/Configuration/CheckTypeProperties.cs @@ -171,6 +171,31 @@ public IReadOnlyList GetSequenceFor(INamedTypeSymbol interface public INamedTypeSymbol? MapToSingleFittingImplementation(INamedTypeSymbol type) { + var choice = + _currentlyConsideredTypes.ImplementationChoices.TryGetValue(type.UnboundIfGeneric(), out var choice0) + ? choice0 + : _currentlyConsideredTypes.ImplementationCollectionChoices.TryGetValue(type.UnboundIfGeneric(), + out var choices) + && choices.Count == 1 && choices[0] is { } choice1 + ? choice1 + : null; + + if (choice is not null) + { + var possibleChoices = GetClosedImplementations(type, new [] { choice }, true); + return possibleChoices.Count == 1 + ? possibleChoices.FirstOrDefault() + : null; + } + + if (type is { TypeKind: not TypeKind.Interface, IsAbstract: false, IsStatic: false }) + { + var possibleConcreteTypeImplementations = GetClosedImplementations(type, new [] { type }, true); + return possibleConcreteTypeImplementations.Count == 1 + ? possibleConcreteTypeImplementations.FirstOrDefault() + : null; + } + var possibleImplementations = _currentlyConsideredTypes.ImplementationMap.TryGetValue(type.UnboundIfGeneric(), out var implementations) ? GetClosedImplementations(type, implementations, true) : Array.Empty(); @@ -180,10 +205,35 @@ public IReadOnlyList GetSequenceFor(INamedTypeSymbol interface : null; } - public IReadOnlyList MapToImplementations(INamedTypeSymbol typeSymbol) => - _currentlyConsideredTypes.ImplementationMap.TryGetValue(typeSymbol.UnboundIfGeneric(), out var implementations) + public IReadOnlyList MapToImplementations(INamedTypeSymbol typeSymbol) + { + var isChoice = + _currentlyConsideredTypes + .ImplementationChoices + .TryGetValue(typeSymbol.UnboundIfGeneric(), out var choice); + + var isCollectionChoice = + _currentlyConsideredTypes + .ImplementationCollectionChoices + .TryGetValue(typeSymbol.UnboundIfGeneric(), out var choiceCollection); + + if (isChoice || isCollectionChoice) + { + var set = ImmutableHashSet.CreateRange( + SymbolEqualityComparer.Default, + isCollectionChoice && choiceCollection is { } + ? choiceCollection + : Enumerable.Empty()); + if (isChoice && choice is { }) + set = set.Add(choice); + return GetClosedImplementations(typeSymbol, set.ToList(), false); + } + + return _currentlyConsideredTypes.ImplementationMap.TryGetValue(typeSymbol.UnboundIfGeneric(), + out var implementations) ? GetClosedImplementations(typeSymbol, implementations, false) : Array.Empty(); + } private IReadOnlyList GetClosedImplementations( INamedTypeSymbol targetType, @@ -202,7 +252,7 @@ private IReadOnlyList GetClosedImplementations( var ret = new List(); foreach (var implementation in rawImplementations) { - if (!implementation.IsGenericType) + if (!implementation.IsGenericType || implementation.TypeArguments.All(ta => ta is INamedTypeSymbol and not IErrorTypeSymbol)) { ret.Add(implementation); continue; @@ -211,7 +261,7 @@ private IReadOnlyList GetClosedImplementations( var unboundImplementation = implementation.UnboundIfGeneric(); var originalImplementation = implementation.OriginalDefinitionIfUnbound(); - if (originalImplementation.AllDerivedTypes() + if (originalImplementation.AllDerivedTypesAndSelf() .FirstOrDefault(t => SymbolEqualityComparer.Default.Equals(t.UnboundIfGeneric(), unboundTargetType)) is { } implementationsTarget) { @@ -236,7 +286,7 @@ ITypeSymbol ForTypeParameterSymbol(ITypeParameterSymbol tps) if (_currentlyConsideredTypes.GenericParameterChoices.TryGetValue( (unboundImplementation, tps), out var choice)) return choice; - if (_currentlyConsideredTypes.GenericParameterSubstitutes.TryGetValue( + if (_currentlyConsideredTypes.GenericParameterSubstitutesChoices.TryGetValue( (unboundImplementation, tps), out var substitutes) && substitutes.Count == 1) return substitutes[0]; @@ -251,7 +301,7 @@ ITypeSymbol ForTypeParameterSymbol(ITypeParameterSymbol tps) { var closedImplementation = originalImplementation.Construct(newTypeArguments); if (closedImplementation - .AllDerivedTypes() + .AllDerivedTypesAndSelf() .Any(t => SymbolEqualityComparer.Default.Equals(targetType, t))) { ret.Add(closedImplementation); @@ -265,7 +315,7 @@ ITypeSymbol ForTypeParameterSymbol(ITypeParameterSymbol tps) .Select(tp => { IImmutableSet substitutes = ImmutableHashSet.CreateRange( - _currentlyConsideredTypes.GenericParameterSubstitutes.TryGetValue( + _currentlyConsideredTypes.GenericParameterSubstitutesChoices.TryGetValue( (unboundImplementation, tp), out var subs) ? subs : Array.Empty()); @@ -291,7 +341,7 @@ ITypeSymbol ForTypeParameterSymbol(ITypeParameterSymbol tps) { var closedImplementation = originalImplementation.Construct(veryNewTypeArguments); if (closedImplementation - .AllDerivedTypes() + .AllDerivedTypesAndSelf() .Any(t => SymbolEqualityComparer.Default.Equals(targetType, t))) { ret.Add(closedImplementation); diff --git a/Main/Configuration/CurrentlyConsideredTypes.cs b/Main/Configuration/CurrentlyConsideredTypes.cs index 141532b8..099bc972 100644 --- a/Main/Configuration/CurrentlyConsideredTypes.cs +++ b/Main/Configuration/CurrentlyConsideredTypes.cs @@ -19,72 +19,140 @@ internal interface ICurrentlyConsideredTypes IReadOnlyDictionary> DecoratorImplementationSequenceChoices { get; } IReadOnlyDictionary> ImplementationMap { get; } IReadOnlyDictionary ImplementationToInitializer { get; } - IReadOnlyDictionary<(INamedTypeSymbol, ITypeParameterSymbol), IReadOnlyList> GenericParameterSubstitutes { get; } + IReadOnlyDictionary<(INamedTypeSymbol, ITypeParameterSymbol), IReadOnlyList> GenericParameterSubstitutesChoices { get; } IReadOnlyDictionary<(INamedTypeSymbol, ITypeParameterSymbol), INamedTypeSymbol> GenericParameterChoices { get; } IReadOnlyDictionary> PropertyChoices { get; } + IReadOnlyDictionary ImplementationChoices { get; } + IReadOnlyDictionary> ImplementationCollectionChoices { get; } } -internal class CurrentlyConsideredTypes : ICurrentlyConsideredTypes +internal interface IImplementationTypeSetCache { - public CurrentlyConsideredTypes( - IReadOnlyList typesFromAttributes, - GeneratorExecutionContext context) + IImmutableSet All { get; } + + IImmutableSet ForAssembly(IAssemblySymbol assembly); +} + +internal class ImplementationTypeSetCache : IImplementationTypeSetCache +{ + private readonly WellKnownTypes _wellKnownTypes; + private readonly Lazy> _all; + private IImmutableDictionary> _assemblyCache = + ImmutableDictionary>.Empty; + + private readonly string _currentAssemblyName; + + internal ImplementationTypeSetCache( + GeneratorExecutionContext context, + WellKnownTypes wellKnownTypes) { - var allImplementations = new List(); - - allImplementations.AddRange(context.Compilation.SyntaxTrees - .Select(st => (st, context.Compilation.GetSemanticModel(st))) - .SelectMany(t => t.st - .GetRoot() - .DescendantNodesAndSelf() - .Where(e => e is ClassDeclarationSyntax or StructDeclarationSyntax or RecordDeclarationSyntax) - .Select(c => t.Item2.GetDeclaredSymbol(c)) - .Where(c => c is not null) - .OfType() - .Where(nts => !nts.IsAbstract))); - - var immutableHashSet = context - .Compilation - .SourceModule - .ReferencedAssemblySymbols - .SelectMany(a => GetAllNamespaces(a.GlobalNamespace)) + _wellKnownTypes = wellKnownTypes; + _currentAssemblyName = context.Compilation.AssemblyName ?? ""; + _all = new Lazy>( + () => + { + IImmutableSet set = ImmutableHashSet.Empty; + set = set.Union(context.Compilation.SyntaxTrees + .Select(st => (st, context.Compilation.GetSemanticModel(st))) + .SelectMany(t => t.st + .GetRoot() + .DescendantNodesAndSelf() + .Where(e => e is ClassDeclarationSyntax or StructDeclarationSyntax or RecordDeclarationSyntax) + .Select(c => t.Item2.GetDeclaredSymbol(c)) + .Where(c => c is not null) + .OfType() + .Where(nts => !nts.IsAbstract))); + + set = set.Union(context + .Compilation + .SourceModule + .ReferencedAssemblySymbols + .SelectMany(ForAssembly) + .ToImmutableHashSet(SymbolEqualityComparer.Default)); + + return set; + }); + } + + public IImmutableSet All => _all.Value; + public IImmutableSet ForAssembly(IAssemblySymbol assembly) + { + if (_assemblyCache.TryGetValue(assembly, out var set)) return set; + + var freshSet = GetImplementationsFrom(assembly); + _assemblyCache = _assemblyCache.Add(assembly, freshSet); + return freshSet; + } + + private IImmutableSet GetImplementationsFrom(IAssemblySymbol assemblySymbol) + { + var internalsAreVisible = assemblySymbol.GetAttributes() + .Any(ad => + SymbolEqualityComparer.Default.Equals(ad.AttributeClass, _wellKnownTypes.InternalsVisibleToAttribute) + && ad.ConstructorArguments.Length == 1 + && ad.ConstructorArguments[0].Value is string assemblyName + && Equals(assemblyName, _currentAssemblyName)); + + return GetAllNamespaces(assemblySymbol.GlobalNamespace) .SelectMany(ns => ns.GetTypeMembers()) .Where(nts => nts is { - IsAbstract: false, + IsAbstract: false, IsStatic: false, IsImplicitClass: false, IsScriptClass: false, TypeKind: TypeKind.Class or TypeKind.Struct or TypeKind.Structure, - DeclaredAccessibility: Accessibility.Public or Accessibility.Internal + DeclaredAccessibility: Accessibility.Public or Accessibility.Internal or Accessibility.ProtectedOrInternal }) - .Where(nts => !nts.Name.StartsWith("<") && nts.IsAccessibleInternally()) - .ToImmutableHashSet(SymbolEqualityComparer.Default); + .Where(nts => + !nts.Name.StartsWith("<") + && (nts.IsAccessiblePublicly() + || internalsAreVisible && nts.IsAccessibleInternally())) + .ToImmutableHashSet(SymbolEqualityComparer.Default); + } - IEnumerable GetAllNamespaces(INamespaceSymbol root) - { - yield return root; - foreach(var child in root.GetNamespaceMembers()) - foreach(var next in GetAllNamespaces(child)) - yield return next; - } + private static IEnumerable GetAllNamespaces(INamespaceSymbol root) + { + yield return root; + foreach(var child in root.GetNamespaceMembers()) + foreach(var next in GetAllNamespaces(child)) + yield return next; + } +} + +internal class CurrentlyConsideredTypes : ICurrentlyConsideredTypes +{ + public CurrentlyConsideredTypes( + IReadOnlyList typesFromAttributes, + IImplementationTypeSetCache implementationTypeSetCache) + { + IImmutableSet allImplementations = ImmutableHashSet.Empty; foreach (var types in typesFromAttributes) { - foreach (var filterType in types.FilterSpy.Concat(types.FilterImplementation)) - allImplementations.Remove(filterType); - - var spiedImplementations = types - .Spy - .SelectMany(t => t?.GetMembers() - .OfType() - .Where(ms => !ms.ReturnsVoid) - .Select(ms => ms.ReturnType) - .OfType() - .Where(nts => !nts.IsAbstract)); - - allImplementations.AddRange(types.Implementation - .Concat(spiedImplementations)); + if (types.FilterAllImplementations) + allImplementations = ImmutableHashSet.Empty; + else + { + allImplementations = allImplementations.Except( + types.FilterImplementation); + allImplementations = types.FilterAssemblyImplementations.Aggregate( + allImplementations, + (current, assembly) => current.Except(implementationTypeSetCache.ForAssembly(assembly))); + } + + if (types.AllImplementations) + { + allImplementations = implementationTypeSetCache.All; + } + else + { + allImplementations = allImplementations.Union( + types.Implementation); + allImplementations = types.AssemblyImplementations.Aggregate( + allImplementations, + (current, assembly) => current.Union(implementationTypeSetCache.ForAssembly(assembly))); + } } SyncTransientTypes = GetSetOfTypesWithProperties( @@ -190,7 +258,7 @@ IEnumerable GetAllNamespaces(INamespaceSymbol root) ImplementationMap = allImplementations .Where(t => !decoratorTypes.Contains(t.UnboundIfGeneric())) .Where(t => !compositeTypes.Contains(t.UnboundIfGeneric())) - .SelectMany(i => { return i.AllInterfaces.OfType().Select(ii => (ii, i)).Prepend((i, i)); }) + .SelectMany(i => { return i.AllDerivedTypesAndSelf().Select(ii => (ii, i)); }) .GroupBy(t => t.Item1.UnboundIfGeneric(), t => t.Item2) .ToDictionary(g => g.Key, g => (IReadOnlyList) g.Distinct(SymbolEqualityComparer.Default).OfType().ToList()); @@ -204,7 +272,7 @@ IEnumerable GetAllNamespaces(INamespaceSymbol root) .ToImmutableHashSet(SymbolEqualityComparer.Default); foreach (var filterConcreteType in allImplementations - .Where(i => i.OriginalDefinitionIfUnbound().AllDerivedTypes() + .Where(i => i.OriginalDefinitionIfUnbound().AllDerivedTypesAndSelf() .Any(inter => filterInterfaceTypes.Contains(inter)))) initializers.Remove(filterConcreteType); @@ -226,7 +294,7 @@ IEnumerable GetAllNamespaces(INamespaceSymbol root) { foreach (var (interfaceType, initializer) in interfaceTypes) { - if (i.OriginalDefinitionIfUnbound().AllDerivedTypes().Contains(interfaceType, SymbolEqualityComparer.Default)) + if (i.OriginalDefinitionIfUnbound().AllDerivedTypesAndSelf().Contains(interfaceType, SymbolEqualityComparer.Default)) { return ((INamedTypeSymbol, INamedTypeSymbol, IMethodSymbol)?) (i, interfaceType, initializer); } @@ -253,38 +321,19 @@ IEnumerable GetAllNamespaces(INamespaceSymbol root) foreach (var typesFromAttribute in typesFromAttributes) { - foreach (var tuple in typesFromAttribute.FilterGenericParameterSubstitutes) - { - var key = (tuple.Item1, tuple.Item2); - if (genericParameterSubstitutes.TryGetValue(key, out var currentGenericTypes)) - { - var newGenericTypes = currentGenericTypes - .Where(gt => !tuple.Item3.Contains(gt, SymbolEqualityComparer.Default)).ToImmutableList(); - if (newGenericTypes.Any()) - genericParameterSubstitutes[key] = newGenericTypes; - else - genericParameterSubstitutes.Remove(key); - } - } + foreach (var tuple in typesFromAttribute.FilterGenericParameterSubstitutesChoices) + genericParameterSubstitutes.Remove(tuple); - foreach (var tuple in typesFromAttribute.GenericParameterSubstitutes) + foreach (var tuple in typesFromAttribute.GenericParameterSubstitutesChoices) { var key = (tuple.Item1, tuple.Item2); - var list = new List( - genericParameterSubstitutes.TryGetValue(key, out var currentGenericTypes) - ? currentGenericTypes - : Array.Empty()); - foreach (var newGenericType in tuple.Item3) - { - if (!list.Contains(newGenericType, SymbolEqualityComparer.Default)) - list.Add(newGenericType); - } - - genericParameterSubstitutes[key] = list; + var choice = tuple.Item3; + + genericParameterSubstitutes[key] = choice; } } - GenericParameterSubstitutes = genericParameterSubstitutes; + GenericParameterSubstitutesChoices = genericParameterSubstitutes; var genericParameterChoices = new Dictionary<(INamedTypeSymbol, ITypeParameterSymbol), INamedTypeSymbol>(); @@ -299,6 +348,35 @@ IEnumerable GetAllNamespaces(INamespaceSymbol root) } GenericParameterChoices = genericParameterChoices; + + + var implementationChoices = + new Dictionary(SymbolEqualityComparer.Default); + + foreach (var typesFromAttribute in typesFromAttributes) + { + foreach (var type in typesFromAttribute.FilterImplementationChoices) + implementationChoices.Remove(type); + + foreach (var (type, choice) in typesFromAttribute.ImplementationChoices) + implementationChoices[type.UnboundIfGeneric()] = choice; + } + + ImplementationChoices = implementationChoices; + + var implementationCollectionChoices = + new Dictionary>(SymbolEqualityComparer.Default); + + foreach (var typesFromAttribute in typesFromAttributes) + { + foreach (var type in typesFromAttribute.FilterImplementationCollectionChoices) + implementationCollectionChoices.Remove(type); + + foreach (var (type, choice) in typesFromAttribute.ImplementationCollectionChoices) + implementationCollectionChoices[type.UnboundIfGeneric()] = choice; + } + + ImplementationCollectionChoices = implementationCollectionChoices; IImmutableSet GetSetOfTypesWithProperties( Func> propertyGivingTypesGetter, @@ -311,7 +389,7 @@ IEnumerable GetAllNamespaces(INamespaceSymbol root) ret = ret.Except(allImplementations .Where(i => { - var derivedTypes = i.AllDerivedTypes().Select(t => t.UnboundIfGeneric()).ToList(); + var derivedTypes = i.AllDerivedTypesAndSelf().Select(t => t.UnboundIfGeneric()).ToList(); return filterPropertyGivingTypes.Any(t => derivedTypes.Contains(t.UnboundIfGeneric(), SymbolEqualityComparer.Default)); }) @@ -322,7 +400,7 @@ IEnumerable GetAllNamespaces(INamespaceSymbol root) ret = ret.Union(allImplementations .Where(i => { - var derivedTypes = i.AllDerivedTypes().Select(t => t.UnboundIfGeneric()).ToList(); + var derivedTypes = i.AllDerivedTypesAndSelf().Select(t => t.UnboundIfGeneric()).ToList(); return propertyGivingTypes.Any(t => derivedTypes.Contains(t.UnboundIfGeneric(), SymbolEqualityComparer.Default)); }) @@ -348,7 +426,9 @@ IEnumerable GetAllNamespaces(INamespaceSymbol root) public IReadOnlyDictionary> DecoratorImplementationSequenceChoices { get; } public IReadOnlyDictionary> ImplementationMap { get; } public IReadOnlyDictionary ImplementationToInitializer { get; } - public IReadOnlyDictionary<(INamedTypeSymbol, ITypeParameterSymbol), IReadOnlyList> GenericParameterSubstitutes { get; } + public IReadOnlyDictionary<(INamedTypeSymbol, ITypeParameterSymbol), IReadOnlyList> GenericParameterSubstitutesChoices { get; } public IReadOnlyDictionary<(INamedTypeSymbol, ITypeParameterSymbol), INamedTypeSymbol> GenericParameterChoices { get; } public IReadOnlyDictionary> PropertyChoices { get; } + public IReadOnlyDictionary ImplementationChoices { get; } + public IReadOnlyDictionary> ImplementationCollectionChoices { get; } } \ No newline at end of file diff --git a/Main/Configuration/TypesFromAttributes.cs b/Main/Configuration/TypesFromAttributes.cs index 9466007f..20b47101 100644 --- a/Main/Configuration/TypesFromAttributes.cs +++ b/Main/Configuration/TypesFromAttributes.cs @@ -4,7 +4,6 @@ namespace MrMeeseeks.DIE.Configuration; internal interface ITypesFromAttributes { - IReadOnlyList Spy { get; } IReadOnlyList Implementation { get; } IReadOnlyList Transient { get; } IReadOnlyList SyncTransient { get; } @@ -19,10 +18,13 @@ internal interface ITypesFromAttributes IReadOnlyList<(INamedTypeSymbol, IReadOnlyList)> DecoratorSequenceChoices { get; } IReadOnlyList<(INamedTypeSymbol, IMethodSymbol)> ConstructorChoices { get; } IReadOnlyList<(INamedTypeSymbol, IMethodSymbol)> TypeInitializers { get; } - IReadOnlyList<(INamedTypeSymbol, ITypeParameterSymbol, IReadOnlyList)> GenericParameterSubstitutes { get; } + IReadOnlyList<(INamedTypeSymbol, ITypeParameterSymbol, IReadOnlyList)> GenericParameterSubstitutesChoices { get; } IReadOnlyList<(INamedTypeSymbol, ITypeParameterSymbol, INamedTypeSymbol)> GenericParameterChoices { get; } IReadOnlyList<(INamedTypeSymbol, IReadOnlyList)> PropertyChoices { get; } - IReadOnlyList FilterSpy { get; } + bool AllImplementations { get; } + IReadOnlyList AssemblyImplementations { get; } + IReadOnlyList<(INamedTypeSymbol, INamedTypeSymbol)> ImplementationChoices { get; } + IReadOnlyList<(INamedTypeSymbol, IReadOnlyList)> ImplementationCollectionChoices { get; } IReadOnlyList FilterImplementation { get; } IReadOnlyList FilterTransient { get; } IReadOnlyList FilterSyncTransient { get; } @@ -37,9 +39,13 @@ internal interface ITypesFromAttributes IReadOnlyList FilterDecoratorSequenceChoices { get; } IReadOnlyList FilterConstructorChoices { get; } IReadOnlyList FilterTypeInitializers { get; } - IReadOnlyList<(INamedTypeSymbol, ITypeParameterSymbol, IReadOnlyList)> FilterGenericParameterSubstitutes { get; } + IReadOnlyList<(INamedTypeSymbol, ITypeParameterSymbol)> FilterGenericParameterSubstitutesChoices { get; } IReadOnlyList<(INamedTypeSymbol, ITypeParameterSymbol)> FilterGenericParameterChoices { get; } IReadOnlyList FilterPropertyChoices { get; } + bool FilterAllImplementations { get; } + IReadOnlyList FilterAssemblyImplementations { get; } + IReadOnlyList FilterImplementationChoices { get; } + IReadOnlyList FilterImplementationCollectionChoices { get; } } internal class TypesFromAttributes : ScopeTypesFromAttributes @@ -75,7 +81,6 @@ internal ScopeTypesFromAttributes( .GroupBy(ad => ad.AttributeClass, SymbolEqualityComparer.Default) .ToDictionary(g => g.Key, g => g); - Spy = GetTypesFromAttribute(wellKnownTypes.SpyAggregationAttribute).ToList(); Implementation = GetTypesFromAttribute(wellKnownTypes.ImplementationAggregationAttribute).ToList(); Transient = GetTypesFromAttribute(wellKnownTypes.TransientAggregationAttribute).ToList(); SyncTransient = GetTypesFromAttribute(wellKnownTypes.SyncTransientAggregationAttribute).ToList(); @@ -88,7 +93,6 @@ internal ScopeTypesFromAttributes( Decorator = GetTypesFromAttribute(wellKnownTypes.DecoratorAggregationAttribute).ToList(); Composite = GetTypesFromAttribute(wellKnownTypes.CompositeAggregationAttribute).ToList(); - FilterSpy = GetTypesFromAttribute(wellKnownTypes.FilterSpyAggregationAttribute).ToList(); FilterImplementation = GetTypesFromAttribute(wellKnownTypes.FilterImplementationAggregationAttribute).ToList(); FilterTransient = GetTypesFromAttribute(wellKnownTypes.FilterTransientAggregationAttribute).ToList(); FilterSyncTransient = GetTypesFromAttribute(wellKnownTypes.FilterSyncTransientAggregationAttribute).ToList(); @@ -101,7 +105,9 @@ internal ScopeTypesFromAttributes( FilterDecorator = GetTypesFromAttribute(wellKnownTypes.FilterDecoratorAggregationAttribute).ToList(); FilterComposite = GetTypesFromAttribute(wellKnownTypes.FilterCompositeAggregationAttribute).ToList(); - DecoratorSequenceChoices = (AttributeDictionary.TryGetValue(wellKnownTypes.DecoratorSequenceChoiceAttribute, out var group) ? group : Enumerable.Empty()) + DecoratorSequenceChoices = (AttributeDictionary.TryGetValue(wellKnownTypes.DecoratorSequenceChoiceAttribute, out var decoratorSequenceChoiceAttributes) + ? decoratorSequenceChoiceAttributes + : Enumerable.Empty()) .Select(ad => { if (ad.ConstructorArguments.Length < 2) @@ -121,7 +127,9 @@ internal ScopeTypesFromAttributes( .OfType<(INamedTypeSymbol, IReadOnlyList)>() .ToList(); - FilterDecoratorSequenceChoices = (AttributeDictionary.TryGetValue(wellKnownTypes.FilterDecoratorSequenceChoiceAttribute, out var group1) ? group1 : Enumerable.Empty()) + FilterDecoratorSequenceChoices = (AttributeDictionary.TryGetValue(wellKnownTypes.FilterDecoratorSequenceChoiceAttribute, out var filterDecoratorSequenceChoiceAttributes) + ? filterDecoratorSequenceChoiceAttributes + : Enumerable.Empty()) .Select(ad => { if (ad.ConstructorArguments.Length != 1) @@ -132,7 +140,9 @@ internal ScopeTypesFromAttributes( .OfType() .ToList(); - ConstructorChoices = (AttributeDictionary.TryGetValue(wellKnownTypes.ConstructorChoiceAttribute, out var group0) ? group0 : Enumerable.Empty()) + ConstructorChoices = (AttributeDictionary.TryGetValue(wellKnownTypes.ConstructorChoiceAttribute, out var constructorChoiceAttributes) + ? constructorChoiceAttributes + : Enumerable.Empty()) .Select(ad => { if (ad.ConstructorArguments.Length < 2) @@ -149,21 +159,6 @@ internal ScopeTypesFromAttributes( ? (implementationType, parameterTypes) : null; }) - .Concat(GetTypesFromAttribute(wellKnownTypes.SpyConstructorChoiceAggregationAttribute) - .Select(t => - { - var members = t - .GetMembers() - .OfType() - .OrderBy(m => m.Name) - .Select(m => m.ReturnType) - .OfType() - .ToImmutableArray(); - if (members.Length < 1) - return ((INamedTypeSymbol, IList)?) null; - - return (members[0], members.Skip(1).ToList()); - })) .Select(t => { if (t is null) return null; @@ -188,32 +183,18 @@ internal ScopeTypesFromAttributes( .OfType<(INamedTypeSymbol, IMethodSymbol)>() .ToList(); - FilterConstructorChoices = (AttributeDictionary.TryGetValue(wellKnownTypes.FilterConstructorChoiceAttribute, out var group2) ? group2 : Enumerable.Empty()) - .Concat(GetTypesFromAttribute(wellKnownTypes.FilterSpyConstructorChoiceAggregationAttribute) - .Select(t => t.GetAttributes().FirstOrDefault(ad => ad.AttributeClass?.Name == nameof(ConstructorChoiceAttribute))) - .OfType()) - .Select(ad => - { - if (ad.ConstructorArguments.Length < 1) - return null; - return ad.ConstructorArguments[0].Value as INamedTypeSymbol; - }) - .Concat(GetTypesFromAttribute(wellKnownTypes.FilterSpyConstructorChoiceAggregationAttribute) - .Select(t => - { - var members = t - .GetMembers() - .OfType() - .OrderBy(m => m.Name) - .Select(m => m.ReturnType) - .OfType() - .ToImmutableArray(); - return members.Length < 1 ? null : members[0]; - })) + FilterConstructorChoices = (AttributeDictionary.TryGetValue(wellKnownTypes.FilterConstructorChoiceAttribute, out var filterConstructorChoiceAttributes) + ? filterConstructorChoiceAttributes + : Enumerable.Empty()) + .Select(ad => ad.ConstructorArguments.Length < 1 + ? null + : ad.ConstructorArguments[0].Value as INamedTypeSymbol) .OfType() .ToList(); - PropertyChoices = (AttributeDictionary.TryGetValue(wellKnownTypes.PropertyChoiceAttribute, out var propertyChoiceGroup) ? propertyChoiceGroup : Enumerable.Empty()) + PropertyChoices = (AttributeDictionary.TryGetValue(wellKnownTypes.PropertyChoiceAttribute, out var propertyChoiceGroup) + ? propertyChoiceGroup + : Enumerable.Empty()) .Select(ad => { if (ad.ConstructorArguments.Length < 1) @@ -239,7 +220,9 @@ internal ScopeTypesFromAttributes( .OfType<(INamedTypeSymbol, IReadOnlyList)>() .ToList(); - FilterPropertyChoices = (AttributeDictionary.TryGetValue(wellKnownTypes.FilterPropertyChoiceAttribute, out var filterPropertyChoicesGroup) ? filterPropertyChoicesGroup : Enumerable.Empty()) + FilterPropertyChoices = (AttributeDictionary.TryGetValue(wellKnownTypes.FilterPropertyChoiceAttribute, out var filterPropertyChoicesGroup) + ? filterPropertyChoicesGroup + : Enumerable.Empty()) .Select(ad => { if (ad.ConstructorArguments.Length < 1) @@ -249,7 +232,9 @@ internal ScopeTypesFromAttributes( .OfType() .ToList(); - TypeInitializers = (AttributeDictionary.TryGetValue(wellKnownTypes.TypeInitializerAttribute, out var group3) ? group3 : Enumerable.Empty()) + TypeInitializers = (AttributeDictionary.TryGetValue(wellKnownTypes.TypeInitializerAttribute, out var typeInitializerAttributes) + ? typeInitializerAttributes + : Enumerable.Empty()) .Select(ad => { if (ad.ConstructorArguments.Length != 2 @@ -273,7 +258,9 @@ internal ScopeTypesFromAttributes( .OfType<(INamedTypeSymbol, IMethodSymbol)>() .ToList(); - FilterTypeInitializers = (AttributeDictionary.TryGetValue(wellKnownTypes.FilterTypeInitializerAttribute, out var group4) ? group4 : Enumerable.Empty()) + FilterTypeInitializers = (AttributeDictionary.TryGetValue(wellKnownTypes.FilterTypeInitializerAttribute, out var filterTypeInitializerAttributes) + ? filterTypeInitializerAttributes + : Enumerable.Empty()) .Select(ad => { if (ad.ConstructorArguments.Length != 1) @@ -283,7 +270,9 @@ internal ScopeTypesFromAttributes( .OfType() .ToList(); - GenericParameterSubstitutes = (AttributeDictionary.TryGetValue(wellKnownTypes.GenericParameterSubstituteAggregationAttribute, out var group5) ? group5 : Enumerable.Empty()) + GenericParameterSubstitutesChoices = (AttributeDictionary.TryGetValue(wellKnownTypes.GenericParameterSubstitutesChoiceAttribute, out var genericParameterSubstitutesChoiceAttributes) + ? genericParameterSubstitutesChoiceAttributes + : Enumerable.Empty()) .Select(ad => { if (ad.ConstructorArguments.Length < 3) @@ -314,7 +303,9 @@ internal ScopeTypesFromAttributes( .OfType<(INamedTypeSymbol, ITypeParameterSymbol, IReadOnlyList)>() .ToList(); - GenericParameterChoices = (AttributeDictionary.TryGetValue(wellKnownTypes.GenericParameterChoiceAttribute, out var group6) ? group6 : Enumerable.Empty()) + GenericParameterChoices = (AttributeDictionary.TryGetValue(wellKnownTypes.GenericParameterChoiceAttribute, out var genericParameterChoiceAttributes) + ? genericParameterChoiceAttributes + : Enumerable.Empty()) .Select(ad => { if (ad.ConstructorArguments.Length < 3) @@ -340,10 +331,12 @@ internal ScopeTypesFromAttributes( .OfType<(INamedTypeSymbol, ITypeParameterSymbol, INamedTypeSymbol)>() .ToList(); - FilterGenericParameterSubstitutes = (AttributeDictionary.TryGetValue(wellKnownTypes.FilterGenericParameterSubstituteAggregationAttribute, out var group7) ? group7 : Enumerable.Empty()) + FilterGenericParameterSubstitutesChoices = (AttributeDictionary.TryGetValue(wellKnownTypes.FilterGenericParameterSubstitutesChoiceAttribute, out var filterGenericParameterSubstitutesChoiceAttributes) + ? filterGenericParameterSubstitutesChoiceAttributes + : Enumerable.Empty()) .Select(ad => { - if (ad.ConstructorArguments.Length < 3) + if (ad.ConstructorArguments.Length < 2) return null; var genericType = ad.ConstructorArguments[0].Value as INamedTypeSymbol; @@ -356,22 +349,17 @@ internal ScopeTypesFromAttributes( .TypeArguments .OfType() .FirstOrDefault(tps => tps.Name == nameOfGenericParameter); - - var substitutes = ad - .ConstructorArguments[2] - .Values - .Select(tc => tc.Value) - .OfType() - .ToList(); return typeParameterSymbol is null ? null - : ((INamedTypeSymbol, ITypeParameterSymbol, IReadOnlyList)?) (genericType, typeParameterSymbol, substitutes); + : ((INamedTypeSymbol, ITypeParameterSymbol)?) (genericType, typeParameterSymbol); }) - .OfType<(INamedTypeSymbol, ITypeParameterSymbol, IReadOnlyList)>() + .OfType<(INamedTypeSymbol, ITypeParameterSymbol)>() .ToList(); - FilterGenericParameterChoices = (AttributeDictionary.TryGetValue(wellKnownTypes.FilterGenericParameterChoiceAttribute, out var group8) ? group8 : Enumerable.Empty()) + FilterGenericParameterChoices = (AttributeDictionary.TryGetValue(wellKnownTypes.FilterGenericParameterChoiceAttribute, out var filterGenericParameterChoiceAttributes) + ? filterGenericParameterChoiceAttributes + : Enumerable.Empty()) .Select(ad => { if (ad.ConstructorArguments.Length < 2) @@ -394,6 +382,86 @@ internal ScopeTypesFromAttributes( }) .OfType<(INamedTypeSymbol, ITypeParameterSymbol)>() .ToList(); + + AllImplementations = (AttributeDictionary.TryGetValue(wellKnownTypes.AllImplementationsAggregationAttribute, out var allImplementationsAttributes) + ? allImplementationsAttributes + : Enumerable.Empty()) + .Any(); + + FilterAllImplementations = (AttributeDictionary.TryGetValue(wellKnownTypes.FilterAllImplementationsAggregationAttribute, out var filterAllImplementationsAttributes) + ? filterAllImplementationsAttributes + : Enumerable.Empty()) + .Any(); + + AssemblyImplementations = (AttributeDictionary.TryGetValue(wellKnownTypes.AssemblyImplementationsAggregationAttribute, out var assemblyImplementationsAttributes) + ? assemblyImplementationsAttributes + : Enumerable.Empty()) + .SelectMany(ad => ad.ConstructorArguments.Length < 1 + ? Array.Empty() + : ad.ConstructorArguments[0] + .Values + .Select(tc => tc.Value) + .OfType() + .Select(t => t.ContainingAssembly) + .OfType()) + .Distinct(SymbolEqualityComparer.Default) + .OfType() + .ToList(); + + FilterAssemblyImplementations = (AttributeDictionary.TryGetValue(wellKnownTypes.FilterAllImplementationsAggregationAttribute, out var filterAssemblyImplementationsAttributes) + ? filterAssemblyImplementationsAttributes + : Enumerable.Empty()) + .SelectMany(ad => ad.ConstructorArguments.Length < 1 + ? Array.Empty() + : ad.ConstructorArguments[0] + .Values + .Select(tc => tc.Value) + .OfType() + .Select(t => t.ContainingAssembly) + .OfType()) + .Distinct(SymbolEqualityComparer.Default) + .OfType() + .ToList(); + + ImplementationChoices = (AttributeDictionary.TryGetValue(wellKnownTypes.ImplementationChoiceAttribute, out var implementationChoiceAttributes) + ? implementationChoiceAttributes + : Enumerable.Empty()) + .Select(ad => + ad.ConstructorArguments.Length < 2 + || ad.ConstructorArguments[0].Value is not INamedTypeSymbol type + || ad.ConstructorArguments[1].Value is not INamedTypeSymbol implementation + ? null + : ((INamedTypeSymbol, INamedTypeSymbol)?) (type, implementation)) + .OfType<(INamedTypeSymbol, INamedTypeSymbol)>() + .ToList(); + + ImplementationCollectionChoices = (AttributeDictionary.TryGetValue(wellKnownTypes.ImplementationCollectionChoiceAttribute, out var implementationCollectionChoicesAttributes) + ? implementationCollectionChoicesAttributes + : Enumerable.Empty()) + .Select(ad => + { + if (ad.ConstructorArguments.Length < 2) + return null; + + var type = ad.ConstructorArguments[0].Value as INamedTypeSymbol; + + var implementations = ad + .ConstructorArguments[1] + .Values + .Select(tc => tc.Value) + .OfType() + .ToList(); + + return type is null + ? null + : ((INamedTypeSymbol, IReadOnlyList)?) (type, implementations); + }) + .OfType<(INamedTypeSymbol, IReadOnlyList)>() + .ToList(); + + FilterImplementationChoices = GetTypesFromAttribute(wellKnownTypes.FilterImplementationChoiceAttribute).ToList(); + + FilterImplementationCollectionChoices = GetTypesFromAttribute(wellKnownTypes.FilterImplementationCollectionChoiceAttribute).ToList(); } private IReadOnlyDictionary> AttributeDictionary { get; } @@ -401,7 +469,7 @@ internal ScopeTypesFromAttributes( protected IEnumerable GetTypesFromAttribute( INamedTypeSymbol attribute) { - return (AttributeDictionary.TryGetValue(attribute, out var group1) ? group1 : Enumerable.Empty()) + return (AttributeDictionary.TryGetValue(attribute, out var attributes) ? attributes : Enumerable.Empty()) .SelectMany(ad => ad.ConstructorArguments .Where(tc => tc.Kind == TypedConstantKind.Type) .OfType() @@ -420,7 +488,6 @@ bool CheckValidType(TypedConstant typedConstant, out INamedTypeSymbol type) } } - public IReadOnlyList Spy { get; } public IReadOnlyList Implementation { get; } public IReadOnlyList Transient { get; } public IReadOnlyList SyncTransient { get; } @@ -435,10 +502,13 @@ bool CheckValidType(TypedConstant typedConstant, out INamedTypeSymbol type) public IReadOnlyList<(INamedTypeSymbol, IReadOnlyList)> DecoratorSequenceChoices { get; } public IReadOnlyList<(INamedTypeSymbol, IMethodSymbol)> ConstructorChoices { get; } public IReadOnlyList<(INamedTypeSymbol, IMethodSymbol)> TypeInitializers { get; } - public IReadOnlyList<(INamedTypeSymbol, ITypeParameterSymbol, IReadOnlyList)> GenericParameterSubstitutes { get; } + public IReadOnlyList<(INamedTypeSymbol, ITypeParameterSymbol, IReadOnlyList)> GenericParameterSubstitutesChoices { get; } public IReadOnlyList<(INamedTypeSymbol, ITypeParameterSymbol, INamedTypeSymbol)> GenericParameterChoices { get; } public IReadOnlyList<(INamedTypeSymbol, IReadOnlyList)> PropertyChoices { get; } - public IReadOnlyList FilterSpy { get; } + public bool AllImplementations { get; } + public IReadOnlyList AssemblyImplementations { get; } + public IReadOnlyList<(INamedTypeSymbol, INamedTypeSymbol)> ImplementationChoices { get; } + public IReadOnlyList<(INamedTypeSymbol, IReadOnlyList)> ImplementationCollectionChoices { get; } public IReadOnlyList FilterImplementation { get; } public IReadOnlyList FilterTransient { get; } public IReadOnlyList FilterSyncTransient { get; } @@ -453,7 +523,11 @@ bool CheckValidType(TypedConstant typedConstant, out INamedTypeSymbol type) public IReadOnlyList FilterDecoratorSequenceChoices { get; } public IReadOnlyList FilterConstructorChoices { get; } public IReadOnlyList FilterTypeInitializers { get; } - public IReadOnlyList<(INamedTypeSymbol, ITypeParameterSymbol, IReadOnlyList)> FilterGenericParameterSubstitutes { get; } + public IReadOnlyList<(INamedTypeSymbol, ITypeParameterSymbol)> FilterGenericParameterSubstitutesChoices { get; } public IReadOnlyList<(INamedTypeSymbol, ITypeParameterSymbol)> FilterGenericParameterChoices { get; } public IReadOnlyList FilterPropertyChoices { get; } + public bool FilterAllImplementations { get; } + public IReadOnlyList FilterAssemblyImplementations { get; } + public IReadOnlyList FilterImplementationChoices { get; } + public IReadOnlyList FilterImplementationCollectionChoices { get; } } \ No newline at end of file diff --git a/Main/ContainerInfo.cs b/Main/ContainerInfo.cs index 2254b082..0ec063d5 100644 --- a/Main/ContainerInfo.cs +++ b/Main/ContainerInfo.cs @@ -1,3 +1,5 @@ +using MrMeeseeks.DIE.Extensions; + namespace MrMeeseeks.DIE; internal interface IContainerInfo diff --git a/Main/Extensions/INamedTypeSymbolExtensions.cs b/Main/Extensions/INamedTypeSymbolExtensions.cs index e92a6ebe..149bf1d1 100644 --- a/Main/Extensions/INamedTypeSymbolExtensions.cs +++ b/Main/Extensions/INamedTypeSymbolExtensions.cs @@ -2,19 +2,24 @@ internal static class INamedTypeSymbolExtensions { - internal static IEnumerable AllDerivedTypes(this INamedTypeSymbol type) + internal static IEnumerable AllDerivedTypesAndSelf(this INamedTypeSymbol type) { - var concreteTypes = new List(); - var temp = type; - while (temp is {}) + var baseTypesAndSelf = new List(); + if (type.TypeKind is TypeKind.Class or TypeKind.Struct) { - concreteTypes.Add(temp); - temp = temp.BaseType; + var temp = type; + while (temp is {}) + { + baseTypesAndSelf.Add(temp); + temp = temp.BaseType; + } } + else if (type.TypeKind is TypeKind.Interface) + baseTypesAndSelf.Add(type); + return type .AllInterfaces - .Append(type) - .Concat(concreteTypes); + .Concat(baseTypesAndSelf); } internal static INamedTypeSymbol UnboundIfGeneric(this INamedTypeSymbol type) => diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs index a6bfab9c..9fd0dbe2 100644 --- a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs @@ -532,20 +532,27 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup private (Resolvable, ITaskConsumableResolution?) SwitchClass(SwitchClassParameter parameter) { var (implementationType, currentParameters) = parameter; + + if (_checkTypeProperties.MapToSingleFittingImplementation(implementationType) is not { } chosenImplementationType) + { + return implementationType.NullableAnnotation == NullableAnnotation.Annotated + ? (new NullResolution(RootReferenceGenerator.Generate(implementationType), implementationType.FullName()), null) // todo warning + : (new ErrorTreeItem($"[{implementationType.FullName()}] Interface: Multiple or no implementations where a single is required"), null); + } var nextParameter = new SwitchImplementationParameter( - implementationType, + chosenImplementationType, currentParameters); - var ret = _checkTypeProperties.ShouldBeScopeRoot(implementationType) switch + var ret = _checkTypeProperties.ShouldBeScopeRoot(chosenImplementationType) switch { ScopeLevel.TransientScope => (_rangeResolutionBaseBuilder.CreateTransientScopeRootResolution( nextParameter, - implementationType, + chosenImplementationType, currentParameters), null), ScopeLevel.Scope => (_rangeResolutionBaseBuilder.CreateScopeRootResolution( nextParameter, - implementationType, + chosenImplementationType, currentParameters), null), _ => SwitchImplementation(nextParameter) }; diff --git a/Main/RoslynExtensions.cs b/Main/RoslynExtensions.cs index a57dbef6..621cb726 100644 --- a/Main/RoslynExtensions.cs +++ b/Main/RoslynExtensions.cs @@ -39,6 +39,23 @@ internal static bool IsAccessibleInternally(this ITypeSymbol type) }; } + // Picked from https://github.com/YairHalberstadt/stronginject Thank you! + internal static bool IsAccessiblePublicly(this ITypeSymbol type) + { + if (type is ITypeParameterSymbol) + return true; + if (!type.ContainingType?.IsAccessiblePublicly() ?? false) + return false; + return type switch + { + IArrayTypeSymbol array => array.ElementType.IsAccessiblePublicly(), + IPointerTypeSymbol pointer => pointer.PointedAtType.IsAccessiblePublicly(), + INamedTypeSymbol named => named.DeclaredAccessibility is Accessibility.Public + && named.TypeArguments.All(IsAccessiblePublicly), + _ => false, + }; + } + // Picked from https://github.com/YairHalberstadt/stronginject Thank you! public static string FullName(this ITypeSymbol type, SymbolDisplayMiscellaneousOptions miscellaneousOptions = SymbolDisplayMiscellaneousOptions.IncludeNullableReferenceTypeModifier) => type.ToDisplayString(new SymbolDisplayFormat( diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index 834238a0..215717db 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -24,6 +24,7 @@ public void Execute(GeneratorExecutionContext context) var referenceGeneratorFactory = new ReferenceGeneratorFactory(ReferenceGeneratorFactory); var containerErrorGenerator = new ContainerErrorGenerator(context); var resolutionTreeCreationErrorHarvester = new ResolutionTreeCreationErrorHarvester(); + var implementationTypeSetCache = new ImplementationTypeSetCache(context, wellKnownTypes); new ExecuteImpl( context, wellKnownTypes, @@ -45,7 +46,7 @@ IContainerResolutionBuilder ResolutionTreeFactory(IContainerInfo ci) new TransientScopeInterfaceResolutionBuilder(referenceGeneratorFactory, wellKnownTypes, RangedFunctionGroupResolutionBuilderFactory, FunctionResolutionSynchronicityDecisionMakerFactory), referenceGeneratorFactory, - new CheckTypeProperties(new CurrentlyConsideredTypes(containerTypesFromAttributesList, context), wellKnownTypes), + new CheckTypeProperties(new CurrentlyConsideredTypes(containerTypesFromAttributesList, implementationTypeSetCache), wellKnownTypes), wellKnownTypes, ScopeManagerFactory, ContainerCreateFunctionResolutionBuilderFactory, @@ -63,7 +64,7 @@ IScopeManager ScopeManagerFactory( TransientScopeResolutionBuilderFactory, ScopeResolutionBuilderFactory, ad => new ScopeTypesFromAttributes(ad, wellKnownTypes), - tfa => new CheckTypeProperties(new CurrentlyConsideredTypes(tfa, context), wellKnownTypes), + tfa => new CheckTypeProperties(new CurrentlyConsideredTypes(tfa, implementationTypeSetCache), wellKnownTypes), st => new UserProvidedScopeElements(st), new EmptyUserProvidedScopeElements(), wellKnownTypes); diff --git a/Main/WellKnownTypes.cs b/Main/WellKnownTypes.cs index 5a5d71b3..8a6af008 100644 --- a/Main/WellKnownTypes.cs +++ b/Main/WellKnownTypes.cs @@ -1,10 +1,9 @@ -using MrMeeseeks.DIE.Configuration; - +using System.Runtime.CompilerServices; +using MrMeeseeks.DIE.Configuration; +[assembly:InternalsVisibleTo("")] namespace MrMeeseeks.DIE; internal record WellKnownTypes( - INamedTypeSymbol SpyAggregationAttribute, - INamedTypeSymbol SpyConstructorChoiceAggregationAttribute, INamedTypeSymbol ImplementationAggregationAttribute, INamedTypeSymbol TransientAggregationAttribute, INamedTypeSymbol SyncTransientAggregationAttribute, @@ -16,14 +15,16 @@ internal record WellKnownTypes( INamedTypeSymbol ScopeRootAggregationAttribute, INamedTypeSymbol DecoratorAggregationAttribute, INamedTypeSymbol CompositeAggregationAttribute, - INamedTypeSymbol GenericParameterSubstituteAggregationAttribute, + INamedTypeSymbol GenericParameterSubstitutesChoiceAttribute, INamedTypeSymbol GenericParameterChoiceAttribute, INamedTypeSymbol DecoratorSequenceChoiceAttribute, INamedTypeSymbol ConstructorChoiceAttribute, INamedTypeSymbol PropertyChoiceAttribute, INamedTypeSymbol TypeInitializerAttribute, - INamedTypeSymbol FilterSpyAggregationAttribute, - INamedTypeSymbol FilterSpyConstructorChoiceAggregationAttribute, + INamedTypeSymbol AllImplementationsAggregationAttribute, + INamedTypeSymbol AssemblyImplementationsAggregationAttribute, + INamedTypeSymbol ImplementationChoiceAttribute, + INamedTypeSymbol ImplementationCollectionChoiceAttribute, INamedTypeSymbol FilterImplementationAggregationAttribute, INamedTypeSymbol FilterTransientAggregationAttribute, INamedTypeSymbol FilterSyncTransientAggregationAttribute, @@ -35,12 +36,16 @@ internal record WellKnownTypes( INamedTypeSymbol FilterScopeRootAggregationAttribute, INamedTypeSymbol FilterDecoratorAggregationAttribute, INamedTypeSymbol FilterCompositeAggregationAttribute, - INamedTypeSymbol FilterGenericParameterSubstituteAggregationAttribute, + INamedTypeSymbol FilterGenericParameterSubstitutesChoiceAttribute, INamedTypeSymbol FilterGenericParameterChoiceAttribute, INamedTypeSymbol FilterDecoratorSequenceChoiceAttribute, INamedTypeSymbol FilterConstructorChoiceAttribute, INamedTypeSymbol FilterPropertyChoiceAttribute, INamedTypeSymbol FilterTypeInitializerAttribute, + INamedTypeSymbol FilterAllImplementationsAggregationAttribute, + INamedTypeSymbol FilterAssemblyImplementationsAggregationAttribute, + INamedTypeSymbol FilterImplementationChoiceAttribute, + INamedTypeSymbol FilterImplementationCollectionChoiceAttribute, INamedTypeSymbol CustomScopeForRootTypesAttribute, INamedTypeSymbol CreateFunctionAttribute, INamedTypeSymbol Disposable, @@ -60,7 +65,8 @@ internal record WellKnownTypes( INamedTypeSymbol ConcurrentDictionaryOfAsyncDisposable, INamedTypeSymbol Exception, INamedTypeSymbol TaskCanceledException, - INamedTypeSymbol SemaphoreSlim) + INamedTypeSymbol SemaphoreSlim, + INamedTypeSymbol InternalsVisibleToAttribute) { internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellKnownTypes) { @@ -92,12 +98,7 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK var exception = compilation.GetTypeOrReport("System.Exception"); var taskCanceledException = compilation.GetTypeOrReport("System.Threading.Tasks.TaskCanceledException"); var semaphoreSlim = compilation.GetTypeOrReport("System.Threading.SemaphoreSlim"); - - var spyAggregationAttribute = compilation - .GetTypeByMetadataName(typeof(SpyAggregationAttribute).FullName ?? ""); - - var spyConstructorChoiceAggregationAttribute = compilation - .GetTypeByMetadataName(typeof(SpyConstructorChoiceAggregationAttribute).FullName ?? ""); + var internalsVisibleToAttribute = compilation.GetTypeOrReport("System.Runtime.CompilerServices.InternalsVisibleToAttribute"); var implementationAggregationAttribute = compilation .GetTypeByMetadataName(typeof(ImplementationAggregationAttribute).FullName ?? ""); @@ -132,11 +133,11 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK var compositeAggregationAttribute = compilation .GetTypeByMetadataName(typeof(CompositeAggregationAttribute).FullName ?? ""); - var genericParameterSubstituteAggregationAttribute = compilation - .GetTypeByMetadataName(typeof(GenericParameterSubstituteAggregationAttribute).FullName ?? ""); + var genericParameterSubstitutesChoiceAttribute = compilation + .GetTypeByMetadataName(typeof(GenericParameterSubstitutesChoiceAttribute).FullName ?? ""); - var filterGenericParameterSubstituteAggregationAttribute = compilation - .GetTypeByMetadataName(typeof(FilterGenericParameterSubstituteAggregationAttribute).FullName ?? ""); + var filterGenericParameterSubstitutesChoiceAttribute = compilation + .GetTypeByMetadataName(typeof(FilterGenericParameterSubstitutesChoiceAttribute).FullName ?? ""); var genericParameterChoiceAttribute = compilation .GetTypeByMetadataName(typeof(GenericParameterChoiceAttribute).FullName ?? ""); @@ -153,11 +154,17 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK var propertyChoiceAttribute = compilation .GetTypeByMetadataName(typeof(PropertyChoiceAttribute).FullName ?? ""); - var filterSpyAggregationAttribute = compilation - .GetTypeByMetadataName(typeof(FilterSpyAggregationAttribute).FullName ?? ""); + var allImplementationsAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(AllImplementationsAggregationAttribute).FullName ?? ""); + + var assemblyImplementationsAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(AssemblyImplementationsAggregationAttribute).FullName ?? ""); + + var implementationChoiceAttribute = compilation + .GetTypeByMetadataName(typeof(ImplementationChoiceAttribute).FullName ?? ""); - var filterSpyConstructorChoiceAggregationAttribute = compilation - .GetTypeByMetadataName(typeof(FilterSpyConstructorChoiceAggregationAttribute).FullName ?? ""); + var implementationCollectionChoiceAttribute = compilation + .GetTypeByMetadataName(typeof(ImplementationCollectionChoiceAttribute).FullName ?? ""); var filterImplementationAggregationAttribute = compilation .GetTypeByMetadataName(typeof(FilterImplementationAggregationAttribute).FullName ?? ""); @@ -201,6 +208,18 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK var filterPropertyChoiceAttribute = compilation .GetTypeByMetadataName(typeof(FilterPropertyChoiceAttribute).FullName ?? ""); + var filterAllImplementationsAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(FilterAllImplementationsAggregationAttribute).FullName ?? ""); + + var filterAssemblyImplementationsAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(FilterAssemblyImplementationsAggregationAttribute).FullName ?? ""); + + var filterImplementationChoiceAttribute = compilation + .GetTypeByMetadataName(typeof(FilterImplementationChoiceAttribute).FullName ?? ""); + + var filterImplementationCollectionChoiceAttribute = compilation + .GetTypeByMetadataName(typeof(FilterImplementationCollectionChoiceAttribute).FullName ?? ""); + var customScopeForRootTypesAttribute = compilation .GetTypeByMetadataName(typeof(CustomScopeForRootTypesAttribute).FullName ?? ""); @@ -213,27 +232,27 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK var createFunctionAttribute = compilation .GetTypeByMetadataName(typeof(CreateFunctionAttribute).FullName ?? ""); - if (spyAggregationAttribute is not null - && spyConstructorChoiceAggregationAttribute is not null - && implementationAggregationAttribute is not null + if (implementationAggregationAttribute is not null && transientAggregationAttribute is not null && syncTransientAggregationAttribute is not null && asyncTransientAggregationAttribute is not null && containerInstanceAggregationAttribute is not null && transientScopeInstanceAggregationAttribute is not null && scopeInstanceAggregationAttribute is not null + && allImplementationsAggregationAttribute is not null + && assemblyImplementationsAggregationAttribute is not null + && implementationChoiceAttribute is not null + && implementationCollectionChoiceAttribute is not null && transientScopeRootAggregationAttribute is not null && scopeRootAggregationAttribute is not null && decoratorAggregationAttribute is not null && compositeAggregationAttribute is not null - && genericParameterSubstituteAggregationAttribute is not null + && genericParameterSubstitutesChoiceAttribute is not null && genericParameterChoiceAttribute is not null && decoratorSequenceChoiceAttribute is not null && constructorChoiceAttribute is not null && propertyChoiceAttribute is not null && typeInitializerAttribute is not null - && filterSpyAggregationAttribute is not null - && filterSpyConstructorChoiceAggregationAttribute is not null && filterImplementationAggregationAttribute is not null && filterTransientAggregationAttribute is not null && filterSyncTransientAggregationAttribute is not null @@ -245,12 +264,16 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK && filterScopeRootAggregationAttribute is not null && filterDecoratorAggregationAttribute is not null && filterCompositeAggregationAttribute is not null - && filterGenericParameterSubstituteAggregationAttribute is not null + && filterGenericParameterSubstitutesChoiceAttribute is not null && filterGenericParameterChoiceAttribute is not null && filterDecoratorSequenceChoiceAttribute is not null && filterConstructorChoiceAttribute is not null && filterPropertyChoiceAttribute is not null && filterTypeInitializerAttribute is not null + && filterAllImplementationsAggregationAttribute is not null + && filterAssemblyImplementationsAggregationAttribute is not null + && filterImplementationChoiceAttribute is not null + && filterImplementationCollectionChoiceAttribute is not null && customScopeForRootTypesAttribute is not null && createFunctionAttribute is not null && iDisposable is not null @@ -270,12 +293,11 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK && concurrentDictionary2OfSyncDisposable is not null && concurrentDictionary2OfAsyncDisposable is not null && exception is not null - && semaphoreSlim is not null) + && semaphoreSlim is not null + && internalsVisibleToAttribute is not null) { wellKnownTypes = new WellKnownTypes( - SpyAggregationAttribute: spyAggregationAttribute, - SpyConstructorChoiceAggregationAttribute: spyConstructorChoiceAggregationAttribute, ImplementationAggregationAttribute: implementationAggregationAttribute, TransientAggregationAttribute: transientAggregationAttribute, SyncTransientAggregationAttribute: syncTransientAggregationAttribute, @@ -287,14 +309,16 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK ScopeRootAggregationAttribute: scopeRootAggregationAttribute, DecoratorAggregationAttribute: decoratorAggregationAttribute, CompositeAggregationAttribute: compositeAggregationAttribute, - GenericParameterSubstituteAggregationAttribute: genericParameterSubstituteAggregationAttribute, + AllImplementationsAggregationAttribute: allImplementationsAggregationAttribute, + AssemblyImplementationsAggregationAttribute: assemblyImplementationsAggregationAttribute, + ImplementationChoiceAttribute: implementationChoiceAttribute, + ImplementationCollectionChoiceAttribute: implementationCollectionChoiceAttribute, + GenericParameterSubstitutesChoiceAttribute: genericParameterSubstitutesChoiceAttribute, GenericParameterChoiceAttribute: genericParameterChoiceAttribute, DecoratorSequenceChoiceAttribute: decoratorSequenceChoiceAttribute, ConstructorChoiceAttribute: constructorChoiceAttribute, PropertyChoiceAttribute: propertyChoiceAttribute, TypeInitializerAttribute: typeInitializerAttribute, - FilterSpyAggregationAttribute: filterSpyAggregationAttribute, - FilterSpyConstructorChoiceAggregationAttribute: filterSpyConstructorChoiceAggregationAttribute, FilterImplementationAggregationAttribute: filterImplementationAggregationAttribute, FilterTransientAggregationAttribute: filterTransientAggregationAttribute, FilterSyncTransientAggregationAttribute: filterSyncTransientAggregationAttribute, @@ -306,12 +330,16 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK FilterScopeRootAggregationAttribute: filterScopeRootAggregationAttribute, FilterDecoratorAggregationAttribute: filterDecoratorAggregationAttribute, FilterCompositeAggregationAttribute: filterCompositeAggregationAttribute, - FilterGenericParameterSubstituteAggregationAttribute: filterGenericParameterSubstituteAggregationAttribute, + FilterGenericParameterSubstitutesChoiceAttribute: filterGenericParameterSubstitutesChoiceAttribute, FilterGenericParameterChoiceAttribute: filterGenericParameterChoiceAttribute, FilterDecoratorSequenceChoiceAttribute: filterDecoratorSequenceChoiceAttribute, FilterConstructorChoiceAttribute: filterConstructorChoiceAttribute, FilterPropertyChoiceAttribute: filterPropertyChoiceAttribute, FilterTypeInitializerAttribute: filterTypeInitializerAttribute, + FilterAllImplementationsAggregationAttribute: filterAllImplementationsAggregationAttribute, + FilterAssemblyImplementationsAggregationAttribute: filterAssemblyImplementationsAggregationAttribute, + FilterImplementationChoiceAttribute: filterImplementationChoiceAttribute, + FilterImplementationCollectionChoiceAttribute: filterImplementationCollectionChoiceAttribute, CustomScopeForRootTypesAttribute: customScopeForRootTypesAttribute, CreateFunctionAttribute: createFunctionAttribute, Disposable: iDisposable, @@ -331,7 +359,8 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK ConcurrentDictionaryOfAsyncDisposable: concurrentDictionary2OfAsyncDisposable, Exception: exception, TaskCanceledException: taskCanceledException, - SemaphoreSlim: semaphoreSlim); + SemaphoreSlim: semaphoreSlim, + InternalsVisibleToAttribute: internalsVisibleToAttribute); return true; } diff --git a/MrMeeseeks.DIE.sln b/MrMeeseeks.DIE.sln index ac5c5bcb..3aeefc54 100644 --- a/MrMeeseeks.DIE.sln +++ b/MrMeeseeks.DIE.sln @@ -12,14 +12,16 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Misc", "Misc", "{4BFDBE50-2 Directory.build.props = Directory.build.props EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Spy", "Spy\Spy.csproj", "{441E6E31-2472-42C0-AE6F-2676CB15ACDF}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test", "Test\Test.csproj", "{5075D83B-EF12-4372-8210-CEB5D81A4FE2}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestChild", "TestChild\TestChild.csproj", "{1CCECD48-C564-4799-8A4C-19A9BF847795}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SampleChild", "SampleChild\SampleChild.csproj", "{73D1DC76-4CD8-4534-8717-0551B635F864}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestNotInternalsVisibleToChild", "TestNotInternalsVisibleToChild\TestNotInternalsVisibleToChild.csproj", "{E1D7CC3A-1340-4817-81C7-6820A2F31A8D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestInternalsVisibleToChild", "TestInternalsVisibleToChild\TestInternalsVisibleToChild.csproj", "{AB74CB8A-5195-4CB0-9844-71AFB1F5C926}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -34,10 +36,6 @@ Global {5DFB446B-AAC8-450A-95A1-A55EF6BB37DB}.Debug|Any CPU.Build.0 = Debug|Any CPU {5DFB446B-AAC8-450A-95A1-A55EF6BB37DB}.Release|Any CPU.ActiveCfg = Release|Any CPU {5DFB446B-AAC8-450A-95A1-A55EF6BB37DB}.Release|Any CPU.Build.0 = Release|Any CPU - {441E6E31-2472-42C0-AE6F-2676CB15ACDF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {441E6E31-2472-42C0-AE6F-2676CB15ACDF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {441E6E31-2472-42C0-AE6F-2676CB15ACDF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {441E6E31-2472-42C0-AE6F-2676CB15ACDF}.Release|Any CPU.Build.0 = Release|Any CPU {5075D83B-EF12-4372-8210-CEB5D81A4FE2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5075D83B-EF12-4372-8210-CEB5D81A4FE2}.Debug|Any CPU.Build.0 = Debug|Any CPU {5075D83B-EF12-4372-8210-CEB5D81A4FE2}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -50,6 +48,14 @@ Global {73D1DC76-4CD8-4534-8717-0551B635F864}.Debug|Any CPU.Build.0 = Debug|Any CPU {73D1DC76-4CD8-4534-8717-0551B635F864}.Release|Any CPU.ActiveCfg = Release|Any CPU {73D1DC76-4CD8-4534-8717-0551B635F864}.Release|Any CPU.Build.0 = Release|Any CPU + {E1D7CC3A-1340-4817-81C7-6820A2F31A8D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E1D7CC3A-1340-4817-81C7-6820A2F31A8D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E1D7CC3A-1340-4817-81C7-6820A2F31A8D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E1D7CC3A-1340-4817-81C7-6820A2F31A8D}.Release|Any CPU.Build.0 = Release|Any CPU + {AB74CB8A-5195-4CB0-9844-71AFB1F5C926}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AB74CB8A-5195-4CB0-9844-71AFB1F5C926}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AB74CB8A-5195-4CB0-9844-71AFB1F5C926}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AB74CB8A-5195-4CB0-9844-71AFB1F5C926}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Sample/Container.cs b/Sample/Container.cs index 370f4afe..a8741dbe 100644 --- a/Sample/Container.cs +++ b/Sample/Container.cs @@ -13,4 +13,6 @@ [assembly:CompositeAggregation(typeof(IComposite<>))] [assembly:TypeInitializer(typeof(ITypeInitializer), nameof(ITypeInitializer.Initialize))] [assembly:TypeInitializer(typeof(ITaskTypeInitializer), nameof(ITaskTypeInitializer.InitializeAsync))] -[assembly:TypeInitializer(typeof(IValueTaskTypeInitializer), nameof(IValueTaskTypeInitializer.InitializeAsync))] \ No newline at end of file +[assembly:TypeInitializer(typeof(IValueTaskTypeInitializer), nameof(IValueTaskTypeInitializer.InitializeAsync))] + +[assembly:AllImplementationsAggregation] \ No newline at end of file diff --git a/Sample/Context.cs b/Sample/Context.cs index f9d36e4c..6abe5573 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -1,23 +1,36 @@ using System.Collections.Generic; using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Sample; -namespace MrMeeseeks.DIE.Test.Record.PrimaryConstr; +namespace MrMeeseeks.DIE.Test.Generics.Configuration.Composite; -internal interface IInterface {} +internal interface IInterface +{ + IReadOnlyList Implementations { get; } +} -internal class Implementation : IInterface {} +internal class BaseA : IInterface +{ + public IReadOnlyList Implementations => new[] { this }; +} -internal class ImplementationA : IInterface {} +internal class BaseB : IInterface +{ + public IReadOnlyList Implementations => new[] { this }; +} -internal class Dependency +internal class Composite : IInterface, IComposite { - public IReadOnlyList Item { get; } + public IReadOnlyList Implementations { get; } - internal Dependency(IReadOnlyList item) - { - Item = item; - } + internal Composite( + IReadOnlyList implementations) => + Implementations = implementations; } -[CreateFunction(typeof(Dependency), "Create")] -internal partial class Container{} \ No newline at end of file +[GenericParameterChoice(typeof(Composite<>), "T0", typeof(int))] +[CreateFunction(typeof(IInterface), "Create")] +internal partial class Container +{ + +} \ No newline at end of file diff --git a/Sample/Program.cs b/Sample/Program.cs index 1acfafea..a0b87a86 100644 --- a/Sample/Program.cs +++ b/Sample/Program.cs @@ -1,5 +1,4 @@ -using System; -using MrMeeseeks.DIE.Test.Record.PrimaryConstr; +using MrMeeseeks.DIE.Test.Generics.Configuration.Composite; internal class Program { diff --git a/Sample/Sample.csproj b/Sample/Sample.csproj index e8ef5c6e..098a068e 100644 --- a/Sample/Sample.csproj +++ b/Sample/Sample.csproj @@ -5,6 +5,7 @@ net6.0 MrMeeseeks.DIE.Sample + MrMeeseeks.DIE.Sample true $(BaseIntermediateOutputPath)\GeneratedFiles diff --git a/SampleChild/AssemblyInfo.cs b/SampleChild/AssemblyInfo.cs new file mode 100644 index 00000000..1f84de8f --- /dev/null +++ b/SampleChild/AssemblyInfo.cs @@ -0,0 +1,17 @@ +global using Microsoft.CodeAnalysis; +global using System; +global using System.Collections.Generic; +global using System.Collections.Immutable; +global using System.Collections.ObjectModel; +global using System.Linq; +global using System.Text; +using System.Runtime.CompilerServices; + +[assembly:InternalsVisibleTo("MrMeeseeks.DIE.Sample")] + +namespace MrMeeseeks.DIE.SampleChild; + +public class AssemblyInfo +{ + +} \ No newline at end of file diff --git a/SampleChild/SampleChild.csproj b/SampleChild/SampleChild.csproj index 13c95705..0990b974 100644 --- a/SampleChild/SampleChild.csproj +++ b/SampleChild/SampleChild.csproj @@ -4,15 +4,8 @@ net6.0 MrMeeseeks.DIE.SampleChild + MrMeeseeks.DIE.SampleChild true $(BaseIntermediateOutputPath)\GeneratedFiles - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - diff --git a/SampleChild/lnternal.cs b/SampleChild/lnternal.cs index 0fe66251..2edcde79 100644 --- a/SampleChild/lnternal.cs +++ b/SampleChild/lnternal.cs @@ -22,7 +22,7 @@ internal ClassToo() { } - + internal ClassToo(int i) { diff --git a/Spy/DiagLogger.cs b/Spy/DiagLogger.cs deleted file mode 100644 index 5daaef09..00000000 --- a/Spy/DiagLogger.cs +++ /dev/null @@ -1,24 +0,0 @@ -namespace MrMeeseeks.DIE.Spy; - -internal interface IDiagLogger -{ - void Log(string message); -} - -internal class DiagLogger : IDiagLogger -{ - private readonly GeneratorExecutionContext _context; - - public DiagLogger( - GeneratorExecutionContext context) - { - _context = context; - } - - private void Log(int id, string title, string message, string category, DiagnosticSeverity diagnosticSeverity) => - _context.ReportDiagnostic(Diagnostic.Create( - new DiagnosticDescriptor($"DIESPY{id.ToString().PadLeft(3, '0')}", title, message, category, diagnosticSeverity, true), - Location.None)); - - public void Log(string message) => Log(0, "INFO", message, "INFO", DiagnosticSeverity.Warning); -} \ No newline at end of file diff --git a/Spy/ExecuteImpl.cs b/Spy/ExecuteImpl.cs deleted file mode 100644 index 94fe44ba..00000000 --- a/Spy/ExecuteImpl.cs +++ /dev/null @@ -1,33 +0,0 @@ -namespace MrMeeseeks.DIE.Spy; - -internal interface IExecute -{ - void Execute(); -} - -internal class ExecuteImpl : IExecute -{ - private readonly GeneratorExecutionContext _context; - private readonly ITypeReportGenerator _typeReportGenerator; - private readonly IDiagLogger _diagLogger; - - public ExecuteImpl( - GeneratorExecutionContext context, - ITypeReportGenerator typeReportGenerator, - IDiagLogger diagLogger) - { - _context = context; - _typeReportGenerator = typeReportGenerator; - _diagLogger = diagLogger; - } - - public void Execute() - { - _diagLogger.Log("Start Execute"); - - _typeReportGenerator.Generate( - _context.Compilation.Assembly.Name); - - _diagLogger.Log("End Execute"); - } -} \ No newline at end of file diff --git a/Spy/GetAllImplementations.cs b/Spy/GetAllImplementations.cs deleted file mode 100644 index 24ec2856..00000000 --- a/Spy/GetAllImplementations.cs +++ /dev/null @@ -1,30 +0,0 @@ -using Microsoft.CodeAnalysis.CSharp.Syntax; - -namespace MrMeeseeks.DIE.Spy; - -internal interface IGetAllImplementations -{ - IReadOnlyList AllNonStaticImplementations { get; } -} - -internal class GetAllImplementations : IGetAllImplementations -{ - private readonly GeneratorExecutionContext _context; - - public GetAllImplementations(GeneratorExecutionContext context) - { - _context = context; - } - - public IReadOnlyList AllNonStaticImplementations => new ReadOnlyCollection(_context.Compilation.SyntaxTrees - .Select(st => (st, _context.Compilation.GetSemanticModel(st))) - .SelectMany(t => t.st - .GetRoot() - .DescendantNodesAndSelf() - .OfType() - .Select(c => t.Item2.GetDeclaredSymbol(c)) - .Where(c => c is not null) - .OfType()) - .Where(nts => !nts.IsStatic) - .ToList()); -} \ No newline at end of file diff --git a/Spy/Properties/launchSettings.json b/Spy/Properties/launchSettings.json deleted file mode 100644 index a4807c69..00000000 --- a/Spy/Properties/launchSettings.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "profiles": { - "Spy": { - "commandName": "DebugRoslynComponent", - "targetProject": "..\\TestChild\\TestChild.csproj" - } - } -} \ No newline at end of file diff --git a/Spy/RoslynExtensions.cs b/Spy/RoslynExtensions.cs deleted file mode 100644 index 342a7c62..00000000 --- a/Spy/RoslynExtensions.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace MrMeeseeks.DIE.Spy; - -public static class RoslynExtensions -{ - // Picked from https://github.com/YairHalberstadt/stronginject Thank you! - public static string FullName(this ITypeSymbol type) => - type.ToDisplayString(new SymbolDisplayFormat( - globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Included, - typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces, - genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters, - parameterOptions: SymbolDisplayParameterOptions.IncludeType | SymbolDisplayParameterOptions.IncludeParamsRefOut, - memberOptions: SymbolDisplayMemberOptions.IncludeRef)); -} \ No newline at end of file diff --git a/Spy/SourceGenerator.cs b/Spy/SourceGenerator.cs deleted file mode 100644 index a51db460..00000000 --- a/Spy/SourceGenerator.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace MrMeeseeks.DIE.Spy; - -[Generator] -public class SourceGenerator : ISourceGenerator -{ - public void Initialize(GeneratorInitializationContext context) - { - } - - public void Execute(GeneratorExecutionContext context) - { - IDiagLogger diagLogger = new DiagLogger(context); - IGetAllImplementations getAllImplementations = new GetAllImplementations(context); - ITypeReportGenerator typeReportGenerator = new TypeReportGenerator(context, getAllImplementations); - IExecute execute = new ExecuteImpl(context, typeReportGenerator, diagLogger); - - execute.Execute(); - } -} \ No newline at end of file diff --git a/Spy/Spy.csproj b/Spy/Spy.csproj deleted file mode 100644 index 9f0339b0..00000000 --- a/Spy/Spy.csproj +++ /dev/null @@ -1,39 +0,0 @@ - - - - Library - netstandard2.0 - MrMeeseeks.DIE.Spy - $(RootNamespace) - - true - true - - - - AllEnabledByDefault - preview - true - - - - - - - - - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - diff --git a/Spy/TypeReportGenerator.cs b/Spy/TypeReportGenerator.cs deleted file mode 100644 index 73acf3d8..00000000 --- a/Spy/TypeReportGenerator.cs +++ /dev/null @@ -1,137 +0,0 @@ -using System; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.Text; - -namespace MrMeeseeks.DIE.Spy; - -internal interface ITypeReportGenerator -{ - void Generate(string namespaceName); -} - -internal class TypeReportGenerator : ITypeReportGenerator -{ - private readonly GeneratorExecutionContext _context; - private readonly IGetAllImplementations _getAllImplementations; - - public TypeReportGenerator( - GeneratorExecutionContext context, - IGetAllImplementations getAllImplementations) - { - _context = context; - _getAllImplementations = getAllImplementations; - } - - public void Generate(string namespaceName) - { - var allNonStaticImplementations = _getAllImplementations - .AllNonStaticImplementations - .ToList(); - var generatedContainer = new StringBuilder() - .AppendLine($"namespace {namespaceName}") - .AppendLine("{"); - - generatedContainer = GenerateBody(Accessibility.Public, allNonStaticImplementations, generatedContainer); - - generatedContainer = GenerateBody(Accessibility.Internal, allNonStaticImplementations, generatedContainer); - - generatedContainer = generatedContainer - .AppendLine("}"); - - var containerSource = CSharpSyntaxTree - .ParseText(SourceText.From(generatedContainer.ToString(), Encoding.UTF8)) - .GetRoot() - .NormalizeWhitespace() - .SyntaxTree - .GetText(); - _context.AddSource("TypeReport.g.cs", containerSource); - - static StringBuilder GenerateBody(Accessibility accessModifier, IList allNonStaticImplementations, StringBuilder generatedContainer) - { - var lowerCaseAccessModifier = accessModifier.ToString().ToLower(); - var pascalCaseAccessModifier = accessModifier.ToString(); - - var types = allNonStaticImplementations - .Where(t => t.DeclaredAccessibility == accessModifier) - .ToList(); - - generatedContainer = generatedContainer - .AppendLine($"{lowerCaseAccessModifier} interface I{pascalCaseAccessModifier}TypeReport") - .AppendLine("{"); - - var i = -1; - generatedContainer = types.Aggregate( - generatedContainer, - (current, type) => current.AppendLine( - $"{FullName(type)} Type{++i}{(type.TypeArguments.Length > 0 ? $"<{string.Join(", ", type.TypeArguments.Select(t => t.Name))}>" : "")}(){TypeArgumentsConstraintsString(type)};")); - - generatedContainer = generatedContainer - .AppendLine("}") - .AppendLine($"{lowerCaseAccessModifier} static class {pascalCaseAccessModifier}ConstructorReport") - .AppendLine("{"); - - foreach (var implementation in allNonStaticImplementations - .Where(i => i.Constructors.Any(c => c.DeclaredAccessibility == accessModifier))) - { - generatedContainer = generatedContainer - .AppendLine($"{lowerCaseAccessModifier} static class {implementation.FullName().Replace(':','_').Replace('.', '_')}") - .AppendLine("{"); - - foreach (var constructor in implementation.Constructors - .Where(c => c.DeclaredAccessibility == accessModifier)) - { - int j = 0; - generatedContainer = generatedContainer - .AppendLine( - $"{lowerCaseAccessModifier} interface {(constructor.Parameters.Any() ? "" : "_")}{string.Join("_", constructor.Parameters.Select(p => p.Type.Name))}") - .AppendLine($"{{") - .AppendLine($"{implementation.FullName()} _{(j++).ToString().PadLeft(20, '0')}();"); - - foreach (var constructorParameter in constructor.Parameters) - { - generatedContainer = generatedContainer - .AppendLine($"{constructorParameter.Type.FullName()} _{(j++).ToString().PadLeft(20, '0')}();"); - } - - generatedContainer = generatedContainer - .AppendLine($"}}"); - } - - generatedContainer = generatedContainer - .AppendLine("}"); - } - - generatedContainer = generatedContainer - .AppendLine("}"); - - return generatedContainer; - } - - static string FullName(ISymbol type) => - type.ToDisplayString(new SymbolDisplayFormat( - globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Included, - typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces, - parameterOptions: SymbolDisplayParameterOptions.IncludeType | SymbolDisplayParameterOptions.IncludeParamsRefOut, - genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters, - memberOptions: SymbolDisplayMemberOptions.IncludeRef)); - - static string TypeArgumentsConstraintsString(INamedTypeSymbol namedTypeSymbol) - { - var displayStringWithoutConstraints = namedTypeSymbol.ToDisplayString(new SymbolDisplayFormat( - globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Included, - typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces, - parameterOptions: SymbolDisplayParameterOptions.IncludeType | SymbolDisplayParameterOptions.IncludeParamsRefOut, - genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters, - memberOptions: SymbolDisplayMemberOptions.IncludeRef)); - var displayStringWithConstraints = namedTypeSymbol.ToDisplayString(new SymbolDisplayFormat( - globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Included, - typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces, - parameterOptions: SymbolDisplayParameterOptions.IncludeType | SymbolDisplayParameterOptions.IncludeParamsRefOut, - genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters | SymbolDisplayGenericsOptions.IncludeTypeConstraints, - memberOptions: SymbolDisplayMemberOptions.IncludeRef)); - - var ret = displayStringWithConstraints.Remove(0, displayStringWithoutConstraints.Length); - return ret; - } - } -} \ No newline at end of file diff --git a/Test/AssemblyInfo.cs b/Test/AssemblyInfo.cs index 7a478ec0..d8604e18 100644 --- a/Test/AssemblyInfo.cs +++ b/Test/AssemblyInfo.cs @@ -13,4 +13,6 @@ [assembly:CompositeAggregation(typeof(IComposite<>))] [assembly:TypeInitializer(typeof(ITypeInitializer), nameof(ITypeInitializer.Initialize))] [assembly:TypeInitializer(typeof(ITaskTypeInitializer), nameof(ITaskTypeInitializer.InitializeAsync))] -[assembly:TypeInitializer(typeof(IValueTaskTypeInitializer), nameof(IValueTaskTypeInitializer.InitializeAsync))] \ No newline at end of file +[assembly:TypeInitializer(typeof(IValueTaskTypeInitializer), nameof(IValueTaskTypeInitializer.InitializeAsync))] + +[assembly:AllImplementationsAggregation] \ No newline at end of file diff --git a/Test/Decorator/List.cs b/Test/Decorator/List.cs index 1d365a35..8ba7b830 100644 --- a/Test/Decorator/List.cs +++ b/Test/Decorator/List.cs @@ -50,7 +50,7 @@ public void Test() Assert.NotEqual(decoratedBasisA, decoratedBasisB); Assert.IsType(decoratedOfA); Assert.IsType(decoratedOfB); - Assert.IsType(decoratedBasisA); - Assert.IsType(decoratedBasisB); + Assert.True(decoratedBasisA.GetType() == typeof(DependencyA) && decoratedBasisB.GetType() == typeof(DependencyB) + || decoratedBasisA.GetType() == typeof(DependencyB) && decoratedBasisB.GetType() == typeof(DependencyA)); } } \ No newline at end of file diff --git a/Test/Generics/Choice/DoubleBothChosenWithSingleOtherSubstitute.cs b/Test/Generics/Choice/DoubleBothChosenWithSingleOtherSubstitute.cs index 1368b9b4..d2699b74 100644 --- a/Test/Generics/Choice/DoubleBothChosenWithSingleOtherSubstitute.cs +++ b/Test/Generics/Choice/DoubleBothChosenWithSingleOtherSubstitute.cs @@ -7,9 +7,9 @@ internal interface IInterface {} internal class Class : IInterface {} -[GenericParameterSubstituteAggregation(typeof(Class<,>), "T0", typeof(uint))] +[GenericParameterSubstitutesChoice(typeof(Class<,>), "T0", typeof(uint))] [GenericParameterChoice(typeof(Class<,>), "T0", typeof(int))] -[GenericParameterSubstituteAggregation(typeof(Class<,>), "T1", typeof(bool))] +[GenericParameterSubstitutesChoice(typeof(Class<,>), "T1", typeof(bool))] [GenericParameterChoice(typeof(Class<,>), "T1", typeof(string))] [CreateFunction(typeof(IInterface), "Create")] internal partial class Container {} diff --git a/Test/Generics/Choice/DoubleWithSingleOtherSubstitute.cs b/Test/Generics/Choice/DoubleWithSingleOtherSubstitute.cs index e9a50dfe..ec7d6087 100644 --- a/Test/Generics/Choice/DoubleWithSingleOtherSubstitute.cs +++ b/Test/Generics/Choice/DoubleWithSingleOtherSubstitute.cs @@ -7,7 +7,7 @@ internal interface IInterface {} internal class Class : IInterface {} -[GenericParameterSubstituteAggregation(typeof(Class<,>), "T1", typeof(bool))] +[GenericParameterSubstitutesChoice(typeof(Class<,>), "T1", typeof(bool))] [GenericParameterChoice(typeof(Class<,>), "T1", typeof(string))] [CreateFunction(typeof(IInterface), "Create")] internal partial class Container {} diff --git a/Test/Generics/Choice/SingleWithSingleOtherSubstitute.cs b/Test/Generics/Choice/SingleWithSingleOtherSubstitute.cs index 7f55954a..4fe0fef3 100644 --- a/Test/Generics/Choice/SingleWithSingleOtherSubstitute.cs +++ b/Test/Generics/Choice/SingleWithSingleOtherSubstitute.cs @@ -7,7 +7,7 @@ internal interface IInterface {} internal class Class : IInterface {} -[GenericParameterSubstituteAggregation(typeof(Class<>), "T0", typeof(bool))] +[GenericParameterSubstitutesChoice(typeof(Class<>), "T0", typeof(bool))] [GenericParameterChoice(typeof(Class<>), "T0", typeof(int))] [CreateFunction(typeof(IInterface), "Create")] internal partial class Container {} diff --git a/Test/Generics/ChoiceIndirectlyBySingleSubstitute/Double.cs b/Test/Generics/ChoiceIndirectlyBySingleSubstitute/Double.cs index 0ec7d0aa..ba1b8eb8 100644 --- a/Test/Generics/ChoiceIndirectlyBySingleSubstitute/Double.cs +++ b/Test/Generics/ChoiceIndirectlyBySingleSubstitute/Double.cs @@ -7,7 +7,7 @@ internal interface IInterface {} internal class Class : IInterface {} -[GenericParameterSubstituteAggregation(typeof(Class<,>), "T1", typeof(string))] +[GenericParameterSubstitutesChoice(typeof(Class<,>), "T1", typeof(string))] [CreateFunction(typeof(IInterface), "Create")] internal partial class Container {} diff --git a/Test/Generics/ChoiceIndirectlyBySingleSubstitute/Single.cs b/Test/Generics/ChoiceIndirectlyBySingleSubstitute/Single.cs index cd00e904..70374dd4 100644 --- a/Test/Generics/ChoiceIndirectlyBySingleSubstitute/Single.cs +++ b/Test/Generics/ChoiceIndirectlyBySingleSubstitute/Single.cs @@ -7,7 +7,7 @@ internal interface IInterface {} internal class Class : IInterface {} -[GenericParameterSubstituteAggregation(typeof(Class<>), "T0", typeof(int))] +[GenericParameterSubstitutesChoice(typeof(Class<>), "T0", typeof(int))] [CreateFunction(typeof(IInterface), "Create")] internal partial class Container {} diff --git a/Test/Generics/SubstituteCollection/Double.cs b/Test/Generics/SubstituteCollection/Double.cs index c34e9ef8..ba52c25a 100644 --- a/Test/Generics/SubstituteCollection/Double.cs +++ b/Test/Generics/SubstituteCollection/Double.cs @@ -8,7 +8,7 @@ internal interface IInterface {} internal class Class : IInterface {} -[GenericParameterSubstituteAggregation(typeof(Class<,>), "T1", typeof(int), typeof(string))] +[GenericParameterSubstitutesChoice(typeof(Class<,>), "T1", typeof(int), typeof(string))] [CreateFunction(typeof(IReadOnlyList>), "Create")] internal partial class Container {} diff --git a/Test/Generics/SubstituteCollection/DoubleBothSubstituted.cs b/Test/Generics/SubstituteCollection/DoubleBothSubstituted.cs index 94b3103e..fb9a72e0 100644 --- a/Test/Generics/SubstituteCollection/DoubleBothSubstituted.cs +++ b/Test/Generics/SubstituteCollection/DoubleBothSubstituted.cs @@ -8,8 +8,8 @@ internal interface IInterface {} internal class Class : IInterface {} -[GenericParameterSubstituteAggregation(typeof(Class<,>), "T0", typeof(bool), typeof(byte))] -[GenericParameterSubstituteAggregation(typeof(Class<,>), "T1", typeof(int), typeof(string))] +[GenericParameterSubstitutesChoice(typeof(Class<,>), "T0", typeof(bool), typeof(byte))] +[GenericParameterSubstitutesChoice(typeof(Class<,>), "T1", typeof(int), typeof(string))] [CreateFunction(typeof(IReadOnlyList), "Create")] internal partial class Container {} diff --git a/Test/Generics/SubstituteCollection/DoubleBothSubstitutedWithChoice.cs b/Test/Generics/SubstituteCollection/DoubleBothSubstitutedWithChoice.cs index d513e614..777f083b 100644 --- a/Test/Generics/SubstituteCollection/DoubleBothSubstitutedWithChoice.cs +++ b/Test/Generics/SubstituteCollection/DoubleBothSubstitutedWithChoice.cs @@ -8,8 +8,8 @@ internal interface IInterface {} internal class Class : IInterface {} -[GenericParameterSubstituteAggregation(typeof(Class<,>), "T0", typeof(bool))] -[GenericParameterSubstituteAggregation(typeof(Class<,>), "T1", typeof(int))] +[GenericParameterSubstitutesChoice(typeof(Class<,>), "T0", typeof(bool))] +[GenericParameterSubstitutesChoice(typeof(Class<,>), "T1", typeof(int))] [GenericParameterChoice(typeof(Class<,>), "T0", typeof(byte))] [GenericParameterChoice(typeof(Class<,>), "T1", typeof(string))] [CreateFunction(typeof(IReadOnlyList), "Create")] diff --git a/Test/Generics/SubstituteCollection/DoubleWithChoice.cs b/Test/Generics/SubstituteCollection/DoubleWithChoice.cs index 066ecde4..895f9eeb 100644 --- a/Test/Generics/SubstituteCollection/DoubleWithChoice.cs +++ b/Test/Generics/SubstituteCollection/DoubleWithChoice.cs @@ -8,7 +8,7 @@ internal interface IInterface {} internal class Class : IInterface {} -[GenericParameterSubstituteAggregation(typeof(Class<,>), "T1", typeof(int))] +[GenericParameterSubstitutesChoice(typeof(Class<,>), "T1", typeof(int))] [GenericParameterChoice(typeof(Class<,>), "T1", typeof(string))] [CreateFunction(typeof(IReadOnlyList>), "Create")] internal partial class Container {} diff --git a/Test/Generics/SubstituteCollection/Single.cs b/Test/Generics/SubstituteCollection/Single.cs index daaa749d..5a1b9567 100644 --- a/Test/Generics/SubstituteCollection/Single.cs +++ b/Test/Generics/SubstituteCollection/Single.cs @@ -10,7 +10,7 @@ internal interface IInterface {} internal class Class : IInterface {} -[GenericParameterSubstituteAggregation(typeof(Class<>), "T0", typeof(int), typeof(string))] +[GenericParameterSubstitutesChoice(typeof(Class<>), "T0", typeof(int), typeof(string))] [CreateFunction(typeof(IReadOnlyList), "Create")] internal partial class Container {} diff --git a/Test/Generics/SubstituteCollection/SingleWithChoice.cs b/Test/Generics/SubstituteCollection/SingleWithChoice.cs index 21c40b91..010beb03 100644 --- a/Test/Generics/SubstituteCollection/SingleWithChoice.cs +++ b/Test/Generics/SubstituteCollection/SingleWithChoice.cs @@ -10,7 +10,7 @@ internal interface IInterface {} internal class Class : IInterface {} -[GenericParameterSubstituteAggregation(typeof(Class<>), "T0", typeof(int))] +[GenericParameterSubstitutesChoice(typeof(Class<>), "T0", typeof(int))] [GenericParameterChoice(typeof(Class<>), "T0", typeof(string))] [CreateFunction(typeof(IReadOnlyList), "Create")] internal partial class Container {} diff --git a/Test/Generics/SubstituteCollection/TripleInsanity.cs b/Test/Generics/SubstituteCollection/TripleInsanity.cs index 70c5a326..a193d032 100644 --- a/Test/Generics/SubstituteCollection/TripleInsanity.cs +++ b/Test/Generics/SubstituteCollection/TripleInsanity.cs @@ -8,9 +8,9 @@ internal interface IInterface {} internal class Class : IInterface {} -[GenericParameterSubstituteAggregation(typeof(Class<,,>), "T0", typeof(int), typeof(string), typeof(uint), typeof(bool), typeof(byte))] -[GenericParameterSubstituteAggregation(typeof(Class<,,>), "T1", typeof(int), typeof(string), typeof(uint), typeof(bool), typeof(byte))] -[GenericParameterSubstituteAggregation(typeof(Class<,,>), "T2", typeof(int), typeof(string), typeof(uint), typeof(bool), typeof(byte))] +[GenericParameterSubstitutesChoice(typeof(Class<,,>), "T0", typeof(int), typeof(string), typeof(uint), typeof(bool), typeof(byte))] +[GenericParameterSubstitutesChoice(typeof(Class<,,>), "T1", typeof(int), typeof(string), typeof(uint), typeof(bool), typeof(byte))] +[GenericParameterSubstitutesChoice(typeof(Class<,,>), "T2", typeof(int), typeof(string), typeof(uint), typeof(bool), typeof(byte))] [CreateFunction(typeof(IReadOnlyList), "Create")] internal partial class Container {} diff --git a/Test/Implementation/Aggregation/AssemblyImplementationsAggregation.cs b/Test/Implementation/Aggregation/AssemblyImplementationsAggregation.cs new file mode 100644 index 00000000..d3021c65 --- /dev/null +++ b/Test/Implementation/Aggregation/AssemblyImplementationsAggregation.cs @@ -0,0 +1,23 @@ +using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.TestNotInternalsVisibleToChild.Public; +using MrMeeseeks.DIE.TestNotInternalsVisibleToChild; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Implementation.Aggregation.AssemblyImplementationsAggregation; + +[FilterAllImplementationsAggregation] +[AssemblyImplementationsAggregation(typeof(AssemblyInfo))] +[ConstructorChoice(typeof(Parent.ClassToo))] +[CreateFunction(typeof(Parent.ClassToo), "Create")] +internal partial class Container {} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var instance = container.Create(); + Assert.IsType(instance); + } +} \ No newline at end of file diff --git a/Test/ImplementationAggregation/ExternalType.cs b/Test/Implementation/Aggregation/ExternalType.cs similarity index 81% rename from Test/ImplementationAggregation/ExternalType.cs rename to Test/Implementation/Aggregation/ExternalType.cs index ace9fd37..55551d3d 100644 --- a/Test/ImplementationAggregation/ExternalType.cs +++ b/Test/Implementation/Aggregation/ExternalType.cs @@ -3,9 +3,10 @@ using MrMeeseeks.DIE.Configuration; using Xunit; -namespace MrMeeseeks.DIE.Test.ImplementationAggregation.ExternalType; +namespace MrMeeseeks.DIE.Test.Implementation.Aggregation.ExternalType; +[AssemblyImplementationsAggregation(typeof(FileInfo))] [ImplementationAggregation(typeof(FileInfo))] [CreateFunction(typeof(Func), "Create")] internal partial class Container diff --git a/Test/Implementation/Aggregation/FilterAllImplementations.cs b/Test/Implementation/Aggregation/FilterAllImplementations.cs new file mode 100644 index 00000000..5edb9125 --- /dev/null +++ b/Test/Implementation/Aggregation/FilterAllImplementations.cs @@ -0,0 +1,26 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Implementation.Aggregation.FilterAllImplementations; + +internal interface IInterface { } + +internal class DependencyA : IInterface {} + +internal class DependencyB : IInterface {} + +[FilterAllImplementationsAggregation] +[ImplementationAggregation(typeof(DependencyB))] +[CreateFunction(typeof(IInterface), "Create")] +internal partial class Container {} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var instance = container.Create(); + Assert.IsType(instance); + } +} \ No newline at end of file diff --git a/Test/Implementation/Aggregation/InternalsVisibleTo.cs b/Test/Implementation/Aggregation/InternalsVisibleTo.cs new file mode 100644 index 00000000..a0dd64e7 --- /dev/null +++ b/Test/Implementation/Aggregation/InternalsVisibleTo.cs @@ -0,0 +1,20 @@ +using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.TestInternalsVisibleToChild.Internal; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Implementation.Aggregation.InternalsVisibleTo; + +[ConstructorChoice(typeof(Parent.ClassToo))] +[CreateFunction(typeof(Parent.ClassToo), "Create")] +internal partial class Container {} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var instance = container.Create(); + Assert.IsType(instance); + } +} \ No newline at end of file diff --git a/Test/Implementation/Choice/Collection.cs b/Test/Implementation/Choice/Collection.cs new file mode 100644 index 00000000..b864e8ef --- /dev/null +++ b/Test/Implementation/Choice/Collection.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Implementation.Choice.Collection; + +internal class Class {} + +internal class SubClassA : Class {} + +internal class SubClassB : Class {} + +[ImplementationCollectionChoice(typeof(Class), typeof(SubClassA), typeof(SubClassB))] +[CreateFunction(typeof(IReadOnlyList), "Create")] +internal partial class Container {} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var instances = container.Create(); + Assert.True(instances.Count == 2); + Assert.True(instances[0].GetType() == typeof(SubClassA) && instances[1].GetType() == typeof(SubClassB) + || instances[0].GetType() == typeof(SubClassB) && instances[1].GetType() == typeof(SubClassA)); + } +} \ No newline at end of file diff --git a/Test/Implementation/Choice/CollectionWithoutChoice.cs b/Test/Implementation/Choice/CollectionWithoutChoice.cs new file mode 100644 index 00000000..35aae97a --- /dev/null +++ b/Test/Implementation/Choice/CollectionWithoutChoice.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Implementation.Choice.CollectionWithoutChoice; + +internal class Class {} + +internal class SubClassA : Class {} + +internal class SubClassB : Class {} + +[CreateFunction(typeof(IReadOnlyList), "Create")] +internal partial class Container {} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var instances = container.Create(); + Assert.True(instances.Count == 3); + } +} \ No newline at end of file diff --git a/Test/Implementation/Choice/SingleInCollection.cs b/Test/Implementation/Choice/SingleInCollection.cs new file mode 100644 index 00000000..bfa5c39a --- /dev/null +++ b/Test/Implementation/Choice/SingleInCollection.cs @@ -0,0 +1,23 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Implementation.Choice.SingleInCollection; + +internal class Class {} + +internal class SubClass : Class {} + +[ImplementationCollectionChoice(typeof(Class), typeof(SubClass))] +[CreateFunction(typeof(Class), "Create")] +internal partial class Container {} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var instance = container.Create(); + Assert.IsType(instance); + } +} \ No newline at end of file diff --git a/Test/Implementation/Choice/Vanilla.cs b/Test/Implementation/Choice/Vanilla.cs new file mode 100644 index 00000000..050f86d6 --- /dev/null +++ b/Test/Implementation/Choice/Vanilla.cs @@ -0,0 +1,23 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Implementation.Choice.Vanilla; + +internal class Class {} + +internal class SubClass : Class {} + +[ImplementationChoice(typeof(Class), typeof(SubClass))] +[CreateFunction(typeof(Class), "Create")] +internal partial class Container {} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var instance = container.Create(); + Assert.IsType(instance); + } +} \ No newline at end of file diff --git a/Test/Implementation/Choice/VanillaWithoutChoice.cs b/Test/Implementation/Choice/VanillaWithoutChoice.cs new file mode 100644 index 00000000..00660552 --- /dev/null +++ b/Test/Implementation/Choice/VanillaWithoutChoice.cs @@ -0,0 +1,22 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Implementation.Choice.VanillaWithoutChoice; + +internal class Class {} + +internal class SubClass : Class {} + +[CreateFunction(typeof(Class), "Create")] +internal partial class Container {} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var instance = container.Create(); + Assert.IsType(instance); + } +} \ No newline at end of file diff --git a/Test/Implementation/Choice/WithSingleInCollection.cs b/Test/Implementation/Choice/WithSingleInCollection.cs new file mode 100644 index 00000000..5b8c3478 --- /dev/null +++ b/Test/Implementation/Choice/WithSingleInCollection.cs @@ -0,0 +1,26 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Implementation.Choice.WithSingleInCollection; + +internal class Class {} + +internal class SubClassA : Class {} + +internal class SubClassB : Class {} + +[ImplementationChoice(typeof(Class), typeof(SubClassA))] +[ImplementationCollectionChoice(typeof(Class), typeof(SubClassB))] +[CreateFunction(typeof(Class), "Create")] +internal partial class Container {} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var instance = container.Create(); + Assert.IsType(instance); + } +} \ No newline at end of file diff --git a/Test/Spy/Implementations.cs b/Test/Spy/Implementations.cs deleted file mode 100644 index 8734772e..00000000 --- a/Test/Spy/Implementations.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; -using MrMeeseeks.DIE.Configuration; -using MrMeeseeks.DIE.TestChild; -using TestChild; -using Xunit; - -namespace MrMeeseeks.DIE.Test.Spy.Implementations; - -[SpyAggregation(typeof(IPublicTypeReport))] -[SpyConstructorChoiceAggregation( - typeof(PublicConstructorReport.global__MrMeeseeks_DIE_TestChild_Class._), - typeof(PublicConstructorReport.global__MrMeeseeks_DIE_TestChild_ClassToo.Int32))] -[CreateFunction(typeof(Class), "CreateClass")] -[CreateFunction(typeof(Func), "CreateClassToo")] -internal partial class Container -{ - -} - -public class Tests -{ - [Fact] - public void Test() - { - var container = new Container(); - var _ = container.CreateClass(); - var __ = container.CreateClassToo()(69); - } -} \ No newline at end of file diff --git a/Test/Test.csproj b/Test/Test.csproj index 473c641d..74b61a79 100644 --- a/Test/Test.csproj +++ b/Test/Test.csproj @@ -4,6 +4,7 @@ net6.0 MrMeeseeks.DIE.Test + MrMeeseeks.DIE.Test false true $(BaseIntermediateOutputPath)\GeneratedFiles @@ -33,6 +34,8 @@ runtime; build; native; contentfiles; analyzers; buildtransitive + + diff --git a/TestChild/TestChild.csproj b/TestChild/TestChild.csproj index 8f16c11c..7915f50e 100644 --- a/TestChild/TestChild.csproj +++ b/TestChild/TestChild.csproj @@ -4,16 +4,8 @@ net6.0 MrMeeseeks.DIE.TestChild + MrMeeseeks.DIE.TestChild true $(BaseIntermediateOutputPath)\GeneratedFiles - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - diff --git a/TestInternalsVisibleToChild/AssemblyInfo.cs b/TestInternalsVisibleToChild/AssemblyInfo.cs new file mode 100644 index 00000000..72a83f9e --- /dev/null +++ b/TestInternalsVisibleToChild/AssemblyInfo.cs @@ -0,0 +1,17 @@ +global using Microsoft.CodeAnalysis; +global using System; +global using System.Collections.Generic; +global using System.Collections.Immutable; +global using System.Collections.ObjectModel; +global using System.Linq; +global using System.Text; +using System.Runtime.CompilerServices; + +[assembly:InternalsVisibleTo("MrMeeseeks.DIE.Test")] + +namespace MrMeeseeks.DIE.TestInternalsVisibleToChild; + +public class AssemblyInfo +{ + +} \ No newline at end of file diff --git a/TestInternalsVisibleToChild/Public.cs b/TestInternalsVisibleToChild/Public.cs new file mode 100644 index 00000000..624d7d70 --- /dev/null +++ b/TestInternalsVisibleToChild/Public.cs @@ -0,0 +1,124 @@ +namespace MrMeeseeks.DIE.TestInternalsVisibleToChild.Public; + +public interface IClass {} + +public class Class : IClass +{ + public Class() + { + } + + public Class(int i) + { + + } +} + +public interface IClassToo {} + +public class ClassToo : IClassToo +{ + public ClassToo() + { + + } + + public ClassToo(int i) + { + + } +} + +public interface IClass {} + +public class Class : IClass +{ + public Class() + { + } + + public Class(int i) + { + + } +} + +public static class StaticParent +{ + public class Class : IClass + { + public Class() + { + } + + public Class(int i) + { + + } + } + + public class ClassToo : IClassToo + { + public ClassToo() + { + + } + + public ClassToo(int i) + { + + } + } + + public class Class : IClass + { + public Class() + { + } + + public Class(int i) + { + + } + } +} + +public class Parent +{ + public class Class : IClass + { + public Class() + { + } + + public Class(int i) + { + + } + } + + public class ClassToo : IClassToo + { + public ClassToo() + { + + } + + public ClassToo(int i) + { + + } + } + + public class Class : IClass + { + public Class() + { + } + + public Class(int i) + { + + } + } +} \ No newline at end of file diff --git a/TestInternalsVisibleToChild/TestInternalsVisibleToChild.csproj b/TestInternalsVisibleToChild/TestInternalsVisibleToChild.csproj new file mode 100644 index 00000000..198134eb --- /dev/null +++ b/TestInternalsVisibleToChild/TestInternalsVisibleToChild.csproj @@ -0,0 +1,12 @@ + + + + net6.0 + + MrMeeseeks.DIE.TestInternalsVisibleToChild + MrMeeseeks.DIE.TestInternalsVisibleToChild + true + $(BaseIntermediateOutputPath)\GeneratedFiles + + + diff --git a/TestInternalsVisibleToChild/lnternal.cs b/TestInternalsVisibleToChild/lnternal.cs new file mode 100644 index 00000000..840ad848 --- /dev/null +++ b/TestInternalsVisibleToChild/lnternal.cs @@ -0,0 +1,125 @@ +namespace MrMeeseeks.DIE.TestInternalsVisibleToChild.Internal; + +internal interface IClass {} + +internal class Class : IClass +{ + internal Class() + { + } + + internal Class(int i) + { + + } +} + +internal interface IClassToo {} + +internal class ClassToo : IClassToo +{ + internal ClassToo() + { + + } + + internal ClassToo(int i) + { + + } +} + +internal interface IClass {} + +internal class Class : IClass +{ + internal Class() + { + } + + internal Class(int i) + { + + } +} + +internal static class StaticParent +{ + internal class Class : IClass + { + internal Class() + { + } + + internal Class(int i) + { + + } + } + + internal class ClassToo : IClassToo + { + internal ClassToo() + { + + } + + internal ClassToo(int i) + { + + } + } + + internal class Class : IClass + { + internal Class() + { + } + + internal Class(int i) + { + + } + } +} + +internal class Parent +{ + internal Parent() {} + internal class Class : IClass + { + internal Class() + { + } + + internal Class(int i) + { + + } + } + + internal class ClassToo : IClassToo + { + internal ClassToo() + { + + } + + internal ClassToo(int i) + { + + } + } + + internal class Class : IClass + { + internal Class() + { + } + + internal Class(int i) + { + + } + } +} \ No newline at end of file diff --git a/Spy/AssemblyInfo.cs b/TestNotInternalsVisibleToChild/AssemblyInfo.cs similarity index 63% rename from Spy/AssemblyInfo.cs rename to TestNotInternalsVisibleToChild/AssemblyInfo.cs index 71805a26..0b82f08a 100644 --- a/Spy/AssemblyInfo.cs +++ b/TestNotInternalsVisibleToChild/AssemblyInfo.cs @@ -1,10 +1,12 @@ global using Microsoft.CodeAnalysis; +global using System; global using System.Collections.Generic; +global using System.Collections.Immutable; global using System.Collections.ObjectModel; global using System.Linq; global using System.Text; -namespace MrMeeseeks.DIE.Spy; +namespace MrMeeseeks.DIE.TestNotInternalsVisibleToChild; public class AssemblyInfo { diff --git a/TestNotInternalsVisibleToChild/Public.cs b/TestNotInternalsVisibleToChild/Public.cs new file mode 100644 index 00000000..e1a47a6c --- /dev/null +++ b/TestNotInternalsVisibleToChild/Public.cs @@ -0,0 +1,124 @@ +namespace MrMeeseeks.DIE.TestNotInternalsVisibleToChild.Public; + +public interface IClass {} + +public class Class : IClass +{ + public Class() + { + } + + public Class(int i) + { + + } +} + +public interface IClassToo {} + +public class ClassToo : IClassToo +{ + public ClassToo() + { + + } + + public ClassToo(int i) + { + + } +} + +public interface IClass {} + +public class Class : IClass +{ + public Class() + { + } + + public Class(int i) + { + + } +} + +public static class StaticParent +{ + public class Class : IClass + { + public Class() + { + } + + public Class(int i) + { + + } + } + + public class ClassToo : IClassToo + { + public ClassToo() + { + + } + + public ClassToo(int i) + { + + } + } + + public class Class : IClass + { + public Class() + { + } + + public Class(int i) + { + + } + } +} + +public class Parent +{ + public class Class : IClass + { + public Class() + { + } + + public Class(int i) + { + + } + } + + public class ClassToo : IClassToo + { + public ClassToo() + { + + } + + public ClassToo(int i) + { + + } + } + + public class Class : IClass + { + public Class() + { + } + + public Class(int i) + { + + } + } +} \ No newline at end of file diff --git a/TestNotInternalsVisibleToChild/TestNotInternalsVisibleToChild.csproj b/TestNotInternalsVisibleToChild/TestNotInternalsVisibleToChild.csproj new file mode 100644 index 00000000..604b06f1 --- /dev/null +++ b/TestNotInternalsVisibleToChild/TestNotInternalsVisibleToChild.csproj @@ -0,0 +1,12 @@ + + + + net6.0 + + MrMeeseeks.DIE.TestNotInternalsVisibleToChild + MrMeeseeks.DIE.TestNotInternalsVisibleToChild + true + $(BaseIntermediateOutputPath)\GeneratedFiles + + + diff --git a/TestNotInternalsVisibleToChild/lnternal.cs b/TestNotInternalsVisibleToChild/lnternal.cs new file mode 100644 index 00000000..315cc202 --- /dev/null +++ b/TestNotInternalsVisibleToChild/lnternal.cs @@ -0,0 +1,125 @@ +namespace MrMeeseeks.DIE.TestNotInternalsVisibleToChild.Internal; + +internal interface IClass {} + +internal class Class : IClass +{ + internal Class() + { + } + + internal Class(int i) + { + + } +} + +internal interface IClassToo {} + +internal class ClassToo : IClassToo +{ + internal ClassToo() + { + + } + + internal ClassToo(int i) + { + + } +} + +internal interface IClass {} + +internal class Class : IClass +{ + internal Class() + { + } + + internal Class(int i) + { + + } +} + +internal static class StaticParent +{ + internal class Class : IClass + { + internal Class() + { + } + + internal Class(int i) + { + + } + } + + internal class ClassToo : IClassToo + { + internal ClassToo() + { + + } + + internal ClassToo(int i) + { + + } + } + + internal class Class : IClass + { + internal Class() + { + } + + internal Class(int i) + { + + } + } +} + +internal class Parent +{ + internal Parent() {} + internal class Class : IClass + { + internal Class() + { + } + + internal Class(int i) + { + + } + } + + internal class ClassToo : IClassToo + { + internal ClassToo() + { + + } + + internal ClassToo(int i) + { + + } + } + + internal class Class : IClass + { + internal Class() + { + } + + internal Class(int i) + { + + } + } +} \ No newline at end of file From 8aec290701fa13b12b85d64448cdfb736bb8cc28 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sat, 14 May 2022 22:49:35 +0200 Subject: [PATCH 071/162] Struct support --- Main/Configuration/CheckTypeProperties.cs | 40 +++++++-------------- Sample/Context.cs | 38 +++----------------- Sample/Program.cs | 4 ++- Test/Struct/NoExplicitConstructor.cs | 20 +++++++++++ Test/Struct/OneExplicitConstructor.cs | 28 +++++++++++++++ Test/Struct/RecordNoExplicitConstructor.cs | 20 +++++++++++ Test/Struct/RecordOneExplicitConstructor.cs | 23 ++++++++++++ 7 files changed, 111 insertions(+), 62 deletions(-) create mode 100644 Test/Struct/NoExplicitConstructor.cs create mode 100644 Test/Struct/OneExplicitConstructor.cs create mode 100644 Test/Struct/RecordNoExplicitConstructor.cs create mode 100644 Test/Struct/RecordOneExplicitConstructor.cs diff --git a/Main/Configuration/CheckTypeProperties.cs b/Main/Configuration/CheckTypeProperties.cs index 9614b632..97eaac87 100644 --- a/Main/Configuration/CheckTypeProperties.cs +++ b/Main/Configuration/CheckTypeProperties.cs @@ -50,6 +50,9 @@ internal CheckTypeProperties( public DisposalType ShouldDisposalBeManaged(INamedTypeSymbol implementationType) { + if (implementationType.TypeKind is TypeKind.Struct or TypeKind.Structure) + return DisposalType.None; + if (implementationType.AllInterfaces.Contains(_wellKnownTypes.AsyncDisposable) && !_currentlyConsideredTypes.AsyncTransientTypes.Contains(implementationType.UnboundIfGeneric())) return DisposalType.Async; @@ -99,44 +102,25 @@ public ScopeLevel GetScopeLevelFor(INamedTypeSymbol implementationType) return constr; var typeToChoseFrom = implementationType.OriginalDefinitionIfUnbound(); - if (typeToChoseFrom.Constructors.Length == 1 - && typeToChoseFrom.Constructors.SingleOrDefault() is { } constructor) - return constructor; return typeToChoseFrom switch { // If reference record and two constructors, decide for the constructor which isn't the copy-constructor - { IsRecord: true, IsValueType: false, Constructors.Length: 2 } + { IsRecord: true, IsReferenceType: true, IsValueType: false, Constructors.Length: 2 } when typeToChoseFrom .Constructors.SingleOrDefault(c => c.Parameters.Length != 1 || !SymbolEqualityComparer.Default.Equals(c.Parameters[0].Type, implementationType)) - is { } constructor0 => constructor0, - - // If value record and three constructors, decide for the constructor which isn't the copy-constructor or the parameterless constructor - { IsRecord: true, IsValueType: true, Constructors.Length: 3 } - when typeToChoseFrom.Constructors - .Where(c => c.Parameters.Length > 0) - .SingleOrDefault(c => - c.Parameters.Length != 1 || - !SymbolEqualityComparer.Default.Equals(c.Parameters[0].Type, implementationType)) - is { } constructor1 => constructor1, + is { } constructor => constructor, - // If value record and two constructors, decide for the parameterless constructor - { IsRecord: true, IsValueType: true, Constructors.Length: 2 } - when typeToChoseFrom.Constructors - .SingleOrDefault(c => c.Parameters.Length == 0) - is { } constructor2 => constructor2, - // If value type and two constructors, decide for the constructor which isn't the parameterless constructor - { IsRecord: false, IsValueType: true, Constructors.Length: 2 } when typeToChoseFrom.Constructors - .SingleOrDefault(c => c.Parameters.Length > 0) - is { } constructor3 => constructor3, - - // If value type and one constructor, decide for the parameterless constructor - { IsRecord: false, IsValueType: true, Constructors.Length: 1 } when typeToChoseFrom.Constructors - .SingleOrDefault() - is { } constructor4 => constructor4, + { IsRecord: true or false, IsReferenceType: false, IsValueType: true, Constructors.Length: 2 } + when typeToChoseFrom.Constructors.SingleOrDefault(c => c.Parameters.Length > 0) + is { } constructor => constructor, + + // If only one constructor, just choose it + { Constructors.Length: 1 } when typeToChoseFrom.Constructors.SingleOrDefault() + is { } constructor => constructor, _ => null }; diff --git a/Sample/Context.cs b/Sample/Context.cs index 6abe5573..c8a5b1f1 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -1,36 +1,8 @@ -using System.Collections.Generic; -using MrMeeseeks.DIE.Configuration; -using MrMeeseeks.DIE.Sample; +using MrMeeseeks.DIE.Configuration; -namespace MrMeeseeks.DIE.Test.Generics.Configuration.Composite; +namespace MrMeeseeks.DIE.Test.Struct.RecordNoExplicitConstructor; -internal interface IInterface -{ - IReadOnlyList Implementations { get; } -} +internal record struct Dependency; -internal class BaseA : IInterface -{ - public IReadOnlyList Implementations => new[] { this }; -} - -internal class BaseB : IInterface -{ - public IReadOnlyList Implementations => new[] { this }; -} - -internal class Composite : IInterface, IComposite -{ - public IReadOnlyList Implementations { get; } - - internal Composite( - IReadOnlyList implementations) => - Implementations = implementations; -} - -[GenericParameterChoice(typeof(Composite<>), "T0", typeof(int))] -[CreateFunction(typeof(IInterface), "Create")] -internal partial class Container -{ - -} \ No newline at end of file +[CreateFunction(typeof(Dependency), "Create")] +internal partial class Container { } \ No newline at end of file diff --git a/Sample/Program.cs b/Sample/Program.cs index a0b87a86..abc0fb82 100644 --- a/Sample/Program.cs +++ b/Sample/Program.cs @@ -1,4 +1,6 @@ -using MrMeeseeks.DIE.Test.Generics.Configuration.Composite; + + +using MrMeeseeks.DIE.Test.Struct.RecordNoExplicitConstructor; internal class Program { diff --git a/Test/Struct/NoExplicitConstructor.cs b/Test/Struct/NoExplicitConstructor.cs new file mode 100644 index 00000000..767af494 --- /dev/null +++ b/Test/Struct/NoExplicitConstructor.cs @@ -0,0 +1,20 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Struct.NoExplicitConstructor; + +internal struct Dependency {} + +[CreateFunction(typeof(Dependency), "Create")] +internal partial class Container { } + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var value = container.Create(); + Assert.IsType(value); + } +} \ No newline at end of file diff --git a/Test/Struct/OneExplicitConstructor.cs b/Test/Struct/OneExplicitConstructor.cs new file mode 100644 index 00000000..86f4a7ff --- /dev/null +++ b/Test/Struct/OneExplicitConstructor.cs @@ -0,0 +1,28 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Struct.OneExplicitConstructor; + +internal class Inner {} + +internal struct Dependency +{ + public Inner Inner { get; } + + internal Dependency(Inner inner) => Inner = inner; +} + +[CreateFunction(typeof(Dependency), "Create")] +internal partial class Container { } + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var value = container.Create(); + Assert.IsType(value); + Assert.NotNull(value.Inner); + } +} \ No newline at end of file diff --git a/Test/Struct/RecordNoExplicitConstructor.cs b/Test/Struct/RecordNoExplicitConstructor.cs new file mode 100644 index 00000000..f10a51f8 --- /dev/null +++ b/Test/Struct/RecordNoExplicitConstructor.cs @@ -0,0 +1,20 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Struct.RecordNoExplicitConstructor; + +internal record struct Dependency; + +[CreateFunction(typeof(Dependency), "Create")] +internal partial class Container { } + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var value = container.Create(); + Assert.IsType(value); + } +} \ No newline at end of file diff --git a/Test/Struct/RecordOneExplicitConstructor.cs b/Test/Struct/RecordOneExplicitConstructor.cs new file mode 100644 index 00000000..28842425 --- /dev/null +++ b/Test/Struct/RecordOneExplicitConstructor.cs @@ -0,0 +1,23 @@ +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Struct.RecordOneExplicitConstructor; + +internal class Inner {} + +internal record struct Dependency(Inner Inner); + +[CreateFunction(typeof(Dependency), "Create")] +internal partial class Container { } + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var value = container.Create(); + Assert.IsType(value); + Assert.NotNull(value.Inner); + } +} \ No newline at end of file From 8639d621fd2d35d58cd5d1b8ec97c6200b4ffd0a Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Wed, 25 May 2022 21:47:23 +0200 Subject: [PATCH 072/162] Stack-base cycle detection inside functions --- Main/Configuration/Attributes.cs | 5 ++ .../Configuration/CurrentlyConsideredTypes.cs | 48 +++++------ Main/Constants.cs | 2 - Main/ContainerDieExceptionGenerator.cs | 45 +++++++++++ Main/ContainerErrorGenerator.cs | 4 +- Main/DiagLogger.cs | 17 ++-- Main/DieException.cs | 22 +++++ Main/ExecuteImpl.cs | 23 +++++- ...ontainerCreateFunctionResolutionBuilder.cs | 3 +- .../FunctionResolutionBuilder.Dtos.cs | 52 ++++++++++++ .../Function/FunctionResolutionBuilder.cs | 81 ++++++++++++------- .../LocalFunctionResolutionBuilder.cs | 4 +- .../RangedFunctionResolutionBuilder.cs | 5 +- ...copeRootCreateFunctionResolutionBuilder.cs | 3 +- .../RangeResolutionBaseBuilder.cs | 2 +- Main/ResolutionBuilding/ResolutionDtos.cs | 75 ++++------------- ...ransientScopeInterfaceResolutionBuilder.cs | 2 +- Main/SourceGenerator.cs | 2 + Main/WellKnownTypes.cs | 12 +++ Sample/Container.cs | 4 +- Sample/Context.cs | 12 ++- Sample/Program.cs | 6 +- Test/AssemblyInfo.cs | 4 +- Test/CycleDetection/Implementation.cs | 26 ++++++ Test/CycleDetection/ImplementationProxied.cs | 32 ++++++++ Test/CycleDetection/NoCycleInParallel.cs | 36 +++++++++ Test/Func/Double.cs | 34 ++++++++ 27 files changed, 407 insertions(+), 154 deletions(-) create mode 100644 Main/ContainerDieExceptionGenerator.cs create mode 100644 Main/DieException.cs create mode 100644 Main/ResolutionBuilding/Function/FunctionResolutionBuilder.Dtos.cs create mode 100644 Test/CycleDetection/Implementation.cs create mode 100644 Test/CycleDetection/ImplementationProxied.cs create mode 100644 Test/CycleDetection/NoCycleInParallel.cs create mode 100644 Test/Func/Double.cs diff --git a/Main/Configuration/Attributes.cs b/Main/Configuration/Attributes.cs index 50368729..d041fe25 100644 --- a/Main/Configuration/Attributes.cs +++ b/Main/Configuration/Attributes.cs @@ -277,4 +277,9 @@ public class FilterImplementationCollectionChoiceAttribute : Attribute { public FilterImplementationCollectionChoiceAttribute(Type type) {} } + +[AttributeUsage(AttributeTargets.Assembly)] +public class ErrorDescriptionInsteadOfBuildFailureAttribute : Attribute +{ +} // ReSharper enable UnusedParameter.Local \ No newline at end of file diff --git a/Main/Configuration/CurrentlyConsideredTypes.cs b/Main/Configuration/CurrentlyConsideredTypes.cs index 099bc972..541e5946 100644 --- a/Main/Configuration/CurrentlyConsideredTypes.cs +++ b/Main/Configuration/CurrentlyConsideredTypes.cs @@ -1,4 +1,3 @@ -using Microsoft.CodeAnalysis.CSharp.Syntax; using MrMeeseeks.DIE.Extensions; namespace MrMeeseeks.DIE.Configuration; @@ -35,6 +34,7 @@ internal interface IImplementationTypeSetCache internal class ImplementationTypeSetCache : IImplementationTypeSetCache { + private readonly GeneratorExecutionContext _context; private readonly WellKnownTypes _wellKnownTypes; private readonly Lazy> _all; private IImmutableDictionary> _assemblyCache = @@ -46,32 +46,17 @@ internal ImplementationTypeSetCache( GeneratorExecutionContext context, WellKnownTypes wellKnownTypes) { + _context = context; _wellKnownTypes = wellKnownTypes; _currentAssemblyName = context.Compilation.AssemblyName ?? ""; _all = new Lazy>( - () => - { - IImmutableSet set = ImmutableHashSet.Empty; - set = set.Union(context.Compilation.SyntaxTrees - .Select(st => (st, context.Compilation.GetSemanticModel(st))) - .SelectMany(t => t.st - .GetRoot() - .DescendantNodesAndSelf() - .Where(e => e is ClassDeclarationSyntax or StructDeclarationSyntax or RecordDeclarationSyntax) - .Select(c => t.Item2.GetDeclaredSymbol(c)) - .Where(c => c is not null) - .OfType() - .Where(nts => !nts.IsAbstract))); - - set = set.Union(context - .Compilation - .SourceModule - .ReferencedAssemblySymbols - .SelectMany(ForAssembly) - .ToImmutableHashSet(SymbolEqualityComparer.Default)); - - return set; - }); + () => context + .Compilation + .SourceModule + .ReferencedAssemblySymbols + .Prepend(_context.Compilation.Assembly) + .SelectMany(ForAssembly) + .ToImmutableHashSet(SymbolEqualityComparer.Default)); } public IImmutableSet All => _all.Value; @@ -86,12 +71,15 @@ public IImmutableSet ForAssembly(IAssemblySymbol assembly) private IImmutableSet GetImplementationsFrom(IAssemblySymbol assemblySymbol) { - var internalsAreVisible = assemblySymbol.GetAttributes() - .Any(ad => - SymbolEqualityComparer.Default.Equals(ad.AttributeClass, _wellKnownTypes.InternalsVisibleToAttribute) - && ad.ConstructorArguments.Length == 1 - && ad.ConstructorArguments[0].Value is string assemblyName - && Equals(assemblyName, _currentAssemblyName)); + var internalsAreVisible = + SymbolEqualityComparer.Default.Equals(_context.Compilation.Assembly, assemblySymbol) + ||assemblySymbol + .GetAttributes() + .Any(ad => + SymbolEqualityComparer.Default.Equals(ad.AttributeClass, _wellKnownTypes.InternalsVisibleToAttribute) + && ad.ConstructorArguments.Length == 1 + && ad.ConstructorArguments[0].Value is string assemblyName + && Equals(assemblyName, _currentAssemblyName)); return GetAllNamespaces(assemblySymbol.GlobalNamespace) .SelectMany(ns => ns.GetTypeMembers()) diff --git a/Main/Constants.cs b/Main/Constants.cs index 1e0c504a..39bcba16 100644 --- a/Main/Constants.cs +++ b/Main/Constants.cs @@ -1,5 +1,3 @@ -using Microsoft.CodeAnalysis.CSharp.Syntax; - namespace MrMeeseeks.DIE; internal static class Constants diff --git a/Main/ContainerDieExceptionGenerator.cs b/Main/ContainerDieExceptionGenerator.cs new file mode 100644 index 00000000..630e73bd --- /dev/null +++ b/Main/ContainerDieExceptionGenerator.cs @@ -0,0 +1,45 @@ +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Text; + +namespace MrMeeseeks.DIE; + +internal interface IContainerDieExceptionGenerator +{ + void Generate(string namespaceName, string containerClassName, DieException exception); +} + +internal class ContainerDieExceptionGenerator : IContainerDieExceptionGenerator +{ + private readonly GeneratorExecutionContext _context; + private readonly WellKnownTypes _wellKnownTypes; + + internal ContainerDieExceptionGenerator( + GeneratorExecutionContext context, + WellKnownTypes wellKnownTypes) + { + _context = context; + _wellKnownTypes = wellKnownTypes; + } + + public void Generate(string namespaceName, string containerClassName, DieException exception) + { + var generatedContainer = new StringBuilder() + .AppendLine($"#nullable enable") + .AppendLine($"namespace {namespaceName}") + .AppendLine($"{{") + .AppendLine($"partial class {containerClassName}") + .AppendLine($"{{") + .AppendLine($"public {_wellKnownTypes.DieExceptionKind.FullName()} ExceptionKind_0_0 => {_wellKnownTypes.DieExceptionKind.FullName()}.{exception.Kind.ToString()};") + .AppendLine($"}}") + .AppendLine($"}}") + .AppendLine($"#nullable disable"); + + var containerSource = CSharpSyntaxTree + .ParseText(SourceText.From(generatedContainer.ToString(), Encoding.UTF8)) + .GetRoot() + .NormalizeWhitespace() + .SyntaxTree + .GetText(); + _context.AddSource($"{namespaceName}.{containerClassName}.g.cs", containerSource); + } +} \ No newline at end of file diff --git a/Main/ContainerErrorGenerator.cs b/Main/ContainerErrorGenerator.cs index 26642a14..dadb647a 100644 --- a/Main/ContainerErrorGenerator.cs +++ b/Main/ContainerErrorGenerator.cs @@ -19,6 +19,7 @@ internal ContainerErrorGenerator( public void Generate(IContainerInfo containerInfo, IReadOnlyList errorTreeItems) { var generatedContainer = new StringBuilder() + .AppendLine($"#nullable enable") .AppendLine($"namespace {containerInfo.Namespace}") .AppendLine($"{{") .AppendLine($"partial class {containerInfo.Name}") @@ -28,7 +29,8 @@ public void Generate(IContainerInfo containerInfo, IReadOnlyList .AppendLine($"throw new Exception(@\"{string.Join(Environment.NewLine, errorTreeItems.Select(eri => eri.Message))}\");") .AppendLine($"}}") .AppendLine($"}}") - .AppendLine($"}}"); + .AppendLine($"}}") + .AppendLine($"#nullable disable"); var containerSource = CSharpSyntaxTree .ParseText(SourceText.From(generatedContainer.ToString(), Encoding.UTF8)) diff --git a/Main/DiagLogger.cs b/Main/DiagLogger.cs index 5ea274a0..66b8ad8a 100644 --- a/Main/DiagLogger.cs +++ b/Main/DiagLogger.cs @@ -5,24 +5,25 @@ internal interface IDiagLogger void Log(string message); void Log(int id, string title, string message, string category, DiagnosticSeverity diagnosticSeverity); + + void Error(DieException exception); } internal class DiagLogger : IDiagLogger { private readonly GeneratorExecutionContext _context; - internal DiagLogger( - GeneratorExecutionContext context) - { - _context = context; - } + internal DiagLogger(GeneratorExecutionContext context) => _context = context; - public void Log(int id, string title, string message, string category, DiagnosticSeverity diagnosticSeverity) - { + public void Log(int id, string title, string message, string category, DiagnosticSeverity diagnosticSeverity) => _context.ReportDiagnostic(Diagnostic.Create( new DiagnosticDescriptor($"DIE{id.ToString().PadLeft(3, '0')}", title, message, category, diagnosticSeverity, true), Location.None)); - } public void Log(string message) => Log(0, "INFO", message, "INFO", DiagnosticSeverity.Warning); + + public void Error(DieException exception) => + _context.ReportDiagnostic(Diagnostic.Create( + new DiagnosticDescriptor($"DIE{69.ToString().PadLeft(3, '0')}", "Error", "Circular implementation references", "Error", DiagnosticSeverity.Error, true), + Location.None)); } \ No newline at end of file diff --git a/Main/DieException.cs b/Main/DieException.cs new file mode 100644 index 00000000..6b72013a --- /dev/null +++ b/Main/DieException.cs @@ -0,0 +1,22 @@ +namespace MrMeeseeks.DIE; + +public enum DieExceptionKind +{ + ImplementationCycle, + FunctionCycle +} + +public abstract class DieException : Exception +{ + public abstract DieExceptionKind Kind { get; } +} + +public class ImplementationCycleDieException : DieException +{ + public override DieExceptionKind Kind => DieExceptionKind.ImplementationCycle; +} + +public class FunctionCycleDieException : DieException +{ + public override DieExceptionKind Kind => DieExceptionKind.FunctionCycle; +} \ No newline at end of file diff --git a/Main/ExecuteImpl.cs b/Main/ExecuteImpl.cs index b21cca8d..0f7a4ec8 100644 --- a/Main/ExecuteImpl.cs +++ b/Main/ExecuteImpl.cs @@ -15,6 +15,7 @@ internal class ExecuteImpl : IExecute private readonly WellKnownTypes _wellKnownTypes; private readonly IContainerGenerator _containerGenerator; private readonly IContainerErrorGenerator _containerErrorGenerator; + private readonly IContainerDieExceptionGenerator _containerDieExceptionGenerator; private readonly Func _containerResolutionBuilderFactory; private readonly IResolutionTreeCreationErrorHarvester _resolutionTreeCreationErrorHarvester; private readonly Func _containerInfoFactory; @@ -25,6 +26,7 @@ internal ExecuteImpl( WellKnownTypes wellKnownTypes, IContainerGenerator containerGenerator, IContainerErrorGenerator containerErrorGenerator, + IContainerDieExceptionGenerator containerDieExceptionGenerator, Func containerResolutionBuilderFactory, IResolutionTreeCreationErrorHarvester resolutionTreeCreationErrorHarvester, Func containerInfoFactory, @@ -34,6 +36,7 @@ internal ExecuteImpl( _wellKnownTypes = wellKnownTypes; _containerGenerator = containerGenerator; _containerErrorGenerator = containerErrorGenerator; + _containerDieExceptionGenerator = containerDieExceptionGenerator; _containerResolutionBuilderFactory = containerResolutionBuilderFactory; _resolutionTreeCreationErrorHarvester = resolutionTreeCreationErrorHarvester; _containerInfoFactory = containerInfoFactory; @@ -43,6 +46,10 @@ internal ExecuteImpl( public void Execute() { _diagLogger.Log("Start Execute"); + + var errorDescriptionInsteadOfBuildFailure = _context.Compilation.Assembly.GetAttributes() + .Any(ad => _wellKnownTypes.ErrorDescriptionInsteadOfBuildFailureAttribute.Equals(ad.AttributeClass, SymbolEqualityComparer.Default)); + foreach (var syntaxTree in _context.Compilation.SyntaxTrees) { var semanticModel = _context.Compilation.GetSemanticModel(syntaxTree); @@ -55,11 +62,11 @@ public void Execute() .OfType() .Where(x => x.GetAttributes().Any(ad => _wellKnownTypes.CreateFunctionAttribute.Equals(ad.AttributeClass, SymbolEqualityComparer.Default))) .ToList(); - foreach (var namedTypeSymbol in containerClasses) + foreach (var containerSymbol in containerClasses) { try { - var containerInfo = _containerInfoFactory(namedTypeSymbol); + var containerInfo = _containerInfoFactory(containerSymbol); if (containerInfo.IsValid) { var containerResolutionBuilder = _containerResolutionBuilderFactory(containerInfo); @@ -69,7 +76,7 @@ public void Execute() { containerResolutionBuilder.DoWork(); } - + var containerResolution = containerResolutionBuilder.Build(); var errorTreeItems = _resolutionTreeCreationErrorHarvester.Harvest(containerResolution); if (errorTreeItems.Any()) @@ -79,6 +86,16 @@ public void Execute() } else throw new NotImplementedException("Handle non-valid container information"); } + catch (DieException dieException) + { + if (errorDescriptionInsteadOfBuildFailure) + _containerDieExceptionGenerator.Generate( + containerSymbol.ContainingNamespace.FullName(), + containerSymbol.Name, + dieException); + else + _diagLogger.Error(dieException); + } catch (Exception) { // ignore diff --git a/Main/ResolutionBuilding/Function/ContainerCreateFunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/ContainerCreateFunctionResolutionBuilder.cs index 5eee26d3..bf6d09af 100644 --- a/Main/ResolutionBuilding/Function/ContainerCreateFunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/ContainerCreateFunctionResolutionBuilder.cs @@ -30,7 +30,8 @@ public ContainerCreateFunctionResolutionBuilder( protected override Resolvable CreateResolvable() => SwitchType(new SwitchTypeParameter( _returnType, - Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>())).Item1; + Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>(), + ImmutableStack.Empty)).Item1; public override FunctionResolution Build() { diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.Dtos.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.Dtos.cs new file mode 100644 index 00000000..4f9e4b9e --- /dev/null +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.Dtos.cs @@ -0,0 +1,52 @@ +namespace MrMeeseeks.DIE.ResolutionBuilding.Function; + +internal abstract partial class FunctionResolutionBuilder +{ + private record SwitchInterfaceAfterScopeRootParameter( + INamedTypeSymbol InterfaceType, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters, + IImmutableStack ImplementationStack); + + private record CreateInterfaceParameter( + INamedTypeSymbol InterfaceType, + INamedTypeSymbol ImplementationType, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters, + IImmutableStack ImplementationStack); + + private record CreateInterfaceParameterAsComposition( + INamedTypeSymbol InterfaceType, + INamedTypeSymbol ImplementationType, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters, + IImmutableStack ImplementationStack, + CompositionInterfaceExtension Composition) + : CreateInterfaceParameter(InterfaceType, ImplementationType, CurrentParameters, ImplementationStack); + + private record SwitchClassParameter( + INamedTypeSymbol TypeSymbol, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters, + IImmutableStack ImplementationStack); + + private record SwitchImplementationParameterWithDecoration( + INamedTypeSymbol ImplementationType, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters, + IImmutableStack ImplementationStack, + DecorationInterfaceExtension Decoration) + : SwitchImplementationParameter(ImplementationType, CurrentParameters, ImplementationStack); + + private record SwitchImplementationParameterWithComposition( + INamedTypeSymbol ImplementationType, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters, + IImmutableStack ImplementationStack, + CompositionInterfaceExtension Composition) + : SwitchImplementationParameter(ImplementationType, CurrentParameters, ImplementationStack); + + private record SwitchTaskParameter((Resolvable, ITaskConsumableResolution?) InnerResolution) : Parameter; + + private record SwitchValueTaskParameter((Resolvable, ITaskConsumableResolution?) InnerResolution) : Parameter; + + private enum TaskType + { + Task, + ValueTask + } +} \ No newline at end of file diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs index 9fd0dbe2..a6e0a6ca 100644 --- a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs @@ -51,7 +51,7 @@ MultiSynchronicityFunctionCallResolution BuildFunctionCall( MethodGroupResolution BuildMethodGroup(); } -internal abstract class FunctionResolutionBuilder : IFunctionResolutionBuilder +internal abstract partial class FunctionResolutionBuilder : IFunctionResolutionBuilder { private readonly IRangeResolutionBaseBuilder _rangeResolutionBaseBuilder; private readonly IFunctionResolutionSynchronicityDecisionMaker _synchronicityDecisionMaker; @@ -107,7 +107,7 @@ internal FunctionResolutionBuilder( protected (Resolvable, ITaskConsumableResolution?) SwitchType(SwitchTypeParameter parameter) { - var (type, currentFuncParameters) = parameter; + var (type, currentFuncParameters, implementationStack) = parameter; if (currentFuncParameters.FirstOrDefault(t => SymbolEqualityComparer.Default.Equals(t.Type.OriginalDefinition, type.OriginalDefinition)) is { Type: not null, Resolution: not null } funcParameter) return (funcParameter.Resolution, null); @@ -135,17 +135,19 @@ internal FunctionResolutionBuilder( factory.Name, factory .Parameters - .Select(p => (p.Name, SwitchType(new SwitchTypeParameter(p.Type, currentFuncParameters)).Item1)) + .Select(p => (p.Name, SwitchType(new SwitchTypeParameter(p.Type, currentFuncParameters, implementationStack)).Item1)) .ToList()), null); if (type.OriginalDefinition.Equals(_wellKnownTypes.Task1, SymbolEqualityComparer.Default) && type is INamedTypeSymbol task) - return SwitchTask(new SwitchTaskParameter(SwitchType(new SwitchTypeParameter(task.TypeArguments[0], currentFuncParameters)))); + return SwitchTask(new SwitchTaskParameter( + SwitchType(new SwitchTypeParameter(task.TypeArguments[0], currentFuncParameters, implementationStack)))); if (type.OriginalDefinition.Equals(_wellKnownTypes.ValueTask1, SymbolEqualityComparer.Default) && type is INamedTypeSymbol valueTask) - return SwitchValueTask(new SwitchValueTaskParameter(SwitchType(new SwitchTypeParameter(valueTask.TypeArguments[0], currentFuncParameters)))); + return SwitchValueTask(new SwitchValueTaskParameter( + SwitchType(new SwitchTypeParameter(valueTask.TypeArguments[0], currentFuncParameters, implementationStack)))); if (type.FullName().StartsWith("global::System.ValueTuple<") && type is INamedTypeSymbol valueTupleType) { @@ -155,7 +157,7 @@ internal FunctionResolutionBuilder( DisposalType.None, valueTupleType .TypeArguments - .Select((t, i) => ($"item{(i + 1)}", SwitchType(new SwitchTypeParameter(t, currentFuncParameters)).Item1)) + .Select((t, i) => ($"item{(i + 1)}", SwitchType(new SwitchTypeParameter(t, currentFuncParameters, implementationStack)).Item1)) .ToList(), Array.Empty<(string Name, Resolvable Dependency)>(), null); @@ -170,7 +172,7 @@ internal FunctionResolutionBuilder( RootReferenceGenerator.Generate("syntaxValueTuple"), syntaxValueTupleType.FullName(), itemTypes - .Select(t => SwitchType(new SwitchTypeParameter(t, currentFuncParameters)).Item1) + .Select(t => SwitchType(new SwitchTypeParameter(t, currentFuncParameters, implementationStack)).Item1) .ToList()), null); @@ -311,8 +313,8 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup .Select(i => { var itemResolution = itemTypeIsInterface - ? SwitchInterfaceWithoutComposition(new CreateInterfaceParameter(unwrappedItemType, i, currentFuncParameters)) - : SwitchClass(new SwitchClassParameter(i, currentFuncParameters)); + ? SwitchInterfaceWithoutComposition(new CreateInterfaceParameter(unwrappedItemType, i, currentFuncParameters, implementationStack)) + : SwitchClass(new SwitchClassParameter(i, currentFuncParameters, implementationStack)); return (taskType switch { TaskType.Task => SwitchTask(new SwitchTaskParameter(itemResolution)), @@ -334,10 +336,10 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup if (type is { TypeKind: TypeKind.Interface} or { TypeKind: TypeKind.Class, IsAbstract: true } && type is INamedTypeSymbol interfaceOrAbstractType) - return SwitchInterface(new SwitchInterfaceAfterScopeRootParameter(interfaceOrAbstractType, currentFuncParameters)); + return SwitchInterface(new SwitchInterfaceAfterScopeRootParameter(interfaceOrAbstractType, currentFuncParameters, implementationStack)); if (type is INamedTypeSymbol { TypeKind: TypeKind.Class or TypeKind.Struct} classOrStructType) - return SwitchClass(new SwitchClassParameter(classOrStructType, currentFuncParameters)); + return SwitchClass(new SwitchClassParameter(classOrStructType, currentFuncParameters, implementationStack)); return ( new ErrorTreeItem($"[{type.FullName()}] Couldn't process in resolution tree creation."), @@ -449,7 +451,7 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup private (Resolvable, ITaskConsumableResolution?) SwitchInterface( SwitchInterfaceAfterScopeRootParameter parameter) { - var (interfaceType, currentParameters) = parameter; + var (interfaceType, currentParameters, implementationStack) = parameter; if (_checkTypeProperties.ShouldBeComposite(interfaceType)) { var implementations = _checkTypeProperties.MapToImplementations(interfaceType); @@ -458,7 +460,8 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup var interfaceResolutions = implementations.Select(i => SwitchInterfaceWithoutComposition(new CreateInterfaceParameter( interfaceType, i, - currentParameters))).ToList(); + currentParameters, + implementationStack))).ToList(); var composition = new CompositionInterfaceExtension( interfaceType, implementations.ToList(), @@ -467,7 +470,8 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup return SwitchInterfaceWithoutComposition(new CreateInterfaceParameterAsComposition( interfaceType, compositeImplementationType, - currentParameters, + currentParameters, + implementationStack, composition)); } if (_checkTypeProperties.MapToSingleFittingImplementation(interfaceType) is not { } implementationType) @@ -480,12 +484,13 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup return SwitchInterfaceWithoutComposition(new CreateInterfaceParameter( interfaceType, implementationType, - currentParameters)); + currentParameters, + implementationStack)); } private (InterfaceResolution, ITaskConsumableResolution?) SwitchInterfaceWithoutComposition(CreateInterfaceParameter parameter) { - var (interfaceType, implementationType, currentParameters) = parameter; + var (interfaceType, implementationType, currentParameters, implementationStack) = parameter; var shouldBeDecorated = _checkTypeProperties.ShouldBeDecorated(interfaceType); var (nextResolvable, _) = parameter switch @@ -493,10 +498,12 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup CreateInterfaceParameterAsComposition asComposition => SwitchImplementation(new SwitchImplementationParameterWithComposition( asComposition.Composition.CompositeType, currentParameters, + implementationStack, asComposition.Composition)), _ => SwitchClass(new SwitchClassParameter( implementationType, - currentParameters)) + currentParameters, + implementationStack)) }; var currentInterfaceResolution = new InterfaceResolution( @@ -518,6 +525,7 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup var decoratorResolution = SwitchImplementation(new SwitchImplementationParameterWithDecoration( decorator, currentParameters, + implementationStack, decoration)).Item1; currentInterfaceResolution = new InterfaceResolution( RootReferenceGenerator.Generate(interfaceType), @@ -531,7 +539,7 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup private (Resolvable, ITaskConsumableResolution?) SwitchClass(SwitchClassParameter parameter) { - var (implementationType, currentParameters) = parameter; + var (implementationType, currentParameters, implementationStack) = parameter; if (_checkTypeProperties.MapToSingleFittingImplementation(implementationType) is not { } chosenImplementationType) { @@ -542,7 +550,8 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup var nextParameter = new SwitchImplementationParameter( chosenImplementationType, - currentParameters); + currentParameters, + implementationStack); var ret = _checkTypeProperties.ShouldBeScopeRoot(chosenImplementationType) switch { @@ -574,7 +583,7 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup protected (Resolvable, ITaskConsumableResolution?) SwitchImplementation(SwitchImplementationParameter parameter) { - var (implementationType, currentParameters) = parameter; + var (implementationType, currentParameters, implementationStack) = parameter; var scopeLevel = parameter switch { SwitchImplementationParameterWithComposition withComposition => @@ -589,12 +598,14 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup SwitchImplementationParameterWithComposition withComposition => new ForConstructorParameterWithComposition( withComposition.Composition.CompositeType, currentParameters, + implementationStack, withComposition.Composition), SwitchImplementationParameterWithDecoration withDecoration => new ForConstructorParameterWithDecoration( withDecoration.Decoration.DecoratorType, currentParameters, + implementationStack, withDecoration.Decoration), - _ => new ForConstructorParameter(implementationType, currentParameters) + _ => new ForConstructorParameter(implementationType, currentParameters, implementationStack) }; var ret = scopeLevel switch @@ -622,21 +633,32 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup protected (Resolvable, ITaskConsumableResolution?) CreateConstructorResolution(ForConstructorParameter parameter) { - var (implementationType, currentParameters) = parameter; - + var (implementationType, currentParameters, implementationStack) = parameter; + if (_checkTypeProperties.GetConstructorChoiceFor(implementationType) is not { } constructor) { - return implementationType.NullableAnnotation == NullableAnnotation.Annotated - ? (new NullResolution(RootReferenceGenerator.Generate(implementationType), implementationType.FullName()), null) // todo warning + return implementationType.NullableAnnotation == NullableAnnotation.Annotated + ? (new NullResolution(RootReferenceGenerator.Generate(implementationType), + implementationType.FullName()), null) // todo warning : (new ErrorTreeItem(implementationType.Constructors.Length switch { - 0 => $"[{implementationType.FullName()}] Class.Constructor: No constructor found for implementation {implementationType.FullName()}", - > 1 => $"[{implementationType.FullName()}] Class.Constructor: More than one constructor found for implementation {implementationType.FullName()}", - _ => $"[{implementationType.FullName()}] Class.Constructor: {implementationType.Constructors[0].Name} is not a method symbol" + 0 => + $"[{implementationType.FullName()}] Class.Constructor: No constructor found for implementation {implementationType.FullName()}", + > 1 => + $"[{implementationType.FullName()}] Class.Constructor: More than one constructor found for implementation {implementationType.FullName()}", + _ => + $"[{implementationType.FullName()}] Class.Constructor: {implementationType.Constructors[0].Name} is not a method symbol" }), null); } + var implementationCycle = implementationStack.Contains(implementationType, SymbolEqualityComparer.Default); + + if (implementationCycle) + throw new ImplementationCycleDieException(); + + implementationStack = implementationStack.Push(implementationType); + var checkForDecoration = false; DecorationInterfaceExtension? decoration = null; @@ -797,7 +819,8 @@ false when initializationMethod.ReturnType.Equals(_wellKnownTypes.ValueTask, Sym parameterName, SwitchType(new SwitchTypeParameter( parameterType, - currParameter)).Item1); + currParameter, + implementationStack)).Item1); } } diff --git a/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs index 71655f8a..7b4edd2f 100644 --- a/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs @@ -6,7 +6,6 @@ internal interface ILocalFunctionResolutionBuilder : IFunctionResolutionBuilder internal class LocalFunctionResolutionBuilder : FunctionResolutionBuilder, ILocalFunctionResolutionBuilder { - private readonly IRangeResolutionBaseBuilder _rangeResolutionBaseBuilder; private readonly INamedTypeSymbol _returnType; private readonly IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> _parameters; @@ -24,7 +23,6 @@ public LocalFunctionResolutionBuilder( Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) : base(rangeResolutionBaseBuilder, returnType, parameters, synchronicityDecisionMaker, wellKnownTypes, referenceGeneratorFactory, localFunctionResolutionBuilderFactory) { - _rangeResolutionBaseBuilder = rangeResolutionBaseBuilder; _returnType = returnType; _parameters = parameters; @@ -33,7 +31,7 @@ public LocalFunctionResolutionBuilder( protected override string Name { get; } - protected override Resolvable CreateResolvable() => SwitchType(new SwitchTypeParameter(_returnType, _parameters)).Item1; + protected override Resolvable CreateResolvable() => SwitchType(new SwitchTypeParameter(_returnType, _parameters, ImmutableStack.Empty)).Item1; public override FunctionResolution Build() { diff --git a/Main/ResolutionBuilding/Function/RangedFunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/RangedFunctionResolutionBuilder.cs index 978e1945..38765ab3 100644 --- a/Main/ResolutionBuilding/Function/RangedFunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/RangedFunctionResolutionBuilder.cs @@ -6,7 +6,6 @@ internal interface IRangedFunctionResolutionBuilder : IFunctionResolutionBuilder internal class RangedFunctionResolutionBuilder : FunctionResolutionBuilder, IRangedFunctionResolutionBuilder { - private readonly IRangeResolutionBaseBuilder _rangeResolutionBaseBuilder; private readonly ForConstructorParameter _forConstructorParameter; public RangedFunctionResolutionBuilder( @@ -23,7 +22,6 @@ public RangedFunctionResolutionBuilder( Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) : base(rangeResolutionBaseBuilder, forConstructorParameter.ImplementationType, forConstructorParameter.CurrentFuncParameters, synchronicityDecisionMaker, wellKnownTypes, referenceGeneratorFactory, localFunctionResolutionBuilderFactory) { - _rangeResolutionBaseBuilder = rangeResolutionBaseBuilder; _forConstructorParameter = forConstructorParameter; Name = reference; @@ -31,7 +29,8 @@ public RangedFunctionResolutionBuilder( protected override string Name { get; } - protected override Resolvable CreateResolvable() => CreateConstructorResolution(_forConstructorParameter).Item1; + protected override Resolvable CreateResolvable() => CreateConstructorResolution( + _forConstructorParameter with { ImplementationStack = ImmutableStack.Empty }).Item1; public override FunctionResolution Build() { diff --git a/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs index c61bb184..eeaa6e70 100644 --- a/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs @@ -28,7 +28,8 @@ public ScopeRootCreateFunctionResolutionBuilder( protected override string Name { get; } - protected override Resolvable CreateResolvable() => SwitchImplementation(_parameter).Item1; + protected override Resolvable CreateResolvable() => SwitchImplementation( + _parameter with { ImplementationStack = ImmutableStack.Empty }).Item1; public override FunctionResolution Build() { diff --git a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs index b45dcca5..f2f59c34 100644 --- a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs +++ b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs @@ -99,7 +99,7 @@ protected MultiSynchronicityFunctionCallResolution CreateRangedInstanceReference string owningObjectReference, Lazy synchronicityDecisionMaker) { - var (implementationType, currentParameters) = parameter; + var (implementationType, currentParameters, _) = parameter; InterfaceExtension? interfaceExtension = parameter switch { ForConstructorParameterWithComposition withComposition => withComposition.Composition, diff --git a/Main/ResolutionBuilding/ResolutionDtos.cs b/Main/ResolutionBuilding/ResolutionDtos.cs index bb8e894c..1b1ee718 100644 --- a/Main/ResolutionBuilding/ResolutionDtos.cs +++ b/Main/ResolutionBuilding/ResolutionDtos.cs @@ -26,6 +26,7 @@ internal record DecorationInterfaceExtension( INamedTypeSymbol DecoratorType, InterfaceResolution CurrentInterfaceResolution) : InterfaceExtension(InterfaceType); + internal record CompositionInterfaceExtension( INamedTypeSymbol InterfaceType, IReadOnlyList ImplementationTypes, @@ -37,94 +38,46 @@ internal record Parameter; internal record SwitchTypeParameter( ITypeSymbol Type, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentFuncParameters) - : Parameter; - -internal record SwitchInterfaceParameter( - ITypeSymbol Type, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentFuncParameters) + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentFuncParameters, + IImmutableStack ImplementationStack) : Parameter; - -internal record SwitchInterfaceAfterScopeRootParameter( - INamedTypeSymbol InterfaceType, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters); - - -internal record SwitchInterfaceForSpecificImplementationParameter( - INamedTypeSymbol InterfaceType, - INamedTypeSymbol ImplementationType, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters); - -internal record CreateInterfaceParameter( - INamedTypeSymbol InterfaceType, - INamedTypeSymbol ImplementationType, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters); - -internal record CreateInterfaceParameterAsComposition( - INamedTypeSymbol InterfaceType, - INamedTypeSymbol ImplementationType, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters, - CompositionInterfaceExtension Composition) - : CreateInterfaceParameter(InterfaceType, ImplementationType, CurrentParameters); - -internal record SwitchClassParameter( - INamedTypeSymbol TypeSymbol, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters); internal record SwitchImplementationParameter( INamedTypeSymbol ImplementationType, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters) + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters, + IImmutableStack ImplementationStack) { public INamedTypeSymbol ReturnType => ImplementationType; } - -internal record SwitchImplementationParameterWithDecoration( - INamedTypeSymbol ImplementationType, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters, - DecorationInterfaceExtension Decoration) - : SwitchImplementationParameter(ImplementationType, CurrentParameters); - -internal record SwitchImplementationParameterWithComposition( - INamedTypeSymbol ImplementationType, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters, - CompositionInterfaceExtension Composition) - : SwitchImplementationParameter(ImplementationType, CurrentParameters); internal record ForConstructorParameter( INamedTypeSymbol ImplementationType, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentFuncParameters); + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentFuncParameters, + IImmutableStack ImplementationStack); internal abstract record ForConstructorParameterWithInterfaceExtension( INamedTypeSymbol ImplementationType, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentFuncParameters, + IImmutableStack ImplementationStack, InterfaceExtension InterfaceExtension) - : ForConstructorParameter(ImplementationType, CurrentFuncParameters); + : ForConstructorParameter(ImplementationType, CurrentFuncParameters, ImplementationStack); internal record ForConstructorParameterWithDecoration( INamedTypeSymbol ImplementationType, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentFuncParameters, + IImmutableStack ImplementationStack, DecorationInterfaceExtension Decoration) - : ForConstructorParameterWithInterfaceExtension(ImplementationType, CurrentFuncParameters, Decoration); + : ForConstructorParameterWithInterfaceExtension(ImplementationType, CurrentFuncParameters, ImplementationStack, Decoration); internal record ForConstructorParameterWithComposition( INamedTypeSymbol ImplementationType, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentFuncParameters, + IImmutableStack ImplementationStack, CompositionInterfaceExtension Composition) - : ForConstructorParameterWithInterfaceExtension(ImplementationType, CurrentFuncParameters, Composition); + : ForConstructorParameterWithInterfaceExtension(ImplementationType, CurrentFuncParameters, ImplementationStack, Composition); -//(RangedInstanceFunction, IReadOnlyList<(ITypeSymbol, ParameterResolution)>, INamedTypeSymbol, InterfaceExtension?) internal record RangedInstanceResolutionsQueueItem( ForConstructorParameter Parameter, string Label, string Reference, - string Key); - -internal record SwitchTaskParameter((Resolvable, ITaskConsumableResolution?) InnerResolution) : Parameter; - -internal record SwitchValueTaskParameter((Resolvable, ITaskConsumableResolution?) InnerResolution) : Parameter; - -internal enum TaskType -{ - Task, - ValueTask -} \ No newline at end of file + string Key); \ No newline at end of file diff --git a/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs b/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs index f37fda73..3955821a 100644 --- a/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs +++ b/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs @@ -82,7 +82,7 @@ private MultiSynchronicityFunctionCallResolution CreateRangedInstanceReferenceRe string label, string owningObjectReference) { - var (implementationType, currentParameters) = parameter; + var (implementationType, currentParameters, _) = parameter; InterfaceExtension? interfaceExtension = parameter switch { ForConstructorParameterWithComposition withComposition => withComposition.Composition, diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index 215717db..4fdaec79 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -23,6 +23,7 @@ public void Execute(GeneratorExecutionContext context) var containerGenerator = new ContainerGenerator(context, diagLogger, ContainerCodeBuilderFactory, TransientScopeCodeBuilderFactory, ScopeCodeBuilderFactory); var referenceGeneratorFactory = new ReferenceGeneratorFactory(ReferenceGeneratorFactory); var containerErrorGenerator = new ContainerErrorGenerator(context); + var containerDieExceptionGenerator = new ContainerDieExceptionGenerator(context, wellKnownTypes); var resolutionTreeCreationErrorHarvester = new ResolutionTreeCreationErrorHarvester(); var implementationTypeSetCache = new ImplementationTypeSetCache(context, wellKnownTypes); new ExecuteImpl( @@ -30,6 +31,7 @@ public void Execute(GeneratorExecutionContext context) wellKnownTypes, containerGenerator, containerErrorGenerator, + containerDieExceptionGenerator, ResolutionTreeFactory, resolutionTreeCreationErrorHarvester, ContainerInfoFactory, diff --git a/Main/WellKnownTypes.cs b/Main/WellKnownTypes.cs index 8a6af008..8ddca9a8 100644 --- a/Main/WellKnownTypes.cs +++ b/Main/WellKnownTypes.cs @@ -48,6 +48,8 @@ internal record WellKnownTypes( INamedTypeSymbol FilterImplementationCollectionChoiceAttribute, INamedTypeSymbol CustomScopeForRootTypesAttribute, INamedTypeSymbol CreateFunctionAttribute, + INamedTypeSymbol ErrorDescriptionInsteadOfBuildFailureAttribute, + INamedTypeSymbol DieExceptionKind, INamedTypeSymbol Disposable, INamedTypeSymbol AsyncDisposable, INamedTypeSymbol Lazy1, @@ -231,6 +233,12 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK var createFunctionAttribute = compilation .GetTypeByMetadataName(typeof(CreateFunctionAttribute).FullName ?? ""); + + var errorDescriptionInsteadOfBuildFailureAttribute = compilation + .GetTypeByMetadataName(typeof(ErrorDescriptionInsteadOfBuildFailureAttribute).FullName ?? ""); + + var dieExceptionKind = compilation + .GetTypeByMetadataName(typeof(DieExceptionKind).FullName ?? ""); if (implementationAggregationAttribute is not null && transientAggregationAttribute is not null @@ -276,6 +284,8 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK && filterImplementationCollectionChoiceAttribute is not null && customScopeForRootTypesAttribute is not null && createFunctionAttribute is not null + && errorDescriptionInsteadOfBuildFailureAttribute is not null + && dieExceptionKind is not null && iDisposable is not null && iAsyncDisposable is not null && lazy1 is not null @@ -342,6 +352,8 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK FilterImplementationCollectionChoiceAttribute: filterImplementationCollectionChoiceAttribute, CustomScopeForRootTypesAttribute: customScopeForRootTypesAttribute, CreateFunctionAttribute: createFunctionAttribute, + ErrorDescriptionInsteadOfBuildFailureAttribute: errorDescriptionInsteadOfBuildFailureAttribute, + DieExceptionKind: dieExceptionKind, Disposable: iDisposable, AsyncDisposable: iAsyncDisposable, Lazy1: lazy1, diff --git a/Sample/Container.cs b/Sample/Container.cs index a8741dbe..e6d9f8d0 100644 --- a/Sample/Container.cs +++ b/Sample/Container.cs @@ -15,4 +15,6 @@ [assembly:TypeInitializer(typeof(ITaskTypeInitializer), nameof(ITaskTypeInitializer.InitializeAsync))] [assembly:TypeInitializer(typeof(IValueTaskTypeInitializer), nameof(IValueTaskTypeInitializer.InitializeAsync))] -[assembly:AllImplementationsAggregation] \ No newline at end of file +[assembly:AllImplementationsAggregation] + +[assembly:ErrorDescriptionInsteadOfBuildFailure] \ No newline at end of file diff --git a/Sample/Context.cs b/Sample/Context.cs index c8a5b1f1..853e9e90 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -1,8 +1,14 @@ using MrMeeseeks.DIE.Configuration; -namespace MrMeeseeks.DIE.Test.Struct.RecordNoExplicitConstructor; +namespace MrMeeseeks.DIE.Test.CycleDetection.Implementation; -internal record struct Dependency; +internal class Dependency +{ + internal Dependency(Dependency inner) {} +} [CreateFunction(typeof(Dependency), "Create")] -internal partial class Container { } \ No newline at end of file +internal partial class Container +{ + +} \ No newline at end of file diff --git a/Sample/Program.cs b/Sample/Program.cs index abc0fb82..09575040 100644 --- a/Sample/Program.cs +++ b/Sample/Program.cs @@ -1,13 +1,9 @@ - - -using MrMeeseeks.DIE.Test.Struct.RecordNoExplicitConstructor; +using MrMeeseeks.DIE.Test.CycleDetection.Implementation; internal class Program { private static void Main() { var container = new Container(); - var dependency = container.Create(); - } } \ No newline at end of file diff --git a/Test/AssemblyInfo.cs b/Test/AssemblyInfo.cs index d8604e18..2f0a6533 100644 --- a/Test/AssemblyInfo.cs +++ b/Test/AssemblyInfo.cs @@ -15,4 +15,6 @@ [assembly:TypeInitializer(typeof(ITaskTypeInitializer), nameof(ITaskTypeInitializer.InitializeAsync))] [assembly:TypeInitializer(typeof(IValueTaskTypeInitializer), nameof(IValueTaskTypeInitializer.InitializeAsync))] -[assembly:AllImplementationsAggregation] \ No newline at end of file +[assembly:AllImplementationsAggregation] + +[assembly:ErrorDescriptionInsteadOfBuildFailure] \ No newline at end of file diff --git a/Test/CycleDetection/Implementation.cs b/Test/CycleDetection/Implementation.cs new file mode 100644 index 00000000..78ea7d46 --- /dev/null +++ b/Test/CycleDetection/Implementation.cs @@ -0,0 +1,26 @@ +using MrMeeseeks.DIE; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CycleDetection.Implementation; + +internal class Dependency +{ + internal Dependency(Dependency inner) {} +} + +[CreateFunction(typeof(Dependency), "Create")] +internal partial class Container +{ + +} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + Assert.Equal(DieExceptionKind.ImplementationCycle , container.ExceptionKind_0_0); + } +} \ No newline at end of file diff --git a/Test/CycleDetection/ImplementationProxied.cs b/Test/CycleDetection/ImplementationProxied.cs new file mode 100644 index 00000000..4a6e69f3 --- /dev/null +++ b/Test/CycleDetection/ImplementationProxied.cs @@ -0,0 +1,32 @@ +using MrMeeseeks.DIE; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CycleDetection.ImplementationProxied; + + +internal class Proxy +{ + internal Proxy(Dependency inner) {} +} + +internal class Dependency +{ + internal Dependency(Proxy inner) {} +} + +[CreateFunction(typeof(Dependency), "Create")] +internal partial class Container +{ + +} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + Assert.Equal(DieExceptionKind.ImplementationCycle , container.ExceptionKind_0_0); + } +} \ No newline at end of file diff --git a/Test/CycleDetection/NoCycleInParallel.cs b/Test/CycleDetection/NoCycleInParallel.cs new file mode 100644 index 00000000..4d9be513 --- /dev/null +++ b/Test/CycleDetection/NoCycleInParallel.cs @@ -0,0 +1,36 @@ +using MrMeeseeks.DIE; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CycleDetection.NoCycleInParallel; + +internal class Dependency +{ +} + +internal class Parent +{ + internal Parent( + Dependency dep0, + Dependency dep1) + { + + } +} + +[CreateFunction(typeof(Parent), "Create")] +internal partial class Container +{ + +} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var parent = container.Create(); + Assert.IsType(parent); + } +} \ No newline at end of file diff --git a/Test/Func/Double.cs b/Test/Func/Double.cs new file mode 100644 index 00000000..74dfc86f --- /dev/null +++ b/Test/Func/Double.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using MrMeeseeks.DIE.Configuration; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Func.Double; + +internal class Dependency{} + +internal class Parent +{ + internal Parent( + Func fac0, + Func fac1) + { + + } +} + +[CreateFunction(typeof(Parent), "Create")] +internal partial class Container +{ +} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var parent = container.Create(); + Assert.IsType(parent); + } +} From cb712adeae9480eef5b4ee2991768f8e31d8cde4 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Thu, 26 May 2022 10:05:20 +0200 Subject: [PATCH 073/162] Refactored Attributes --- Main/Configuration/Attributes.cs | 285 ------------------ Main/Configuration/Attributes/Aggregation.cs | 251 +++++++++++++++ Main/Configuration/Attributes/Choice.cs | 93 ++++++ .../Configuration/Attributes/Miscellaneous.cs | 39 +++ .../Configuration/CurrentlyConsideredTypes.cs | 32 +- Main/Configuration/TypesFromAttributes.cs | 187 ++++++------ Main/ContainerDieExceptionGenerator.cs | 8 +- Main/ContainerInfo.cs | 6 +- Main/ExecuteImpl.cs | 10 +- Main/ResolutionBuilding/ScopeManager.cs | 6 +- Main/SourceGenerator.cs | 29 +- Main/WellKnownTypes.cs | 283 +---------------- Main/WellKnownTypesAggregation.cs | 182 +++++++++++ Main/WellKnownTypesChoice.cs | 103 +++++++ Main/WellKnownTypesMiscellaneous.cs | 55 ++++ Sample/Container.cs | 22 +- Sample/Context.cs | 2 +- Test/AssemblyInfo.cs | 22 +- .../Async/Awaited/AsyncScopeRootCallAsTask.cs | 2 +- .../Awaited/AsyncScopeRootCallAsValueTask.cs | 2 +- .../Awaited/AsyncScopeRootCallAwaited.cs | 2 +- .../ContainerInstanceFunctionAsTask.cs | 2 +- .../ContainerInstanceFunctionAsValueTask.cs | 2 +- .../Awaited/ScopeInstanceFunctionAsTask.cs | 2 +- .../ScopeInstanceFunctionAsValueTask.cs | 2 +- Test/Async/Awaited/TaskTypeInitializerTask.cs | 2 +- .../Awaited/TaskTypeInitializerValueTask.cs | 2 +- .../TransientScopeInstanceFunctionAsTask.cs | 2 +- ...ansientScopeInstanceFunctionAsValueTask.cs | 2 +- ...InstanceFunction_DifferentSynchronicity.cs | 2 +- .../ContainerInstanceFunctionAsTask.cs | 2 +- .../ContainerInstanceFunctionAsValueTask.cs | 2 +- Test/Async/Wrapped/DecorationChaining.cs | 2 +- Test/Async/Wrapped/Func.cs | 2 +- Test/Async/Wrapped/Lazy.cs | 2 +- .../Wrapped/ScopeInstanceFunctionAsTask.cs | 2 +- .../ScopeInstanceFunctionAsValueTask.cs | 2 +- Test/Async/Wrapped/SyncToTask.cs | 2 +- Test/Async/Wrapped/SyncToValueTask.cs | 2 +- Test/Async/Wrapped/TaskCollection.cs | 2 +- Test/Async/Wrapped/TaskComposition.cs | 2 +- Test/Async/Wrapped/TaskToTask.cs | 2 +- Test/Async/Wrapped/TaskToValueTask.cs | 2 +- .../TransientScopeInstanceFunctionAsTask.cs | 2 +- ...ceFunctionAsTask_DifferentSynchronicity.cs | 2 +- ...ansientScopeInstanceFunctionAsValueTask.cs | 2 +- ...ctionAsValueTask_DifferentSynchronicity.cs | 2 +- Test/Async/Wrapped/ValueTaskCollection.cs | 2 +- Test/Async/Wrapped/ValueTaskComposition.cs | 2 +- Test/Async/Wrapped/ValueTaskToTask.cs | 2 +- Test/Async/Wrapped/ValueTaskToValueTask.cs | 2 +- Test/Composite/Container.cs | 2 +- Test/Composite/Decorated.cs | 2 +- Test/Composite/MixedScoping.cs | 2 +- Test/Composite/Normal.cs | 2 +- Test/Composite/ScopeRoot.cs | 2 +- Test/ConstructorChoice/Parameterless.cs | 2 +- Test/ConstructorChoice/WithParameter.cs | 2 +- Test/CustomEmbedding/FactoryInContainercs.cs | 2 +- Test/CustomEmbedding/FactoryInScope.cs | 2 +- .../FactoryInTransientScope.cs | 2 +- .../FactoryWithParameterInContainercs.cs | 2 +- .../FactoryWithParameterInScope.cs | 2 +- .../FactoryWithParameterInTransientScope.cs | 2 +- Test/CustomEmbedding/FieldInContainercs.cs | 2 +- Test/CustomEmbedding/FieldInScope.cs | 2 +- Test/CustomEmbedding/FieldInTransientScope.cs | 2 +- Test/CustomEmbedding/PropertyInContainercs.cs | 2 +- Test/CustomEmbedding/PropertyInScope.cs | 2 +- .../PropertyInTransientScope.cs | 2 +- Test/CycleDetection/Implementation.cs | 2 +- Test/CycleDetection/ImplementationProxied.cs | 2 +- Test/CycleDetection/NoCycleInParallel.cs | 2 +- Test/Decorator/ContainerInstance.cs | 2 +- Test/Decorator/List.cs | 2 +- Test/Decorator/Multi.cs | 2 +- Test/Decorator/Normal.cs | 2 +- .../ScopeDecoratorForContainerDependency.cs | 2 +- ...opeDecoratorForTransientScopeDependency.cs | 2 +- Test/Decorator/SequenceEdgeCase.cs | 2 +- Test/Disposal/Async/InContainer.cs | 2 +- Test/Disposal/Async/InScope.cs | 2 +- .../Disposal/Async/InScopeInTransientScope.cs | 2 +- Test/Disposal/Async/InTransientScope.cs | 2 +- .../Async/InTransientScopeInTransientScope.cs | 2 +- Test/Disposal/Sync/InContainer.cs | 2 +- Test/Disposal/Sync/InScope.cs | 2 +- Test/Disposal/Sync/InScopeInTransientScope.cs | 2 +- Test/Disposal/Sync/InTransientScope.cs | 2 +- .../Sync/InTransientScopeInTransientScope.cs | 2 +- .../AsyncContainerToAsyncDisposalHandle.cs | 2 +- .../NoneContainerToAsyncDisposalHandle.cs | 2 +- .../NoneContainerToSyncDisposalHandle.cs | 2 +- .../SyncContainerToAsyncDisposalHandle.cs | 2 +- .../SyncContainerToSyncDisposalHandle.cs | 2 +- Test/Func/Double.cs | 2 +- Test/Func/Vanilla.cs | 2 +- Test/Generics/Choice/Double.cs | 2 +- Test/Generics/Choice/DoubleBothChosen.cs | 2 +- ...ubleBothChosenWithSingleOtherSubstitute.cs | 2 +- .../Choice/DoubleWithSingleOtherSubstitute.cs | 2 +- Test/Generics/Choice/Single.cs | 2 +- .../Choice/SingleWithSingleOtherSubstitute.cs | 2 +- .../Double.cs | 2 +- .../Single.cs | 2 +- Test/Generics/Configuration/AsyncTransient.cs | 2 +- .../AsyncTransientWithJustTransient.cs | 2 +- Test/Generics/Configuration/Composite.cs | 2 +- .../Configuration/ConstructorChoice.cs | 2 +- .../Configuration/ContainerInstance.cs | 2 +- ...erInstanceWithDifferentGenericParameter.cs | 2 +- Test/Generics/Configuration/Decorator.cs | 2 +- .../InitializerImplementationAsync.cs | 2 +- .../InitializerImplementationAsyncValue.cs | 2 +- .../InitializerImplementationSync.cs | 2 +- .../InitializerInterfaceAsync.cs | 2 +- .../InitializerInterfaceAsyncValue.cs | 2 +- .../Configuration/InitializerInterfaceSync.cs | 2 +- .../InterfaceGenericComposite.cs | 2 +- .../InterfaceGenericDecorator.cs | 2 +- Test/Generics/Configuration/ScopeInstance.cs | 2 +- ...peInstanceWithDifferentGenericParameter.cs | 2 +- Test/Generics/Configuration/ScopeRoot.cs | 2 +- Test/Generics/Configuration/SyncTransient.cs | 2 +- .../SyncTransientWithJustTransient.cs | 2 +- .../Configuration/TransientScopeInstance.cs | 2 +- ...peInstanceWithDifferentGenericParameter.cs | 2 +- .../Configuration/TransientScopeRoot.cs | 2 +- Test/Generics/Implementation/Double.cs | 2 +- Test/Generics/Implementation/Single.cs | 2 +- Test/Generics/Interface/Double.cs | 2 +- Test/Generics/Interface/DoubleAndOneFixed.cs | 2 +- Test/Generics/Interface/DoubleAndSetToSame.cs | 2 +- Test/Generics/Interface/DoubleSwitched.cs | 2 +- Test/Generics/Interface/Single.cs | 2 +- ...eAndBaseImplementationDoubleButOneFixed.cs | 2 +- Test/Generics/SubstituteCollection/Double.cs | 2 +- .../DoubleBothSubstituted.cs | 2 +- .../DoubleBothSubstitutedWithChoice.cs | 2 +- .../SubstituteCollection/DoubleWithChoice.cs | 2 +- Test/Generics/SubstituteCollection/Single.cs | 2 +- .../SubstituteCollection/SingleWithChoice.cs | 2 +- .../SubstituteCollection/TripleInsanity.cs | 2 +- .../AssemblyImplementationsAggregation.cs | 2 +- .../Aggregation/ExternalType.cs | 2 +- .../Aggregation/FilterAllImplementations.cs | 2 +- .../Aggregation/InternalsVisibleTo.cs | 2 +- Test/Implementation/Choice/Collection.cs | 2 +- .../Choice/CollectionWithoutChoice.cs | 2 +- .../Choice/SingleInCollection.cs | 2 +- Test/Implementation/Choice/Vanilla.cs | 2 +- .../Choice/VanillaWithoutChoice.cs | 2 +- .../Choice/WithSingleInCollection.cs | 2 +- Test/InitProperty/Vanilla.cs | 2 +- Test/Lazy/Vanilla.cs | 2 +- .../NonOptional/MultipleImplementations.cs | 2 +- .../NonOptional/NoImplementation.cs | 2 +- .../Optional/MultipleImplementations.cs | 2 +- Test/Nullability/Optional/NoImplementation.cs | 2 +- Test/Record/CustomProperty.cs | 2 +- Test/Record/PrimaryConstr.cs | 2 +- Test/Record/Vanilla.cs | 2 +- .../ScopeSpecificAttributes/Decorator.cs | 2 +- .../ScopeSpecificAttributes/Implementation.cs | 2 +- .../ImplementationCollection.cs | 2 +- .../TransientScopeInstance/InContainer.cs | 2 +- .../Scoping/TransientScopeInstance/InScope.cs | 2 +- .../TransientScopeInstance/InScopeInScope.cs | 2 +- .../InTransientScope.cs | 2 +- .../InTransientScopeWithScopes.cs | 2 +- Test/Struct/NoExplicitConstructor.cs | 2 +- Test/Struct/OneExplicitConstructor.cs | 2 +- Test/Struct/RecordNoExplicitConstructor.cs | 2 +- Test/Struct/RecordOneExplicitConstructor.cs | 2 +- Test/TypeInitializer/AsyncTask.cs | 2 +- Test/TypeInitializer/AsyncValueTask.cs | 2 +- Test/TypeInitializer/Sync.cs | 2 +- Test/ValueTuple/NonSyntaxVariant.cs | 2 +- Test/ValueTuple/NonSyntaxVariantSingleItem.cs | 2 +- Test/ValueTuple/SyntaxVariant.cs | 2 +- Test/ValueTuple/ValueTupleTests.cs | 2 +- 181 files changed, 1059 insertions(+), 882 deletions(-) delete mode 100644 Main/Configuration/Attributes.cs create mode 100644 Main/Configuration/Attributes/Aggregation.cs create mode 100644 Main/Configuration/Attributes/Choice.cs create mode 100644 Main/Configuration/Attributes/Miscellaneous.cs create mode 100644 Main/WellKnownTypesAggregation.cs create mode 100644 Main/WellKnownTypesChoice.cs create mode 100644 Main/WellKnownTypesMiscellaneous.cs diff --git a/Main/Configuration/Attributes.cs b/Main/Configuration/Attributes.cs deleted file mode 100644 index d041fe25..00000000 --- a/Main/Configuration/Attributes.cs +++ /dev/null @@ -1,285 +0,0 @@ -namespace MrMeeseeks.DIE.Configuration; - -[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] -public class ImplementationAggregationAttribute : Attribute -{ - public ImplementationAggregationAttribute(params Type[] types) {} -} - -[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] -public class FilterImplementationAggregationAttribute : Attribute -{ - public FilterImplementationAggregationAttribute(params Type[] types) {} -} - -[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] -public class TransientAggregationAttribute : Attribute -{ - public TransientAggregationAttribute(params Type[] types) {} -} - -[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] -public class FilterTransientAggregationAttribute : Attribute -{ - public FilterTransientAggregationAttribute(params Type[] types) {} -} - -[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] -public class SyncTransientAggregationAttribute : Attribute -{ - public SyncTransientAggregationAttribute(params Type[] types) {} -} - -[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] -public class FilterSyncTransientAggregationAttribute : Attribute -{ - public FilterSyncTransientAggregationAttribute(params Type[] types) {} -} - -[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] -public class AsyncTransientAggregationAttribute : Attribute -{ - public AsyncTransientAggregationAttribute(params Type[] types) {} -} - -[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] -public class FilterAsyncTransientAggregationAttribute : Attribute -{ - public FilterAsyncTransientAggregationAttribute(params Type[] types) {} -} - -[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] -public class ContainerInstanceAggregationAttribute : Attribute -{ - public ContainerInstanceAggregationAttribute(params Type[] types) {} -} - -[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] -public class FilterContainerInstanceAggregationAttribute : Attribute -{ - public FilterContainerInstanceAggregationAttribute(params Type[] types) {} -} - -[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] -public class TransientScopeInstanceAggregationAttribute : Attribute -{ - public TransientScopeInstanceAggregationAttribute(params Type[] types) {} -} - -[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] -public class FilterTransientScopeInstanceAggregationAttribute : Attribute -{ - public FilterTransientScopeInstanceAggregationAttribute(params Type[] types) {} -} - -[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] -public class ScopeInstanceAggregationAttribute : Attribute -{ - public ScopeInstanceAggregationAttribute(params Type[] types) {} -} - -[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] -public class FilterScopeInstanceAggregationAttribute : Attribute -{ - public FilterScopeInstanceAggregationAttribute(params Type[] types) {} -} - -[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] -public class TransientScopeRootAggregationAttribute : Attribute -{ - public TransientScopeRootAggregationAttribute(params Type[] types) {} -} - -[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] -public class FilterTransientScopeRootAggregationAttribute : Attribute -{ - public FilterTransientScopeRootAggregationAttribute(params Type[] types) {} -} - -[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] -public class ScopeRootAggregationAttribute : Attribute -{ - public ScopeRootAggregationAttribute(params Type[] types) {} -} - -[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] -public class FilterScopeRootAggregationAttribute : Attribute -{ - public FilterScopeRootAggregationAttribute(params Type[] types) {} -} - -[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] -public class DecoratorAggregationAttribute : Attribute -{ - public DecoratorAggregationAttribute(params Type[] types) {} -} - -[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] -public class FilterDecoratorAggregationAttribute : Attribute -{ - public FilterDecoratorAggregationAttribute(params Type[] types) {} -} - -[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] -public class CompositeAggregationAttribute : Attribute -{ - public CompositeAggregationAttribute(params Type[] types) {} -} - -[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] -public class FilterCompositeAggregationAttribute : Attribute -{ - public FilterCompositeAggregationAttribute(params Type[] types) {} -} - -[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] -public class GenericParameterSubstitutesChoiceAttribute : Attribute -{ - public GenericParameterSubstitutesChoiceAttribute(Type unboundGenericType, string genericArgumentName, params Type[] types) {} -} - -[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] -public class FilterGenericParameterSubstitutesChoiceAttribute : Attribute -{ - public FilterGenericParameterSubstitutesChoiceAttribute(Type unboundGenericType, string genericArgumentName) {} -} - -[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] -public class GenericParameterChoiceAttribute : Attribute -{ - public GenericParameterChoiceAttribute(Type unboundGenericType, string genericArgumentName, Type chosenType) {} -} - -[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] -public class FilterGenericParameterChoiceAttribute : Attribute -{ - public FilterGenericParameterChoiceAttribute(Type unboundGenericType, string genericArgumentName) {} -} - -[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] -public class DecoratorSequenceChoiceAttribute : Attribute -{ - public DecoratorSequenceChoiceAttribute(Type decoratedType, params Type[] types) {} -} - -[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] -public class FilterDecoratorSequenceChoiceAttribute : Attribute -{ - public FilterDecoratorSequenceChoiceAttribute(Type decoratedType) {} -} - -[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] -public class ConstructorChoiceAttribute : Attribute -{ - public ConstructorChoiceAttribute(Type implementationType, params Type[] parameterTypes) - { - } -} - -[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] -public class FilterConstructorChoiceAttribute : Attribute -{ - public FilterConstructorChoiceAttribute(Type implementationType) - { - } -} - -[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] -public class PropertyChoiceAttribute : Attribute -{ - public PropertyChoiceAttribute(Type implementationType, params string[] propertyName) - { - } -} - -[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] -public class FilterPropertyChoiceAttribute : Attribute -{ - public FilterPropertyChoiceAttribute(Type implementationType) - { - } -} - -[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] -public class CustomScopeForRootTypesAttribute : Attribute -{ - public CustomScopeForRootTypesAttribute(params Type[] types) - { - } -} - -[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] -public class TypeInitializerAttribute : Attribute -{ - public TypeInitializerAttribute(Type type, string methodName) - { - } -} - -[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] -public class FilterTypeInitializerAttribute : Attribute -{ - public FilterTypeInitializerAttribute(Type type) - { - } -} - -[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] -public class CreateFunctionAttribute : Attribute -{ - public CreateFunctionAttribute(Type type, string methodNamePrefix) - { - } -} - -[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = false)] -public class AllImplementationsAggregationAttribute : Attribute -{ -} - -[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] -public class FilterAllImplementationsAggregationAttribute : Attribute -{ -} - -[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] -public class AssemblyImplementationsAggregationAttribute : Attribute -{ - public AssemblyImplementationsAggregationAttribute(params Type[] typesFromAssemblies) {} -} - -[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] -public class FilterAssemblyImplementationsAggregationAttribute : Attribute -{ - public FilterAssemblyImplementationsAggregationAttribute(params Type[] typesFromAssemblies) {} -} - -[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] -public class ImplementationChoiceAttribute : Attribute -{ - public ImplementationChoiceAttribute(Type type, Type implementationChoice) {} -} - -[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] -public class FilterImplementationChoiceAttribute : Attribute -{ - public FilterImplementationChoiceAttribute(Type type) {} -} - -[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] -public class ImplementationCollectionChoiceAttribute : Attribute -{ - public ImplementationCollectionChoiceAttribute(Type type, params Type[] implementationChoice) {} -} - -[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] -public class FilterImplementationCollectionChoiceAttribute : Attribute -{ - public FilterImplementationCollectionChoiceAttribute(Type type) {} -} - -[AttributeUsage(AttributeTargets.Assembly)] -public class ErrorDescriptionInsteadOfBuildFailureAttribute : Attribute -{ -} -// ReSharper enable UnusedParameter.Local \ No newline at end of file diff --git a/Main/Configuration/Attributes/Aggregation.cs b/Main/Configuration/Attributes/Aggregation.cs new file mode 100644 index 00000000..e3050c93 --- /dev/null +++ b/Main/Configuration/Attributes/Aggregation.cs @@ -0,0 +1,251 @@ +namespace MrMeeseeks.DIE.Configuration.Attributes; + +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = false)] +public class AllImplementationsAggregationAttribute : Attribute +{ +} + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] +public class FilterAllImplementationsAggregationAttribute : Attribute +{ +} + +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] +public class AssemblyImplementationsAggregationAttribute : Attribute +{ + public AssemblyImplementationsAggregationAttribute(params Type[] typesFromAssemblies) {} +} + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class FilterAssemblyImplementationsAggregationAttribute : Attribute +{ + public FilterAssemblyImplementationsAggregationAttribute(params Type[] typesFromAssemblies) {} +} + +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] +public class ImplementationAggregationAttribute : Attribute +{ + public ImplementationAggregationAttribute(params Type[] types) {} +} + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class FilterImplementationAggregationAttribute : Attribute +{ + public FilterImplementationAggregationAttribute(params Type[] types) {} +} + +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] +public class TransientAbstractionAggregationAttribute : Attribute +{ + public TransientAbstractionAggregationAttribute(params Type[] types) {} +} + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class FilterTransientAbstractionAggregationAttribute : Attribute +{ + public FilterTransientAbstractionAggregationAttribute(params Type[] types) {} +} + +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] +public class TransientImplementationAggregationAttribute : Attribute +{ + public TransientImplementationAggregationAttribute(params Type[] types) {} +} + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class FilterTransientImplementationAggregationAttribute : Attribute +{ + public FilterTransientImplementationAggregationAttribute(params Type[] types) {} +} + +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] +public class SyncTransientAbstractionAggregationAttribute : Attribute +{ + public SyncTransientAbstractionAggregationAttribute(params Type[] types) {} +} + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class FilterSyncTransientAbstractionAggregationAttribute : Attribute +{ + public FilterSyncTransientAbstractionAggregationAttribute(params Type[] types) {} +} + +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] +public class SyncTransientImplementationAggregationAttribute : Attribute +{ + public SyncTransientImplementationAggregationAttribute(params Type[] types) {} +} + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class FilterSyncTransientImplementationAggregationAttribute : Attribute +{ + public FilterSyncTransientImplementationAggregationAttribute(params Type[] types) {} +} + +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] +public class AsyncTransientAbstractionAggregationAttribute : Attribute +{ + public AsyncTransientAbstractionAggregationAttribute(params Type[] types) {} +} + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class FilterAsyncTransientAbstractionAggregationAttribute : Attribute +{ + public FilterAsyncTransientAbstractionAggregationAttribute(params Type[] types) {} +} + +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] +public class AsyncTransientImplementationAggregationAttribute : Attribute +{ + public AsyncTransientImplementationAggregationAttribute(params Type[] types) {} +} + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class FilterAsyncTransientImplementationAggregationAttribute : Attribute +{ + public FilterAsyncTransientImplementationAggregationAttribute(params Type[] types) {} +} + +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] +public class ContainerInstanceAbstractionAggregationAttribute : Attribute +{ + public ContainerInstanceAbstractionAggregationAttribute(params Type[] types) {} +} + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class FilterContainerInstanceAbstractionAggregationAttribute : Attribute +{ + public FilterContainerInstanceAbstractionAggregationAttribute(params Type[] types) {} +} + +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] +public class ContainerInstanceImplementationAggregationAttribute : Attribute +{ + public ContainerInstanceImplementationAggregationAttribute(params Type[] types) {} +} + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class FilterContainerInstanceImplementationAggregationAttribute : Attribute +{ + public FilterContainerInstanceImplementationAggregationAttribute(params Type[] types) {} +} + +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] +public class TransientScopeInstanceAbstractionAggregationAttribute : Attribute +{ + public TransientScopeInstanceAbstractionAggregationAttribute(params Type[] types) {} +} + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class FilterTransientScopeInstanceAbstractionAggregationAttribute : Attribute +{ + public FilterTransientScopeInstanceAbstractionAggregationAttribute(params Type[] types) {} +} + +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] +public class TransientScopeInstanceImplementationAggregationAttribute : Attribute +{ + public TransientScopeInstanceImplementationAggregationAttribute(params Type[] types) {} +} + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class FilterTransientScopeInstanceImplementationAggregationAttribute : Attribute +{ + public FilterTransientScopeInstanceImplementationAggregationAttribute(params Type[] types) {} +} + +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] +public class ScopeInstanceAbstractionAggregationAttribute : Attribute +{ + public ScopeInstanceAbstractionAggregationAttribute(params Type[] types) {} +} + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class FilterScopeInstanceAbstractionAggregationAttribute : Attribute +{ + public FilterScopeInstanceAbstractionAggregationAttribute(params Type[] types) {} +} + +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] +public class ScopeInstanceAbstractionImplementationAttribute : Attribute +{ + public ScopeInstanceAbstractionImplementationAttribute(params Type[] types) {} +} + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class FilterScopeInstanceImplementationAggregationAttribute : Attribute +{ + public FilterScopeInstanceImplementationAggregationAttribute(params Type[] types) {} +} + +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] +public class TransientScopeRootAbstractionAggregationAttribute : Attribute +{ + public TransientScopeRootAbstractionAggregationAttribute(params Type[] types) {} +} + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class FilterTransientScopeRootAbstractionAggregationAttribute : Attribute +{ + public FilterTransientScopeRootAbstractionAggregationAttribute(params Type[] types) {} +} + +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] +public class TransientScopeRootImplementationAggregationAttribute : Attribute +{ + public TransientScopeRootImplementationAggregationAttribute(params Type[] types) {} +} + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class FilterTransientScopeRootImplementationAggregationAttribute : Attribute +{ + public FilterTransientScopeRootImplementationAggregationAttribute(params Type[] types) {} +} + +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] +public class ScopeRootAbstractionAggregationAttribute : Attribute +{ + public ScopeRootAbstractionAggregationAttribute(params Type[] types) {} +} + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class FilterScopeRootAbstractionAggregationAttribute : Attribute +{ + public FilterScopeRootAbstractionAggregationAttribute(params Type[] types) {} +} + +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] +public class ScopeRootImplementationAggregationAttribute : Attribute +{ + public ScopeRootImplementationAggregationAttribute(params Type[] types) {} +} + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class FilterScopeRootImplementationAggregationAttribute : Attribute +{ + public FilterScopeRootImplementationAggregationAttribute(params Type[] types) {} +} + +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] +public class DecoratorAbstractionAggregationAttribute : Attribute +{ + public DecoratorAbstractionAggregationAttribute(params Type[] types) {} +} + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class FilterDecoratorAbstractionAggregationAttribute : Attribute +{ + public FilterDecoratorAbstractionAggregationAttribute(params Type[] types) {} +} + +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] +public class CompositeAbstractionAggregationAttribute : Attribute +{ + public CompositeAbstractionAggregationAttribute(params Type[] types) {} +} + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class FilterCompositeAbstractionAggregationAttribute : Attribute +{ + public FilterCompositeAbstractionAggregationAttribute(params Type[] types) {} +} \ No newline at end of file diff --git a/Main/Configuration/Attributes/Choice.cs b/Main/Configuration/Attributes/Choice.cs new file mode 100644 index 00000000..f86beb7f --- /dev/null +++ b/Main/Configuration/Attributes/Choice.cs @@ -0,0 +1,93 @@ +namespace MrMeeseeks.DIE.Configuration.Attributes; + +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] +public class GenericParameterSubstitutesChoiceAttribute : Attribute +{ + public GenericParameterSubstitutesChoiceAttribute(Type unboundGenericType, string genericArgumentName, params Type[] types) {} +} + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class FilterGenericParameterSubstitutesChoiceAttribute : Attribute +{ + public FilterGenericParameterSubstitutesChoiceAttribute(Type unboundGenericType, string genericArgumentName) {} +} + +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] +public class GenericParameterChoiceAttribute : Attribute +{ + public GenericParameterChoiceAttribute(Type unboundGenericType, string genericArgumentName, Type chosenType) {} +} + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class FilterGenericParameterChoiceAttribute : Attribute +{ + public FilterGenericParameterChoiceAttribute(Type unboundGenericType, string genericArgumentName) {} +} + +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] +public class DecoratorSequenceChoiceAttribute : Attribute +{ + public DecoratorSequenceChoiceAttribute(Type decoratedType, params Type[] types) {} +} + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class FilterDecoratorSequenceChoiceAttribute : Attribute +{ + public FilterDecoratorSequenceChoiceAttribute(Type decoratedType) {} +} + +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] +public class ConstructorChoiceAttribute : Attribute +{ + public ConstructorChoiceAttribute(Type implementationType, params Type[] parameterTypes) + { + } +} + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class FilterConstructorChoiceAttribute : Attribute +{ + public FilterConstructorChoiceAttribute(Type implementationType) + { + } +} + +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] +public class PropertyChoiceAttribute : Attribute +{ + public PropertyChoiceAttribute(Type implementationType, params string[] propertyName) + { + } +} + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class FilterPropertyChoiceAttribute : Attribute +{ + public FilterPropertyChoiceAttribute(Type implementationType) + { + } +} + +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] +public class ImplementationChoiceAttribute : Attribute +{ + public ImplementationChoiceAttribute(Type type, Type implementationChoice) {} +} + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class FilterImplementationChoiceAttribute : Attribute +{ + public FilterImplementationChoiceAttribute(Type type) {} +} + +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] +public class ImplementationCollectionChoiceAttribute : Attribute +{ + public ImplementationCollectionChoiceAttribute(Type type, params Type[] implementationChoice) {} +} + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class FilterImplementationCollectionChoiceAttribute : Attribute +{ + public FilterImplementationCollectionChoiceAttribute(Type type) {} +} \ No newline at end of file diff --git a/Main/Configuration/Attributes/Miscellaneous.cs b/Main/Configuration/Attributes/Miscellaneous.cs new file mode 100644 index 00000000..8ac0d57c --- /dev/null +++ b/Main/Configuration/Attributes/Miscellaneous.cs @@ -0,0 +1,39 @@ +namespace MrMeeseeks.DIE.Configuration.Attributes; + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class CustomScopeForRootTypesAttribute : Attribute +{ + public CustomScopeForRootTypesAttribute(params Type[] types) + { + } +} + +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] +public class TypeInitializerAttribute : Attribute +{ + public TypeInitializerAttribute(Type type, string methodName) + { + } +} + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class FilterTypeInitializerAttribute : Attribute +{ + public FilterTypeInitializerAttribute(Type type) + { + } +} + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class CreateFunctionAttribute : Attribute +{ + public CreateFunctionAttribute(Type type, string methodNamePrefix) + { + } +} + +[AttributeUsage(AttributeTargets.Assembly)] +public class ErrorDescriptionInsteadOfBuildFailureAttribute : Attribute +{ +} +// ReSharper enable UnusedParameter.Local \ No newline at end of file diff --git a/Main/Configuration/CurrentlyConsideredTypes.cs b/Main/Configuration/CurrentlyConsideredTypes.cs index 541e5946..a238a25e 100644 --- a/Main/Configuration/CurrentlyConsideredTypes.cs +++ b/Main/Configuration/CurrentlyConsideredTypes.cs @@ -144,25 +144,25 @@ public CurrentlyConsideredTypes( } SyncTransientTypes = GetSetOfTypesWithProperties( - t => t.SyncTransient.Concat(t.Transient).ToList(), - t => t.FilterSyncTransient.Concat(t.FilterTransient).ToList()); + t => t.SyncTransientAbstraction.Concat(t.TransientAbstraction).ToList(), + t => t.FilterSyncTransientAbstraction.Concat(t.FilterTransientAbstraction).ToList()); AsyncTransientTypes = GetSetOfTypesWithProperties( - t => t.AsyncTransient.Concat(t.Transient).ToList(), - t => t.FilterAsyncTransient.Concat(t.FilterTransient).ToList()); - ContainerInstanceTypes = GetSetOfTypesWithProperties(t => t.ContainerInstance, t => t.FilterContainerInstance); - TransientScopeInstanceTypes = GetSetOfTypesWithProperties(t => t.TransientScopeInstance, t => t.FilterTransientScopeInstance); - ScopeInstanceTypes = GetSetOfTypesWithProperties(t => t.ScopeInstance, t => t.FilterScopeInstance); - TransientScopeRootTypes = GetSetOfTypesWithProperties(t => t.TransientScopeRoot, t => t.FilterTransientScopeRoot); - ScopeRootTypes = GetSetOfTypesWithProperties(t => t.ScopeRoot, t => t.FilterScopeRoot); + t => t.AsyncTransientAbstraction.Concat(t.TransientAbstraction).ToList(), + t => t.FilterAsyncTransientAbstraction.Concat(t.FilterTransientAbstraction).ToList()); + ContainerInstanceTypes = GetSetOfTypesWithProperties(t => t.ContainerInstanceAbstraction, t => t.FilterContainerInstanceAbstraction); + TransientScopeInstanceTypes = GetSetOfTypesWithProperties(t => t.TransientScopeInstanceAbstraction, t => t.FilterTransientScopeInstanceAbstraction); + ScopeInstanceTypes = GetSetOfTypesWithProperties(t => t.ScopeInstance, t => t.FilterScopeInstanceAbstraction); + TransientScopeRootTypes = GetSetOfTypesWithProperties(t => t.TransientScopeRootAbstraction, t => t.FilterTransientScopeRootAbstraction); + ScopeRootTypes = GetSetOfTypesWithProperties(t => t.ScopeRootAbstraction, t => t.FilterScopeRootAbstraction); var compositeInterfaces = ImmutableHashSet.Empty; foreach (var types in typesFromAttributes) { - compositeInterfaces = compositeInterfaces.Except(types.FilterComposite.Select(c => c.UnboundIfGeneric())); - compositeInterfaces = compositeInterfaces.Union(types.Composite.Select(c => c.UnboundIfGeneric())); + compositeInterfaces = compositeInterfaces.Except(types.FilterCompositeAbstraction.Select(c => c.UnboundIfGeneric())); + compositeInterfaces = compositeInterfaces.Union(types.CompositeAbstraction.Select(c => c.UnboundIfGeneric())); } - var compositeTypes = GetSetOfTypesWithProperties(t => t.Composite, t => t.FilterComposite); + var compositeTypes = GetSetOfTypesWithProperties(t => t.CompositeAbstraction, t => t.FilterCompositeAbstraction); InterfaceToComposite = compositeTypes .OfType() .GroupBy(nts => @@ -205,13 +205,13 @@ public CurrentlyConsideredTypes( var decoratorInterfaces = ImmutableHashSet.Empty; foreach (var types in typesFromAttributes) { - decoratorInterfaces = decoratorInterfaces.Except(types.FilterDecorator.Select(c => c.UnboundIfGeneric())); - decoratorInterfaces = decoratorInterfaces.Union(types.Decorator.Select(c => c.UnboundIfGeneric())); + decoratorInterfaces = decoratorInterfaces.Except(types.FilterDecoratorAbstraction.Select(c => c.UnboundIfGeneric())); + decoratorInterfaces = decoratorInterfaces.Union(types.DecoratorAbstraction.Select(c => c.UnboundIfGeneric())); } var decoratorTypes = GetSetOfTypesWithProperties( - t => t.Decorator, - t => t.FilterDecorator); + t => t.DecoratorAbstraction, + t => t.FilterDecoratorAbstraction); InterfaceToDecorators = decoratorTypes .OfType() .GroupBy(nts => diff --git a/Main/Configuration/TypesFromAttributes.cs b/Main/Configuration/TypesFromAttributes.cs index 20b47101..3cd34c2b 100644 --- a/Main/Configuration/TypesFromAttributes.cs +++ b/Main/Configuration/TypesFromAttributes.cs @@ -5,16 +5,16 @@ namespace MrMeeseeks.DIE.Configuration; internal interface ITypesFromAttributes { IReadOnlyList Implementation { get; } - IReadOnlyList Transient { get; } - IReadOnlyList SyncTransient { get; } - IReadOnlyList AsyncTransient { get; } - IReadOnlyList ContainerInstance { get; } - IReadOnlyList TransientScopeInstance { get; } + IReadOnlyList TransientAbstraction { get; } + IReadOnlyList SyncTransientAbstraction { get; } + IReadOnlyList AsyncTransientAbstraction { get; } + IReadOnlyList ContainerInstanceAbstraction { get; } + IReadOnlyList TransientScopeInstanceAbstraction { get; } IReadOnlyList ScopeInstance { get; } - IReadOnlyList TransientScopeRoot { get; } - IReadOnlyList ScopeRoot { get; } - IReadOnlyList Decorator { get; } - IReadOnlyList Composite { get; } + IReadOnlyList TransientScopeRootAbstraction { get; } + IReadOnlyList ScopeRootAbstraction { get; } + IReadOnlyList DecoratorAbstraction { get; } + IReadOnlyList CompositeAbstraction { get; } IReadOnlyList<(INamedTypeSymbol, IReadOnlyList)> DecoratorSequenceChoices { get; } IReadOnlyList<(INamedTypeSymbol, IMethodSymbol)> ConstructorChoices { get; } IReadOnlyList<(INamedTypeSymbol, IMethodSymbol)> TypeInitializers { get; } @@ -26,16 +26,16 @@ internal interface ITypesFromAttributes IReadOnlyList<(INamedTypeSymbol, INamedTypeSymbol)> ImplementationChoices { get; } IReadOnlyList<(INamedTypeSymbol, IReadOnlyList)> ImplementationCollectionChoices { get; } IReadOnlyList FilterImplementation { get; } - IReadOnlyList FilterTransient { get; } - IReadOnlyList FilterSyncTransient { get; } - IReadOnlyList FilterAsyncTransient { get; } - IReadOnlyList FilterContainerInstance { get; } - IReadOnlyList FilterTransientScopeInstance { get; } - IReadOnlyList FilterScopeInstance { get; } - IReadOnlyList FilterTransientScopeRoot { get; } - IReadOnlyList FilterScopeRoot { get; } - IReadOnlyList FilterDecorator { get; } - IReadOnlyList FilterComposite { get; } + IReadOnlyList FilterTransientAbstraction { get; } + IReadOnlyList FilterSyncTransientAbstraction { get; } + IReadOnlyList FilterAsyncTransientAbstraction { get; } + IReadOnlyList FilterContainerInstanceAbstraction { get; } + IReadOnlyList FilterTransientScopeInstanceAbstraction { get; } + IReadOnlyList FilterScopeInstanceAbstraction { get; } + IReadOnlyList FilterTransientScopeRootAbstraction { get; } + IReadOnlyList FilterScopeRootAbstraction { get; } + IReadOnlyList FilterDecoratorAbstraction { get; } + IReadOnlyList FilterCompositeAbstraction { get; } IReadOnlyList FilterDecoratorSequenceChoices { get; } IReadOnlyList FilterConstructorChoices { get; } IReadOnlyList FilterTypeInitializers { get; } @@ -55,16 +55,19 @@ internal TypesFromAttributes( IReadOnlyList attributeData, // dependencies - WellKnownTypes wellKnownTypes) : base(attributeData, wellKnownTypes) + WellKnownTypesAggregation wellKnownTypesAggregation, + WellKnownTypesChoice wellKnownTypesChoice, + WellKnownTypesMiscellaneous wellKnownTypesMiscellaneous) + : base(attributeData, wellKnownTypesAggregation, wellKnownTypesChoice, wellKnownTypesMiscellaneous) { - ContainerInstance = GetTypesFromAttribute(wellKnownTypes.ContainerInstanceAggregationAttribute).ToList(); - TransientScopeInstance = GetTypesFromAttribute(wellKnownTypes.TransientScopeInstanceAggregationAttribute).ToList(); - TransientScopeRoot = GetTypesFromAttribute(wellKnownTypes.TransientScopeRootAggregationAttribute).ToList(); - ScopeRoot = GetTypesFromAttribute(wellKnownTypes.ScopeRootAggregationAttribute).ToList(); - FilterContainerInstance = GetTypesFromAttribute(wellKnownTypes.FilterContainerInstanceAggregationAttribute).ToList(); - FilterTransientScopeInstance = GetTypesFromAttribute(wellKnownTypes.FilterTransientScopeInstanceAggregationAttribute).ToList(); - FilterTransientScopeRoot = GetTypesFromAttribute(wellKnownTypes.FilterTransientScopeRootAggregationAttribute).ToList(); - FilterScopeRoot = GetTypesFromAttribute(wellKnownTypes.FilterScopeRootAggregationAttribute).ToList(); + ContainerInstanceAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.ContainerInstanceAbstractionAggregationAttribute).ToList(); + TransientScopeInstanceAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.TransientScopeInstanceAbstractionAggregationAttribute).ToList(); + TransientScopeRootAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.TransientScopeRootAbstractionAggregationAttribute).ToList(); + ScopeRootAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.ScopeRootAbstractionAggregationAttribute).ToList(); + FilterContainerInstanceAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.FilterContainerInstanceAbstractionAggregationAttribute).ToList(); + FilterTransientScopeInstanceAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.FilterTransientScopeInstanceAbstractionAggregationAttribute).ToList(); + FilterTransientScopeRootAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.FilterTransientScopeRootAbstractionAggregationAttribute).ToList(); + FilterScopeRootAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.FilterScopeRootAbstractionAggregationAttribute).ToList(); } } @@ -75,37 +78,39 @@ internal ScopeTypesFromAttributes( IReadOnlyList attributeData, // dependencies - WellKnownTypes wellKnownTypes) + WellKnownTypesAggregation wellKnownTypesAggregation, + WellKnownTypesChoice wellKnownTypesChoice, + WellKnownTypesMiscellaneous wellKnownTypesMiscellaneous) { AttributeDictionary = attributeData .GroupBy(ad => ad.AttributeClass, SymbolEqualityComparer.Default) .ToDictionary(g => g.Key, g => g); - Implementation = GetTypesFromAttribute(wellKnownTypes.ImplementationAggregationAttribute).ToList(); - Transient = GetTypesFromAttribute(wellKnownTypes.TransientAggregationAttribute).ToList(); - SyncTransient = GetTypesFromAttribute(wellKnownTypes.SyncTransientAggregationAttribute).ToList(); - AsyncTransient = GetTypesFromAttribute(wellKnownTypes.AsyncTransientAggregationAttribute).ToList(); - ContainerInstance = new List(); - TransientScopeInstance = new List(); - ScopeInstance = GetTypesFromAttribute(wellKnownTypes.ScopeInstanceAggregationAttribute).ToList(); - TransientScopeRoot = new List(); - ScopeRoot = new List(); - Decorator = GetTypesFromAttribute(wellKnownTypes.DecoratorAggregationAttribute).ToList(); - Composite = GetTypesFromAttribute(wellKnownTypes.CompositeAggregationAttribute).ToList(); - - FilterImplementation = GetTypesFromAttribute(wellKnownTypes.FilterImplementationAggregationAttribute).ToList(); - FilterTransient = GetTypesFromAttribute(wellKnownTypes.FilterTransientAggregationAttribute).ToList(); - FilterSyncTransient = GetTypesFromAttribute(wellKnownTypes.FilterSyncTransientAggregationAttribute).ToList(); - FilterAsyncTransient = GetTypesFromAttribute(wellKnownTypes.FilterAsyncTransientAggregationAttribute).ToList(); - FilterContainerInstance = new List(); - FilterTransientScopeInstance = new List(); - FilterScopeInstance = GetTypesFromAttribute(wellKnownTypes.FilterScopeInstanceAggregationAttribute).ToList(); - FilterTransientScopeRoot = new List(); - FilterScopeRoot = new List(); - FilterDecorator = GetTypesFromAttribute(wellKnownTypes.FilterDecoratorAggregationAttribute).ToList(); - FilterComposite = GetTypesFromAttribute(wellKnownTypes.FilterCompositeAggregationAttribute).ToList(); + Implementation = GetTypesFromAttribute(wellKnownTypesAggregation.ImplementationAggregationAttribute).ToList(); + TransientAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.TransientAbstractionAggregationAttribute).ToList(); + SyncTransientAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.SyncTransientAbstractionAggregationAttribute).ToList(); + AsyncTransientAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.AsyncTransientAbstractionAggregationAttribute).ToList(); + ContainerInstanceAbstraction = new List(); + TransientScopeInstanceAbstraction = new List(); + ScopeInstance = GetTypesFromAttribute(wellKnownTypesAggregation.ScopeInstanceAbstractionAggregationAttribute).ToList(); + TransientScopeRootAbstraction = new List(); + ScopeRootAbstraction = new List(); + DecoratorAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.DecoratorAbstractionAggregationAttribute).ToList(); + CompositeAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.CompositeAbstractionAggregationAttribute).ToList(); + + FilterImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.FilterImplementationAggregationAttribute).ToList(); + FilterTransientAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.FilterTransientAbstractionAggregationAttribute).ToList(); + FilterSyncTransientAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.FilterSyncTransientAbstractionAggregationAttribute).ToList(); + FilterAsyncTransientAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.FilterAsyncTransientAbstractionAggregationAttribute).ToList(); + FilterContainerInstanceAbstraction = new List(); + FilterTransientScopeInstanceAbstraction = new List(); + FilterScopeInstanceAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.FilterScopeInstanceAbstractionAggregationAttribute).ToList(); + FilterTransientScopeRootAbstraction = new List(); + FilterScopeRootAbstraction = new List(); + FilterDecoratorAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.FilterDecoratorAbstractionAggregationAttribute).ToList(); + FilterCompositeAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.FilterCompositeAbstractionAggregationAttribute).ToList(); - DecoratorSequenceChoices = (AttributeDictionary.TryGetValue(wellKnownTypes.DecoratorSequenceChoiceAttribute, out var decoratorSequenceChoiceAttributes) + DecoratorSequenceChoices = (AttributeDictionary.TryGetValue(wellKnownTypesChoice.DecoratorSequenceChoiceAttribute, out var decoratorSequenceChoiceAttributes) ? decoratorSequenceChoiceAttributes : Enumerable.Empty()) .Select(ad => @@ -127,7 +132,7 @@ internal ScopeTypesFromAttributes( .OfType<(INamedTypeSymbol, IReadOnlyList)>() .ToList(); - FilterDecoratorSequenceChoices = (AttributeDictionary.TryGetValue(wellKnownTypes.FilterDecoratorSequenceChoiceAttribute, out var filterDecoratorSequenceChoiceAttributes) + FilterDecoratorSequenceChoices = (AttributeDictionary.TryGetValue(wellKnownTypesChoice.FilterDecoratorSequenceChoiceAttribute, out var filterDecoratorSequenceChoiceAttributes) ? filterDecoratorSequenceChoiceAttributes : Enumerable.Empty()) .Select(ad => @@ -140,7 +145,7 @@ internal ScopeTypesFromAttributes( .OfType() .ToList(); - ConstructorChoices = (AttributeDictionary.TryGetValue(wellKnownTypes.ConstructorChoiceAttribute, out var constructorChoiceAttributes) + ConstructorChoices = (AttributeDictionary.TryGetValue(wellKnownTypesChoice.ConstructorChoiceAttribute, out var constructorChoiceAttributes) ? constructorChoiceAttributes : Enumerable.Empty()) .Select(ad => @@ -183,7 +188,7 @@ internal ScopeTypesFromAttributes( .OfType<(INamedTypeSymbol, IMethodSymbol)>() .ToList(); - FilterConstructorChoices = (AttributeDictionary.TryGetValue(wellKnownTypes.FilterConstructorChoiceAttribute, out var filterConstructorChoiceAttributes) + FilterConstructorChoices = (AttributeDictionary.TryGetValue(wellKnownTypesChoice.FilterConstructorChoiceAttribute, out var filterConstructorChoiceAttributes) ? filterConstructorChoiceAttributes : Enumerable.Empty()) .Select(ad => ad.ConstructorArguments.Length < 1 @@ -192,7 +197,7 @@ internal ScopeTypesFromAttributes( .OfType() .ToList(); - PropertyChoices = (AttributeDictionary.TryGetValue(wellKnownTypes.PropertyChoiceAttribute, out var propertyChoiceGroup) + PropertyChoices = (AttributeDictionary.TryGetValue(wellKnownTypesChoice.PropertyChoiceAttribute, out var propertyChoiceGroup) ? propertyChoiceGroup : Enumerable.Empty()) .Select(ad => @@ -220,7 +225,7 @@ internal ScopeTypesFromAttributes( .OfType<(INamedTypeSymbol, IReadOnlyList)>() .ToList(); - FilterPropertyChoices = (AttributeDictionary.TryGetValue(wellKnownTypes.FilterPropertyChoiceAttribute, out var filterPropertyChoicesGroup) + FilterPropertyChoices = (AttributeDictionary.TryGetValue(wellKnownTypesChoice.FilterPropertyChoiceAttribute, out var filterPropertyChoicesGroup) ? filterPropertyChoicesGroup : Enumerable.Empty()) .Select(ad => @@ -232,7 +237,7 @@ internal ScopeTypesFromAttributes( .OfType() .ToList(); - TypeInitializers = (AttributeDictionary.TryGetValue(wellKnownTypes.TypeInitializerAttribute, out var typeInitializerAttributes) + TypeInitializers = (AttributeDictionary.TryGetValue(wellKnownTypesMiscellaneous.TypeInitializerAttribute, out var typeInitializerAttributes) ? typeInitializerAttributes : Enumerable.Empty()) .Select(ad => @@ -258,7 +263,7 @@ internal ScopeTypesFromAttributes( .OfType<(INamedTypeSymbol, IMethodSymbol)>() .ToList(); - FilterTypeInitializers = (AttributeDictionary.TryGetValue(wellKnownTypes.FilterTypeInitializerAttribute, out var filterTypeInitializerAttributes) + FilterTypeInitializers = (AttributeDictionary.TryGetValue(wellKnownTypesMiscellaneous.FilterTypeInitializerAttribute, out var filterTypeInitializerAttributes) ? filterTypeInitializerAttributes : Enumerable.Empty()) .Select(ad => @@ -270,7 +275,7 @@ internal ScopeTypesFromAttributes( .OfType() .ToList(); - GenericParameterSubstitutesChoices = (AttributeDictionary.TryGetValue(wellKnownTypes.GenericParameterSubstitutesChoiceAttribute, out var genericParameterSubstitutesChoiceAttributes) + GenericParameterSubstitutesChoices = (AttributeDictionary.TryGetValue(wellKnownTypesChoice.GenericParameterSubstitutesChoiceAttribute, out var genericParameterSubstitutesChoiceAttributes) ? genericParameterSubstitutesChoiceAttributes : Enumerable.Empty()) .Select(ad => @@ -303,7 +308,7 @@ internal ScopeTypesFromAttributes( .OfType<(INamedTypeSymbol, ITypeParameterSymbol, IReadOnlyList)>() .ToList(); - GenericParameterChoices = (AttributeDictionary.TryGetValue(wellKnownTypes.GenericParameterChoiceAttribute, out var genericParameterChoiceAttributes) + GenericParameterChoices = (AttributeDictionary.TryGetValue(wellKnownTypesChoice.GenericParameterChoiceAttribute, out var genericParameterChoiceAttributes) ? genericParameterChoiceAttributes : Enumerable.Empty()) .Select(ad => @@ -331,7 +336,7 @@ internal ScopeTypesFromAttributes( .OfType<(INamedTypeSymbol, ITypeParameterSymbol, INamedTypeSymbol)>() .ToList(); - FilterGenericParameterSubstitutesChoices = (AttributeDictionary.TryGetValue(wellKnownTypes.FilterGenericParameterSubstitutesChoiceAttribute, out var filterGenericParameterSubstitutesChoiceAttributes) + FilterGenericParameterSubstitutesChoices = (AttributeDictionary.TryGetValue(wellKnownTypesChoice.FilterGenericParameterSubstitutesChoiceAttribute, out var filterGenericParameterSubstitutesChoiceAttributes) ? filterGenericParameterSubstitutesChoiceAttributes : Enumerable.Empty()) .Select(ad => @@ -357,7 +362,7 @@ internal ScopeTypesFromAttributes( .OfType<(INamedTypeSymbol, ITypeParameterSymbol)>() .ToList(); - FilterGenericParameterChoices = (AttributeDictionary.TryGetValue(wellKnownTypes.FilterGenericParameterChoiceAttribute, out var filterGenericParameterChoiceAttributes) + FilterGenericParameterChoices = (AttributeDictionary.TryGetValue(wellKnownTypesChoice.FilterGenericParameterChoiceAttribute, out var filterGenericParameterChoiceAttributes) ? filterGenericParameterChoiceAttributes : Enumerable.Empty()) .Select(ad => @@ -383,17 +388,17 @@ internal ScopeTypesFromAttributes( .OfType<(INamedTypeSymbol, ITypeParameterSymbol)>() .ToList(); - AllImplementations = (AttributeDictionary.TryGetValue(wellKnownTypes.AllImplementationsAggregationAttribute, out var allImplementationsAttributes) + AllImplementations = (AttributeDictionary.TryGetValue(wellKnownTypesAggregation.AllImplementationsAggregationAttribute, out var allImplementationsAttributes) ? allImplementationsAttributes : Enumerable.Empty()) .Any(); - FilterAllImplementations = (AttributeDictionary.TryGetValue(wellKnownTypes.FilterAllImplementationsAggregationAttribute, out var filterAllImplementationsAttributes) + FilterAllImplementations = (AttributeDictionary.TryGetValue(wellKnownTypesAggregation.FilterAllImplementationsAggregationAttribute, out var filterAllImplementationsAttributes) ? filterAllImplementationsAttributes : Enumerable.Empty()) .Any(); - AssemblyImplementations = (AttributeDictionary.TryGetValue(wellKnownTypes.AssemblyImplementationsAggregationAttribute, out var assemblyImplementationsAttributes) + AssemblyImplementations = (AttributeDictionary.TryGetValue(wellKnownTypesAggregation.AssemblyImplementationsAggregationAttribute, out var assemblyImplementationsAttributes) ? assemblyImplementationsAttributes : Enumerable.Empty()) .SelectMany(ad => ad.ConstructorArguments.Length < 1 @@ -408,7 +413,7 @@ internal ScopeTypesFromAttributes( .OfType() .ToList(); - FilterAssemblyImplementations = (AttributeDictionary.TryGetValue(wellKnownTypes.FilterAllImplementationsAggregationAttribute, out var filterAssemblyImplementationsAttributes) + FilterAssemblyImplementations = (AttributeDictionary.TryGetValue(wellKnownTypesAggregation.FilterAllImplementationsAggregationAttribute, out var filterAssemblyImplementationsAttributes) ? filterAssemblyImplementationsAttributes : Enumerable.Empty()) .SelectMany(ad => ad.ConstructorArguments.Length < 1 @@ -423,7 +428,7 @@ internal ScopeTypesFromAttributes( .OfType() .ToList(); - ImplementationChoices = (AttributeDictionary.TryGetValue(wellKnownTypes.ImplementationChoiceAttribute, out var implementationChoiceAttributes) + ImplementationChoices = (AttributeDictionary.TryGetValue(wellKnownTypesChoice.ImplementationChoiceAttribute, out var implementationChoiceAttributes) ? implementationChoiceAttributes : Enumerable.Empty()) .Select(ad => @@ -435,7 +440,7 @@ internal ScopeTypesFromAttributes( .OfType<(INamedTypeSymbol, INamedTypeSymbol)>() .ToList(); - ImplementationCollectionChoices = (AttributeDictionary.TryGetValue(wellKnownTypes.ImplementationCollectionChoiceAttribute, out var implementationCollectionChoicesAttributes) + ImplementationCollectionChoices = (AttributeDictionary.TryGetValue(wellKnownTypesChoice.ImplementationCollectionChoiceAttribute, out var implementationCollectionChoicesAttributes) ? implementationCollectionChoicesAttributes : Enumerable.Empty()) .Select(ad => @@ -459,9 +464,9 @@ internal ScopeTypesFromAttributes( .OfType<(INamedTypeSymbol, IReadOnlyList)>() .ToList(); - FilterImplementationChoices = GetTypesFromAttribute(wellKnownTypes.FilterImplementationChoiceAttribute).ToList(); + FilterImplementationChoices = GetTypesFromAttribute(wellKnownTypesChoice.FilterImplementationChoiceAttribute).ToList(); - FilterImplementationCollectionChoices = GetTypesFromAttribute(wellKnownTypes.FilterImplementationCollectionChoiceAttribute).ToList(); + FilterImplementationCollectionChoices = GetTypesFromAttribute(wellKnownTypesChoice.FilterImplementationCollectionChoiceAttribute).ToList(); } private IReadOnlyDictionary> AttributeDictionary { get; } @@ -489,16 +494,16 @@ bool CheckValidType(TypedConstant typedConstant, out INamedTypeSymbol type) } public IReadOnlyList Implementation { get; } - public IReadOnlyList Transient { get; } - public IReadOnlyList SyncTransient { get; } - public IReadOnlyList AsyncTransient { get; } - public IReadOnlyList ContainerInstance { get; protected init; } - public IReadOnlyList TransientScopeInstance { get; protected init; } + public IReadOnlyList TransientAbstraction { get; } + public IReadOnlyList SyncTransientAbstraction { get; } + public IReadOnlyList AsyncTransientAbstraction { get; } + public IReadOnlyList ContainerInstanceAbstraction { get; protected init; } + public IReadOnlyList TransientScopeInstanceAbstraction { get; protected init; } public IReadOnlyList ScopeInstance { get; } - public IReadOnlyList TransientScopeRoot { get; protected init; } - public IReadOnlyList ScopeRoot { get; protected init; } - public IReadOnlyList Decorator { get; } - public IReadOnlyList Composite { get; } + public IReadOnlyList TransientScopeRootAbstraction { get; protected init; } + public IReadOnlyList ScopeRootAbstraction { get; protected init; } + public IReadOnlyList DecoratorAbstraction { get; } + public IReadOnlyList CompositeAbstraction { get; } public IReadOnlyList<(INamedTypeSymbol, IReadOnlyList)> DecoratorSequenceChoices { get; } public IReadOnlyList<(INamedTypeSymbol, IMethodSymbol)> ConstructorChoices { get; } public IReadOnlyList<(INamedTypeSymbol, IMethodSymbol)> TypeInitializers { get; } @@ -510,16 +515,16 @@ bool CheckValidType(TypedConstant typedConstant, out INamedTypeSymbol type) public IReadOnlyList<(INamedTypeSymbol, INamedTypeSymbol)> ImplementationChoices { get; } public IReadOnlyList<(INamedTypeSymbol, IReadOnlyList)> ImplementationCollectionChoices { get; } public IReadOnlyList FilterImplementation { get; } - public IReadOnlyList FilterTransient { get; } - public IReadOnlyList FilterSyncTransient { get; } - public IReadOnlyList FilterAsyncTransient { get; } - public IReadOnlyList FilterContainerInstance { get; protected init; } - public IReadOnlyList FilterTransientScopeInstance { get; protected init; } - public IReadOnlyList FilterScopeInstance { get; } - public IReadOnlyList FilterTransientScopeRoot { get; protected init; } - public IReadOnlyList FilterScopeRoot { get; protected init; } - public IReadOnlyList FilterDecorator { get; } - public IReadOnlyList FilterComposite { get; } + public IReadOnlyList FilterTransientAbstraction { get; } + public IReadOnlyList FilterSyncTransientAbstraction { get; } + public IReadOnlyList FilterAsyncTransientAbstraction { get; } + public IReadOnlyList FilterContainerInstanceAbstraction { get; protected init; } + public IReadOnlyList FilterTransientScopeInstanceAbstraction { get; protected init; } + public IReadOnlyList FilterScopeInstanceAbstraction { get; } + public IReadOnlyList FilterTransientScopeRootAbstraction { get; protected init; } + public IReadOnlyList FilterScopeRootAbstraction { get; protected init; } + public IReadOnlyList FilterDecoratorAbstraction { get; } + public IReadOnlyList FilterCompositeAbstraction { get; } public IReadOnlyList FilterDecoratorSequenceChoices { get; } public IReadOnlyList FilterConstructorChoices { get; } public IReadOnlyList FilterTypeInitializers { get; } diff --git a/Main/ContainerDieExceptionGenerator.cs b/Main/ContainerDieExceptionGenerator.cs index 630e73bd..35a34f64 100644 --- a/Main/ContainerDieExceptionGenerator.cs +++ b/Main/ContainerDieExceptionGenerator.cs @@ -11,14 +11,14 @@ internal interface IContainerDieExceptionGenerator internal class ContainerDieExceptionGenerator : IContainerDieExceptionGenerator { private readonly GeneratorExecutionContext _context; - private readonly WellKnownTypes _wellKnownTypes; + private readonly WellKnownTypesMiscellaneous _wellKnownTypesMiscellaneous; internal ContainerDieExceptionGenerator( GeneratorExecutionContext context, - WellKnownTypes wellKnownTypes) + WellKnownTypesMiscellaneous wellKnownTypesMiscellaneous) { _context = context; - _wellKnownTypes = wellKnownTypes; + _wellKnownTypesMiscellaneous = wellKnownTypesMiscellaneous; } public void Generate(string namespaceName, string containerClassName, DieException exception) @@ -29,7 +29,7 @@ public void Generate(string namespaceName, string containerClassName, DieExcepti .AppendLine($"{{") .AppendLine($"partial class {containerClassName}") .AppendLine($"{{") - .AppendLine($"public {_wellKnownTypes.DieExceptionKind.FullName()} ExceptionKind_0_0 => {_wellKnownTypes.DieExceptionKind.FullName()}.{exception.Kind.ToString()};") + .AppendLine($"public {_wellKnownTypesMiscellaneous.DieExceptionKind.FullName()} ExceptionKind_0_0 => {_wellKnownTypesMiscellaneous.DieExceptionKind.FullName()}.{exception.Kind.ToString()};") .AppendLine($"}}") .AppendLine($"}}") .AppendLine($"#nullable disable"); diff --git a/Main/ContainerInfo.cs b/Main/ContainerInfo.cs index 0ec063d5..5d431877 100644 --- a/Main/ContainerInfo.cs +++ b/Main/ContainerInfo.cs @@ -1,5 +1,3 @@ -using MrMeeseeks.DIE.Extensions; - namespace MrMeeseeks.DIE; internal interface IContainerInfo @@ -19,7 +17,7 @@ internal ContainerInfo( INamedTypeSymbol containerClass, // dependencies - WellKnownTypes wellKnowTypes) + WellKnownTypesMiscellaneous wellKnowTypesMiscellaneous) { Name = containerClass.Name; Namespace = containerClass.ContainingNamespace.FullName(); @@ -28,7 +26,7 @@ internal ContainerInfo( CreateFunctionData = containerClass .GetAttributes() - .Where(ad => wellKnowTypes.CreateFunctionAttribute.Equals(ad.AttributeClass, SymbolEqualityComparer.Default)) + .Where(ad => wellKnowTypesMiscellaneous.CreateFunctionAttribute.Equals(ad.AttributeClass, SymbolEqualityComparer.Default)) .Select(ad => ad.ConstructorArguments.Length == 2 && ad.ConstructorArguments[0].Kind == TypedConstantKind.Type && ad.ConstructorArguments[0].Value is INamedTypeSymbol type diff --git a/Main/ExecuteImpl.cs b/Main/ExecuteImpl.cs index 0f7a4ec8..6edd8c92 100644 --- a/Main/ExecuteImpl.cs +++ b/Main/ExecuteImpl.cs @@ -12,7 +12,7 @@ internal interface IExecute internal class ExecuteImpl : IExecute { private readonly GeneratorExecutionContext _context; - private readonly WellKnownTypes _wellKnownTypes; + private readonly WellKnownTypesMiscellaneous _wellKnownTypesMiscellaneous; private readonly IContainerGenerator _containerGenerator; private readonly IContainerErrorGenerator _containerErrorGenerator; private readonly IContainerDieExceptionGenerator _containerDieExceptionGenerator; @@ -23,7 +23,7 @@ internal class ExecuteImpl : IExecute internal ExecuteImpl( GeneratorExecutionContext context, - WellKnownTypes wellKnownTypes, + WellKnownTypesMiscellaneous wellKnownTypesMiscellaneous, IContainerGenerator containerGenerator, IContainerErrorGenerator containerErrorGenerator, IContainerDieExceptionGenerator containerDieExceptionGenerator, @@ -33,7 +33,7 @@ internal ExecuteImpl( IDiagLogger diagLogger) { _context = context; - _wellKnownTypes = wellKnownTypes; + _wellKnownTypesMiscellaneous = wellKnownTypesMiscellaneous; _containerGenerator = containerGenerator; _containerErrorGenerator = containerErrorGenerator; _containerDieExceptionGenerator = containerDieExceptionGenerator; @@ -48,7 +48,7 @@ public void Execute() _diagLogger.Log("Start Execute"); var errorDescriptionInsteadOfBuildFailure = _context.Compilation.Assembly.GetAttributes() - .Any(ad => _wellKnownTypes.ErrorDescriptionInsteadOfBuildFailureAttribute.Equals(ad.AttributeClass, SymbolEqualityComparer.Default)); + .Any(ad => _wellKnownTypesMiscellaneous.ErrorDescriptionInsteadOfBuildFailureAttribute.Equals(ad.AttributeClass, SymbolEqualityComparer.Default)); foreach (var syntaxTree in _context.Compilation.SyntaxTrees) { @@ -60,7 +60,7 @@ public void Execute() .Select(x => semanticModel.GetDeclaredSymbol(x)) .Where(x => x is not null) .OfType() - .Where(x => x.GetAttributes().Any(ad => _wellKnownTypes.CreateFunctionAttribute.Equals(ad.AttributeClass, SymbolEqualityComparer.Default))) + .Where(x => x.GetAttributes().Any(ad => _wellKnownTypesMiscellaneous.CreateFunctionAttribute.Equals(ad.AttributeClass, SymbolEqualityComparer.Default))) .ToList(); foreach (var containerSymbol in containerClasses) { diff --git a/Main/ResolutionBuilding/ScopeManager.cs b/Main/ResolutionBuilding/ScopeManager.cs index 27f88ca0..d12c594e 100644 --- a/Main/ResolutionBuilding/ScopeManager.cs +++ b/Main/ResolutionBuilding/ScopeManager.cs @@ -73,7 +73,7 @@ public ScopeManager( Func, ICheckTypeProperties> checkTypePropertiesFactory, Func userProvidedScopeElementsFactory, IUserProvidedScopeElements emptyUserProvidedScopeElements, - WellKnownTypes wellKnownTypes) + WellKnownTypesMiscellaneous wellKnownTypesMiscellaneous) { _containerInfo = containerInfo; _containerResolutionBuilder = containerResolutionBuilder; @@ -128,7 +128,7 @@ defaultTransientScopeType is {} .SelectMany(nts => nts.GetAttributes() .Where(ad => SymbolEqualityComparer.Default.Equals(ad.AttributeClass, - wellKnownTypes.CustomScopeForRootTypesAttribute)) + wellKnownTypesMiscellaneous.CustomScopeForRootTypesAttribute)) .SelectMany(ad => ad .ConstructorArguments .SelectMany(tc => tc.Kind switch @@ -151,7 +151,7 @@ defaultTransientScopeType is {} .SelectMany(nts => nts.GetAttributes() .Where(ad => SymbolEqualityComparer.Default.Equals(ad.AttributeClass, - wellKnownTypes.CustomScopeForRootTypesAttribute)) + wellKnownTypesMiscellaneous.CustomScopeForRootTypesAttribute)) .SelectMany(ad => ad .ConstructorArguments .SelectMany(tc => tc.Kind switch diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index 4fdaec79..2ca906da 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -19,16 +19,23 @@ public void Execute(GeneratorExecutionContext context) { var diagLogger = new DiagLogger(context); var _ = WellKnownTypes.TryCreate(context.Compilation, out var wellKnownTypes); - var attributeTypesFromAttributes = new TypesFromAttributes(context.Compilation.Assembly.GetAttributes(), wellKnownTypes); + var __ = WellKnownTypesAggregation.TryCreate(context.Compilation, out var wellKnownTypesAggregation); + var ___ = WellKnownTypesChoice.TryCreate(context.Compilation, out var wellKnownTypesChoice); + var ____ = WellKnownTypesMiscellaneous.TryCreate(context.Compilation, out var wellKnownTypesMiscellaneous); + var attributeTypesFromAttributes = new TypesFromAttributes( + context.Compilation.Assembly.GetAttributes(), + wellKnownTypesAggregation, + wellKnownTypesChoice, + wellKnownTypesMiscellaneous); var containerGenerator = new ContainerGenerator(context, diagLogger, ContainerCodeBuilderFactory, TransientScopeCodeBuilderFactory, ScopeCodeBuilderFactory); var referenceGeneratorFactory = new ReferenceGeneratorFactory(ReferenceGeneratorFactory); var containerErrorGenerator = new ContainerErrorGenerator(context); - var containerDieExceptionGenerator = new ContainerDieExceptionGenerator(context, wellKnownTypes); + var containerDieExceptionGenerator = new ContainerDieExceptionGenerator(context, wellKnownTypesMiscellaneous); var resolutionTreeCreationErrorHarvester = new ResolutionTreeCreationErrorHarvester(); var implementationTypeSetCache = new ImplementationTypeSetCache(context, wellKnownTypes); new ExecuteImpl( context, - wellKnownTypes, + wellKnownTypesMiscellaneous, containerGenerator, containerErrorGenerator, containerDieExceptionGenerator, @@ -41,7 +48,11 @@ IContainerResolutionBuilder ResolutionTreeFactory(IContainerInfo ci) { var containerTypesFromAttributesList = ImmutableList.Create( (ITypesFromAttributes) attributeTypesFromAttributes, - new TypesFromAttributes(ci.ContainerType.GetAttributes(), wellKnownTypes)); + new TypesFromAttributes( + ci.ContainerType.GetAttributes(), + wellKnownTypesAggregation, + wellKnownTypesChoice, + wellKnownTypesMiscellaneous)); return new ContainerResolutionBuilder( ci, @@ -65,11 +76,15 @@ IScopeManager ScopeManagerFactory( containerTypesFromAttributesList, TransientScopeResolutionBuilderFactory, ScopeResolutionBuilderFactory, - ad => new ScopeTypesFromAttributes(ad, wellKnownTypes), + ad => new ScopeTypesFromAttributes( + ad, + wellKnownTypesAggregation, + wellKnownTypesChoice, + wellKnownTypesMiscellaneous), tfa => new CheckTypeProperties(new CurrentlyConsideredTypes(tfa, implementationTypeSetCache), wellKnownTypes), st => new UserProvidedScopeElements(st), new EmptyUserProvidedScopeElements(), - wellKnownTypes); + wellKnownTypesMiscellaneous); ITransientScopeResolutionBuilder TransientScopeResolutionBuilderFactory( string name, @@ -177,7 +192,7 @@ IRangedFunctionGroupResolutionBuilder RangedFunctionGroupResolutionBuilderFactor IFunctionResolutionSynchronicityDecisionMaker FunctionResolutionSynchronicityDecisionMakerFactory() => new FunctionResolutionSynchronicityDecisionMaker(); } - IContainerInfo ContainerInfoFactory(INamedTypeSymbol type) => new ContainerInfo(type, wellKnownTypes); + IContainerInfo ContainerInfoFactory(INamedTypeSymbol type) => new ContainerInfo(type, wellKnownTypesMiscellaneous); IReferenceGenerator ReferenceGeneratorFactory(int j) => new ReferenceGenerator(j); IContainerCodeBuilder ContainerCodeBuilderFactory( diff --git a/Main/WellKnownTypes.cs b/Main/WellKnownTypes.cs index 8ddca9a8..e1d13b28 100644 --- a/Main/WellKnownTypes.cs +++ b/Main/WellKnownTypes.cs @@ -1,55 +1,6 @@ -using System.Runtime.CompilerServices; -using MrMeeseeks.DIE.Configuration; -[assembly:InternalsVisibleTo("")] -namespace MrMeeseeks.DIE; +namespace MrMeeseeks.DIE; internal record WellKnownTypes( - INamedTypeSymbol ImplementationAggregationAttribute, - INamedTypeSymbol TransientAggregationAttribute, - INamedTypeSymbol SyncTransientAggregationAttribute, - INamedTypeSymbol AsyncTransientAggregationAttribute, - INamedTypeSymbol ContainerInstanceAggregationAttribute, - INamedTypeSymbol TransientScopeInstanceAggregationAttribute, - INamedTypeSymbol ScopeInstanceAggregationAttribute, - INamedTypeSymbol TransientScopeRootAggregationAttribute, - INamedTypeSymbol ScopeRootAggregationAttribute, - INamedTypeSymbol DecoratorAggregationAttribute, - INamedTypeSymbol CompositeAggregationAttribute, - INamedTypeSymbol GenericParameterSubstitutesChoiceAttribute, - INamedTypeSymbol GenericParameterChoiceAttribute, - INamedTypeSymbol DecoratorSequenceChoiceAttribute, - INamedTypeSymbol ConstructorChoiceAttribute, - INamedTypeSymbol PropertyChoiceAttribute, - INamedTypeSymbol TypeInitializerAttribute, - INamedTypeSymbol AllImplementationsAggregationAttribute, - INamedTypeSymbol AssemblyImplementationsAggregationAttribute, - INamedTypeSymbol ImplementationChoiceAttribute, - INamedTypeSymbol ImplementationCollectionChoiceAttribute, - INamedTypeSymbol FilterImplementationAggregationAttribute, - INamedTypeSymbol FilterTransientAggregationAttribute, - INamedTypeSymbol FilterSyncTransientAggregationAttribute, - INamedTypeSymbol FilterAsyncTransientAggregationAttribute, - INamedTypeSymbol FilterContainerInstanceAggregationAttribute, - INamedTypeSymbol FilterTransientScopeInstanceAggregationAttribute, - INamedTypeSymbol FilterScopeInstanceAggregationAttribute, - INamedTypeSymbol FilterTransientScopeRootAggregationAttribute, - INamedTypeSymbol FilterScopeRootAggregationAttribute, - INamedTypeSymbol FilterDecoratorAggregationAttribute, - INamedTypeSymbol FilterCompositeAggregationAttribute, - INamedTypeSymbol FilterGenericParameterSubstitutesChoiceAttribute, - INamedTypeSymbol FilterGenericParameterChoiceAttribute, - INamedTypeSymbol FilterDecoratorSequenceChoiceAttribute, - INamedTypeSymbol FilterConstructorChoiceAttribute, - INamedTypeSymbol FilterPropertyChoiceAttribute, - INamedTypeSymbol FilterTypeInitializerAttribute, - INamedTypeSymbol FilterAllImplementationsAggregationAttribute, - INamedTypeSymbol FilterAssemblyImplementationsAggregationAttribute, - INamedTypeSymbol FilterImplementationChoiceAttribute, - INamedTypeSymbol FilterImplementationCollectionChoiceAttribute, - INamedTypeSymbol CustomScopeForRootTypesAttribute, - INamedTypeSymbol CreateFunctionAttribute, - INamedTypeSymbol ErrorDescriptionInsteadOfBuildFailureAttribute, - INamedTypeSymbol DieExceptionKind, INamedTypeSymbol Disposable, INamedTypeSymbol AsyncDisposable, INamedTypeSymbol Lazy1, @@ -102,191 +53,7 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK var semaphoreSlim = compilation.GetTypeOrReport("System.Threading.SemaphoreSlim"); var internalsVisibleToAttribute = compilation.GetTypeOrReport("System.Runtime.CompilerServices.InternalsVisibleToAttribute"); - var implementationAggregationAttribute = compilation - .GetTypeByMetadataName(typeof(ImplementationAggregationAttribute).FullName ?? ""); - - var transientAggregationAttribute = compilation - .GetTypeByMetadataName(typeof(TransientAggregationAttribute).FullName ?? ""); - - var syncTransientAggregationAttribute = compilation - .GetTypeByMetadataName(typeof(SyncTransientAggregationAttribute).FullName ?? ""); - - var asyncTransientAggregationAttribute = compilation - .GetTypeByMetadataName(typeof(AsyncTransientAggregationAttribute).FullName ?? ""); - - var containerInstanceAggregationAttribute = compilation - .GetTypeByMetadataName(typeof(ContainerInstanceAggregationAttribute).FullName ?? ""); - - var transientScopeInstanceAggregationAttribute = compilation - .GetTypeByMetadataName(typeof(TransientScopeInstanceAggregationAttribute).FullName ?? ""); - - var scopeInstanceAggregationAttribute = compilation - .GetTypeByMetadataName(typeof(ScopeInstanceAggregationAttribute).FullName ?? ""); - - var transientScopeRootAggregationAttribute = compilation - .GetTypeByMetadataName(typeof(TransientScopeRootAggregationAttribute).FullName ?? ""); - - var scopeRootAggregationAttribute = compilation - .GetTypeByMetadataName(typeof(ScopeRootAggregationAttribute).FullName ?? ""); - - var decoratorAggregationAttribute = compilation - .GetTypeByMetadataName(typeof(DecoratorAggregationAttribute).FullName ?? ""); - - var compositeAggregationAttribute = compilation - .GetTypeByMetadataName(typeof(CompositeAggregationAttribute).FullName ?? ""); - - var genericParameterSubstitutesChoiceAttribute = compilation - .GetTypeByMetadataName(typeof(GenericParameterSubstitutesChoiceAttribute).FullName ?? ""); - - var filterGenericParameterSubstitutesChoiceAttribute = compilation - .GetTypeByMetadataName(typeof(FilterGenericParameterSubstitutesChoiceAttribute).FullName ?? ""); - - var genericParameterChoiceAttribute = compilation - .GetTypeByMetadataName(typeof(GenericParameterChoiceAttribute).FullName ?? ""); - - var filterGenericParameterChoiceAttribute = compilation - .GetTypeByMetadataName(typeof(FilterGenericParameterChoiceAttribute).FullName ?? ""); - - var decoratorSequenceChoiceAttribute = compilation - .GetTypeByMetadataName(typeof(DecoratorSequenceChoiceAttribute).FullName ?? ""); - - var constructorChoiceAttribute = compilation - .GetTypeByMetadataName(typeof(ConstructorChoiceAttribute).FullName ?? ""); - - var propertyChoiceAttribute = compilation - .GetTypeByMetadataName(typeof(PropertyChoiceAttribute).FullName ?? ""); - - var allImplementationsAggregationAttribute = compilation - .GetTypeByMetadataName(typeof(AllImplementationsAggregationAttribute).FullName ?? ""); - - var assemblyImplementationsAggregationAttribute = compilation - .GetTypeByMetadataName(typeof(AssemblyImplementationsAggregationAttribute).FullName ?? ""); - - var implementationChoiceAttribute = compilation - .GetTypeByMetadataName(typeof(ImplementationChoiceAttribute).FullName ?? ""); - - var implementationCollectionChoiceAttribute = compilation - .GetTypeByMetadataName(typeof(ImplementationCollectionChoiceAttribute).FullName ?? ""); - - var filterImplementationAggregationAttribute = compilation - .GetTypeByMetadataName(typeof(FilterImplementationAggregationAttribute).FullName ?? ""); - - var filterTransientAggregationAttribute = compilation - .GetTypeByMetadataName(typeof(FilterTransientAggregationAttribute).FullName ?? ""); - - var filterSyncTransientAggregationAttribute = compilation - .GetTypeByMetadataName(typeof(FilterSyncTransientAggregationAttribute).FullName ?? ""); - - var filterAsyncTransientAggregationAttribute = compilation - .GetTypeByMetadataName(typeof(FilterAsyncTransientAggregationAttribute).FullName ?? ""); - - var filterContainerInstanceAggregationAttribute = compilation - .GetTypeByMetadataName(typeof(FilterContainerInstanceAggregationAttribute).FullName ?? ""); - - var filterTransientScopeInstanceAggregationAttribute = compilation - .GetTypeByMetadataName(typeof(FilterTransientScopeInstanceAggregationAttribute).FullName ?? ""); - - var filterScopeInstanceAggregationAttribute = compilation - .GetTypeByMetadataName(typeof(FilterScopeInstanceAggregationAttribute).FullName ?? ""); - - var filterTransientScopeRootAggregationAttribute = compilation - .GetTypeByMetadataName(typeof(FilterTransientScopeRootAggregationAttribute).FullName ?? ""); - - var filterScopeRootAggregationAttribute = compilation - .GetTypeByMetadataName(typeof(FilterScopeRootAggregationAttribute).FullName ?? ""); - - var filterDecoratorAggregationAttribute = compilation - .GetTypeByMetadataName(typeof(FilterDecoratorAggregationAttribute).FullName ?? ""); - - var filterCompositeAggregationAttribute = compilation - .GetTypeByMetadataName(typeof(FilterCompositeAggregationAttribute).FullName ?? ""); - - var filterDecoratorSequenceChoiceAttribute = compilation - .GetTypeByMetadataName(typeof(FilterDecoratorSequenceChoiceAttribute).FullName ?? ""); - - var filterConstructorChoiceAttribute = compilation - .GetTypeByMetadataName(typeof(FilterConstructorChoiceAttribute).FullName ?? ""); - - var filterPropertyChoiceAttribute = compilation - .GetTypeByMetadataName(typeof(FilterPropertyChoiceAttribute).FullName ?? ""); - - var filterAllImplementationsAggregationAttribute = compilation - .GetTypeByMetadataName(typeof(FilterAllImplementationsAggregationAttribute).FullName ?? ""); - - var filterAssemblyImplementationsAggregationAttribute = compilation - .GetTypeByMetadataName(typeof(FilterAssemblyImplementationsAggregationAttribute).FullName ?? ""); - - var filterImplementationChoiceAttribute = compilation - .GetTypeByMetadataName(typeof(FilterImplementationChoiceAttribute).FullName ?? ""); - - var filterImplementationCollectionChoiceAttribute = compilation - .GetTypeByMetadataName(typeof(FilterImplementationCollectionChoiceAttribute).FullName ?? ""); - - var customScopeForRootTypesAttribute = compilation - .GetTypeByMetadataName(typeof(CustomScopeForRootTypesAttribute).FullName ?? ""); - - var typeInitializerAttribute = compilation - .GetTypeByMetadataName(typeof(TypeInitializerAttribute).FullName ?? ""); - - var filterTypeInitializerAttribute = compilation - .GetTypeByMetadataName(typeof(FilterTypeInitializerAttribute).FullName ?? ""); - - var createFunctionAttribute = compilation - .GetTypeByMetadataName(typeof(CreateFunctionAttribute).FullName ?? ""); - - var errorDescriptionInsteadOfBuildFailureAttribute = compilation - .GetTypeByMetadataName(typeof(ErrorDescriptionInsteadOfBuildFailureAttribute).FullName ?? ""); - - var dieExceptionKind = compilation - .GetTypeByMetadataName(typeof(DieExceptionKind).FullName ?? ""); - - if (implementationAggregationAttribute is not null - && transientAggregationAttribute is not null - && syncTransientAggregationAttribute is not null - && asyncTransientAggregationAttribute is not null - && containerInstanceAggregationAttribute is not null - && transientScopeInstanceAggregationAttribute is not null - && scopeInstanceAggregationAttribute is not null - && allImplementationsAggregationAttribute is not null - && assemblyImplementationsAggregationAttribute is not null - && implementationChoiceAttribute is not null - && implementationCollectionChoiceAttribute is not null - && transientScopeRootAggregationAttribute is not null - && scopeRootAggregationAttribute is not null - && decoratorAggregationAttribute is not null - && compositeAggregationAttribute is not null - && genericParameterSubstitutesChoiceAttribute is not null - && genericParameterChoiceAttribute is not null - && decoratorSequenceChoiceAttribute is not null - && constructorChoiceAttribute is not null - && propertyChoiceAttribute is not null - && typeInitializerAttribute is not null - && filterImplementationAggregationAttribute is not null - && filterTransientAggregationAttribute is not null - && filterSyncTransientAggregationAttribute is not null - && filterAsyncTransientAggregationAttribute is not null - && filterContainerInstanceAggregationAttribute is not null - && filterTransientScopeInstanceAggregationAttribute is not null - && filterScopeInstanceAggregationAttribute is not null - && filterTransientScopeRootAggregationAttribute is not null - && filterScopeRootAggregationAttribute is not null - && filterDecoratorAggregationAttribute is not null - && filterCompositeAggregationAttribute is not null - && filterGenericParameterSubstitutesChoiceAttribute is not null - && filterGenericParameterChoiceAttribute is not null - && filterDecoratorSequenceChoiceAttribute is not null - && filterConstructorChoiceAttribute is not null - && filterPropertyChoiceAttribute is not null - && filterTypeInitializerAttribute is not null - && filterAllImplementationsAggregationAttribute is not null - && filterAssemblyImplementationsAggregationAttribute is not null - && filterImplementationChoiceAttribute is not null - && filterImplementationCollectionChoiceAttribute is not null - && customScopeForRootTypesAttribute is not null - && createFunctionAttribute is not null - && errorDescriptionInsteadOfBuildFailureAttribute is not null - && dieExceptionKind is not null - && iDisposable is not null + if (iDisposable is not null && iAsyncDisposable is not null && lazy1 is not null && valueTask is not null @@ -308,52 +75,6 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypes wellK { wellKnownTypes = new WellKnownTypes( - ImplementationAggregationAttribute: implementationAggregationAttribute, - TransientAggregationAttribute: transientAggregationAttribute, - SyncTransientAggregationAttribute: syncTransientAggregationAttribute, - AsyncTransientAggregationAttribute: asyncTransientAggregationAttribute, - ContainerInstanceAggregationAttribute: containerInstanceAggregationAttribute, - TransientScopeInstanceAggregationAttribute: transientScopeInstanceAggregationAttribute, - ScopeInstanceAggregationAttribute: scopeInstanceAggregationAttribute, - TransientScopeRootAggregationAttribute: transientScopeRootAggregationAttribute, - ScopeRootAggregationAttribute: scopeRootAggregationAttribute, - DecoratorAggregationAttribute: decoratorAggregationAttribute, - CompositeAggregationAttribute: compositeAggregationAttribute, - AllImplementationsAggregationAttribute: allImplementationsAggregationAttribute, - AssemblyImplementationsAggregationAttribute: assemblyImplementationsAggregationAttribute, - ImplementationChoiceAttribute: implementationChoiceAttribute, - ImplementationCollectionChoiceAttribute: implementationCollectionChoiceAttribute, - GenericParameterSubstitutesChoiceAttribute: genericParameterSubstitutesChoiceAttribute, - GenericParameterChoiceAttribute: genericParameterChoiceAttribute, - DecoratorSequenceChoiceAttribute: decoratorSequenceChoiceAttribute, - ConstructorChoiceAttribute: constructorChoiceAttribute, - PropertyChoiceAttribute: propertyChoiceAttribute, - TypeInitializerAttribute: typeInitializerAttribute, - FilterImplementationAggregationAttribute: filterImplementationAggregationAttribute, - FilterTransientAggregationAttribute: filterTransientAggregationAttribute, - FilterSyncTransientAggregationAttribute: filterSyncTransientAggregationAttribute, - FilterAsyncTransientAggregationAttribute: filterAsyncTransientAggregationAttribute, - FilterContainerInstanceAggregationAttribute: filterContainerInstanceAggregationAttribute, - FilterTransientScopeInstanceAggregationAttribute: filterTransientScopeInstanceAggregationAttribute, - FilterScopeInstanceAggregationAttribute: filterScopeInstanceAggregationAttribute, - FilterTransientScopeRootAggregationAttribute: filterTransientScopeRootAggregationAttribute, - FilterScopeRootAggregationAttribute: filterScopeRootAggregationAttribute, - FilterDecoratorAggregationAttribute: filterDecoratorAggregationAttribute, - FilterCompositeAggregationAttribute: filterCompositeAggregationAttribute, - FilterGenericParameterSubstitutesChoiceAttribute: filterGenericParameterSubstitutesChoiceAttribute, - FilterGenericParameterChoiceAttribute: filterGenericParameterChoiceAttribute, - FilterDecoratorSequenceChoiceAttribute: filterDecoratorSequenceChoiceAttribute, - FilterConstructorChoiceAttribute: filterConstructorChoiceAttribute, - FilterPropertyChoiceAttribute: filterPropertyChoiceAttribute, - FilterTypeInitializerAttribute: filterTypeInitializerAttribute, - FilterAllImplementationsAggregationAttribute: filterAllImplementationsAggregationAttribute, - FilterAssemblyImplementationsAggregationAttribute: filterAssemblyImplementationsAggregationAttribute, - FilterImplementationChoiceAttribute: filterImplementationChoiceAttribute, - FilterImplementationCollectionChoiceAttribute: filterImplementationCollectionChoiceAttribute, - CustomScopeForRootTypesAttribute: customScopeForRootTypesAttribute, - CreateFunctionAttribute: createFunctionAttribute, - ErrorDescriptionInsteadOfBuildFailureAttribute: errorDescriptionInsteadOfBuildFailureAttribute, - DieExceptionKind: dieExceptionKind, Disposable: iDisposable, AsyncDisposable: iAsyncDisposable, Lazy1: lazy1, diff --git a/Main/WellKnownTypesAggregation.cs b/Main/WellKnownTypesAggregation.cs new file mode 100644 index 00000000..9abef691 --- /dev/null +++ b/Main/WellKnownTypesAggregation.cs @@ -0,0 +1,182 @@ +using MrMeeseeks.DIE.Configuration.Attributes; + +namespace MrMeeseeks.DIE; + +internal record WellKnownTypesAggregation( + INamedTypeSymbol ImplementationAggregationAttribute, + INamedTypeSymbol TransientAbstractionAggregationAttribute, + INamedTypeSymbol SyncTransientAbstractionAggregationAttribute, + INamedTypeSymbol AsyncTransientAbstractionAggregationAttribute, + INamedTypeSymbol ContainerInstanceAbstractionAggregationAttribute, + INamedTypeSymbol TransientScopeInstanceAbstractionAggregationAttribute, + INamedTypeSymbol ScopeInstanceAbstractionAggregationAttribute, + INamedTypeSymbol TransientScopeRootAbstractionAggregationAttribute, + INamedTypeSymbol ScopeRootAbstractionAggregationAttribute, + INamedTypeSymbol DecoratorAbstractionAggregationAttribute, + INamedTypeSymbol CompositeAbstractionAggregationAttribute, + INamedTypeSymbol AllImplementationsAggregationAttribute, + INamedTypeSymbol AssemblyImplementationsAggregationAttribute, + INamedTypeSymbol FilterImplementationAggregationAttribute, + INamedTypeSymbol FilterTransientAbstractionAggregationAttribute, + INamedTypeSymbol FilterSyncTransientAbstractionAggregationAttribute, + INamedTypeSymbol FilterAsyncTransientAbstractionAggregationAttribute, + INamedTypeSymbol FilterContainerInstanceAbstractionAggregationAttribute, + INamedTypeSymbol FilterTransientScopeInstanceAbstractionAggregationAttribute, + INamedTypeSymbol FilterScopeInstanceAbstractionAggregationAttribute, + INamedTypeSymbol FilterTransientScopeRootAbstractionAggregationAttribute, + INamedTypeSymbol FilterScopeRootAbstractionAggregationAttribute, + INamedTypeSymbol FilterDecoratorAbstractionAggregationAttribute, + INamedTypeSymbol FilterCompositeAbstractionAggregationAttribute, + INamedTypeSymbol FilterAllImplementationsAggregationAttribute, + INamedTypeSymbol FilterAssemblyImplementationsAggregationAttribute) +{ + internal static bool TryCreate(Compilation compilation, out WellKnownTypesAggregation wellKnownTypes) + { + var implementationAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(ImplementationAggregationAttribute).FullName ?? ""); + + var transientAbstractionAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(TransientAbstractionAggregationAttribute).FullName ?? ""); + + var syncTransientAbstractionAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(SyncTransientAbstractionAggregationAttribute).FullName ?? ""); + + var asyncTransientAbstractionAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(AsyncTransientAbstractionAggregationAttribute).FullName ?? ""); + + var containerInstanceAbstractionAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(ContainerInstanceAbstractionAggregationAttribute).FullName ?? ""); + + var transientScopeInstanceAbstractionAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(TransientScopeInstanceAbstractionAggregationAttribute).FullName ?? ""); + + var scopeInstanceAbstractionAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(ScopeInstanceAbstractionAggregationAttribute).FullName ?? ""); + + var transientScopeRootAbstractionAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(TransientScopeRootAbstractionAggregationAttribute).FullName ?? ""); + + var scopeRootAbstractionAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(ScopeRootAbstractionAggregationAttribute).FullName ?? ""); + + var decoratorAbstractionAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(DecoratorAbstractionAggregationAttribute).FullName ?? ""); + + var compositeAbstractionAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(CompositeAbstractionAggregationAttribute).FullName ?? ""); + + var allImplementationsAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(AllImplementationsAggregationAttribute).FullName ?? ""); + + var assemblyImplementationsAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(AssemblyImplementationsAggregationAttribute).FullName ?? ""); + + var implementationChoiceAttribute = compilation + .GetTypeByMetadataName(typeof(ImplementationChoiceAttribute).FullName ?? ""); + + var implementationCollectionChoiceAttribute = compilation + .GetTypeByMetadataName(typeof(ImplementationCollectionChoiceAttribute).FullName ?? ""); + + var filterImplementationAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(FilterImplementationAggregationAttribute).FullName ?? ""); + + var filterTransientAbstractionAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(FilterTransientAbstractionAggregationAttribute).FullName ?? ""); + + var filterSyncTransientAbstractionAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(FilterSyncTransientAbstractionAggregationAttribute).FullName ?? ""); + + var filterAsyncTransientAbstractionAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(FilterAsyncTransientAbstractionAggregationAttribute).FullName ?? ""); + + var filterContainerInstanceAbstractionAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(FilterContainerInstanceAbstractionAggregationAttribute).FullName ?? ""); + + var filterTransientScopeInstanceAbstractionAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(FilterTransientScopeInstanceAbstractionAggregationAttribute).FullName ?? ""); + + var filterScopeInstanceAggregationAbstractionAttribute = compilation + .GetTypeByMetadataName(typeof(FilterScopeInstanceAbstractionAggregationAttribute).FullName ?? ""); + + var filterTransientScopeRootAggregationAbstractionAttribute = compilation + .GetTypeByMetadataName(typeof(FilterTransientScopeRootAbstractionAggregationAttribute).FullName ?? ""); + + var filterScopeRootAbstractionAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(FilterScopeRootAbstractionAggregationAttribute).FullName ?? ""); + + var filterDecoratorAbstractionAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(FilterDecoratorAbstractionAggregationAttribute).FullName ?? ""); + + var filterCompositeAbstractionAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(FilterCompositeAbstractionAggregationAttribute).FullName ?? ""); + + var filterAllImplementationsAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(FilterAllImplementationsAggregationAttribute).FullName ?? ""); + + var filterAssemblyImplementationsAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(FilterAssemblyImplementationsAggregationAttribute).FullName ?? ""); + + if (implementationAggregationAttribute is not null + && transientAbstractionAggregationAttribute is not null + && syncTransientAbstractionAggregationAttribute is not null + && asyncTransientAbstractionAggregationAttribute is not null + && containerInstanceAbstractionAggregationAttribute is not null + && transientScopeInstanceAbstractionAggregationAttribute is not null + && scopeInstanceAbstractionAggregationAttribute is not null + && allImplementationsAggregationAttribute is not null + && assemblyImplementationsAggregationAttribute is not null + && implementationChoiceAttribute is not null + && implementationCollectionChoiceAttribute is not null + && transientScopeRootAbstractionAggregationAttribute is not null + && scopeRootAbstractionAggregationAttribute is not null + && decoratorAbstractionAggregationAttribute is not null + && compositeAbstractionAggregationAttribute is not null + && filterImplementationAggregationAttribute is not null + && filterTransientAbstractionAggregationAttribute is not null + && filterSyncTransientAbstractionAggregationAttribute is not null + && filterAsyncTransientAbstractionAggregationAttribute is not null + && filterContainerInstanceAbstractionAggregationAttribute is not null + && filterTransientScopeInstanceAbstractionAggregationAttribute is not null + && filterScopeInstanceAggregationAbstractionAttribute is not null + && filterTransientScopeRootAggregationAbstractionAttribute is not null + && filterScopeRootAbstractionAggregationAttribute is not null + && filterDecoratorAbstractionAggregationAttribute is not null + && filterCompositeAbstractionAggregationAttribute is not null + && filterAllImplementationsAggregationAttribute is not null + && filterAssemblyImplementationsAggregationAttribute is not null) + { + + wellKnownTypes = new WellKnownTypesAggregation( + ImplementationAggregationAttribute: implementationAggregationAttribute, + TransientAbstractionAggregationAttribute: transientAbstractionAggregationAttribute, + SyncTransientAbstractionAggregationAttribute: syncTransientAbstractionAggregationAttribute, + AsyncTransientAbstractionAggregationAttribute: asyncTransientAbstractionAggregationAttribute, + ContainerInstanceAbstractionAggregationAttribute: containerInstanceAbstractionAggregationAttribute, + TransientScopeInstanceAbstractionAggregationAttribute: transientScopeInstanceAbstractionAggregationAttribute, + ScopeInstanceAbstractionAggregationAttribute: scopeInstanceAbstractionAggregationAttribute, + TransientScopeRootAbstractionAggregationAttribute: transientScopeRootAbstractionAggregationAttribute, + ScopeRootAbstractionAggregationAttribute: scopeRootAbstractionAggregationAttribute, + DecoratorAbstractionAggregationAttribute: decoratorAbstractionAggregationAttribute, + CompositeAbstractionAggregationAttribute: compositeAbstractionAggregationAttribute, + AllImplementationsAggregationAttribute: allImplementationsAggregationAttribute, + AssemblyImplementationsAggregationAttribute: assemblyImplementationsAggregationAttribute, + FilterImplementationAggregationAttribute: filterImplementationAggregationAttribute, + FilterTransientAbstractionAggregationAttribute: filterTransientAbstractionAggregationAttribute, + FilterSyncTransientAbstractionAggregationAttribute: filterSyncTransientAbstractionAggregationAttribute, + FilterAsyncTransientAbstractionAggregationAttribute: filterAsyncTransientAbstractionAggregationAttribute, + FilterContainerInstanceAbstractionAggregationAttribute: filterContainerInstanceAbstractionAggregationAttribute, + FilterTransientScopeInstanceAbstractionAggregationAttribute: filterTransientScopeInstanceAbstractionAggregationAttribute, + FilterScopeInstanceAbstractionAggregationAttribute: filterScopeInstanceAggregationAbstractionAttribute, + FilterTransientScopeRootAbstractionAggregationAttribute: filterTransientScopeRootAggregationAbstractionAttribute, + FilterScopeRootAbstractionAggregationAttribute: filterScopeRootAbstractionAggregationAttribute, + FilterDecoratorAbstractionAggregationAttribute: filterDecoratorAbstractionAggregationAttribute, + FilterCompositeAbstractionAggregationAttribute: filterCompositeAbstractionAggregationAttribute, + FilterAllImplementationsAggregationAttribute: filterAllImplementationsAggregationAttribute, + FilterAssemblyImplementationsAggregationAttribute: filterAssemblyImplementationsAggregationAttribute); + return true; + } + + wellKnownTypes = null!; + return false; + } +} \ No newline at end of file diff --git a/Main/WellKnownTypesChoice.cs b/Main/WellKnownTypesChoice.cs new file mode 100644 index 00000000..5ccf73e6 --- /dev/null +++ b/Main/WellKnownTypesChoice.cs @@ -0,0 +1,103 @@ +using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; + +namespace MrMeeseeks.DIE; + +internal record WellKnownTypesChoice( + INamedTypeSymbol GenericParameterSubstitutesChoiceAttribute, + INamedTypeSymbol GenericParameterChoiceAttribute, + INamedTypeSymbol DecoratorSequenceChoiceAttribute, + INamedTypeSymbol ConstructorChoiceAttribute, + INamedTypeSymbol PropertyChoiceAttribute, + INamedTypeSymbol ImplementationChoiceAttribute, + INamedTypeSymbol ImplementationCollectionChoiceAttribute, + INamedTypeSymbol FilterGenericParameterSubstitutesChoiceAttribute, + INamedTypeSymbol FilterGenericParameterChoiceAttribute, + INamedTypeSymbol FilterDecoratorSequenceChoiceAttribute, + INamedTypeSymbol FilterConstructorChoiceAttribute, + INamedTypeSymbol FilterPropertyChoiceAttribute, + INamedTypeSymbol FilterImplementationChoiceAttribute, + INamedTypeSymbol FilterImplementationCollectionChoiceAttribute) +{ + internal static bool TryCreate(Compilation compilation, out WellKnownTypesChoice wellKnownTypes) + { + var genericParameterSubstitutesChoiceAttribute = compilation + .GetTypeByMetadataName(typeof(GenericParameterSubstitutesChoiceAttribute).FullName ?? ""); + + var filterGenericParameterSubstitutesChoiceAttribute = compilation + .GetTypeByMetadataName(typeof(FilterGenericParameterSubstitutesChoiceAttribute).FullName ?? ""); + + var genericParameterChoiceAttribute = compilation + .GetTypeByMetadataName(typeof(GenericParameterChoiceAttribute).FullName ?? ""); + + var filterGenericParameterChoiceAttribute = compilation + .GetTypeByMetadataName(typeof(FilterGenericParameterChoiceAttribute).FullName ?? ""); + + var decoratorSequenceChoiceAttribute = compilation + .GetTypeByMetadataName(typeof(DecoratorSequenceChoiceAttribute).FullName ?? ""); + + var constructorChoiceAttribute = compilation + .GetTypeByMetadataName(typeof(ConstructorChoiceAttribute).FullName ?? ""); + + var propertyChoiceAttribute = compilation + .GetTypeByMetadataName(typeof(PropertyChoiceAttribute).FullName ?? ""); + + var implementationChoiceAttribute = compilation + .GetTypeByMetadataName(typeof(ImplementationChoiceAttribute).FullName ?? ""); + + var implementationCollectionChoiceAttribute = compilation + .GetTypeByMetadataName(typeof(ImplementationCollectionChoiceAttribute).FullName ?? ""); + + var filterDecoratorSequenceChoiceAttribute = compilation + .GetTypeByMetadataName(typeof(FilterDecoratorSequenceChoiceAttribute).FullName ?? ""); + + var filterConstructorChoiceAttribute = compilation + .GetTypeByMetadataName(typeof(FilterConstructorChoiceAttribute).FullName ?? ""); + + var filterPropertyChoiceAttribute = compilation + .GetTypeByMetadataName(typeof(FilterPropertyChoiceAttribute).FullName ?? ""); + + var filterImplementationChoiceAttribute = compilation + .GetTypeByMetadataName(typeof(FilterImplementationChoiceAttribute).FullName ?? ""); + + var filterImplementationCollectionChoiceAttribute = compilation + .GetTypeByMetadataName(typeof(FilterImplementationCollectionChoiceAttribute).FullName ?? ""); + + if (implementationChoiceAttribute is not null + && implementationCollectionChoiceAttribute is not null + && genericParameterSubstitutesChoiceAttribute is not null + && genericParameterChoiceAttribute is not null + && decoratorSequenceChoiceAttribute is not null + && constructorChoiceAttribute is not null + && propertyChoiceAttribute is not null + && filterGenericParameterSubstitutesChoiceAttribute is not null + && filterGenericParameterChoiceAttribute is not null + && filterDecoratorSequenceChoiceAttribute is not null + && filterConstructorChoiceAttribute is not null + && filterPropertyChoiceAttribute is not null + && filterImplementationChoiceAttribute is not null + && filterImplementationCollectionChoiceAttribute is not null) + { + + wellKnownTypes = new WellKnownTypesChoice( + ImplementationChoiceAttribute: implementationChoiceAttribute, + ImplementationCollectionChoiceAttribute: implementationCollectionChoiceAttribute, + GenericParameterSubstitutesChoiceAttribute: genericParameterSubstitutesChoiceAttribute, + GenericParameterChoiceAttribute: genericParameterChoiceAttribute, + DecoratorSequenceChoiceAttribute: decoratorSequenceChoiceAttribute, + ConstructorChoiceAttribute: constructorChoiceAttribute, + PropertyChoiceAttribute: propertyChoiceAttribute, + FilterGenericParameterSubstitutesChoiceAttribute: filterGenericParameterSubstitutesChoiceAttribute, + FilterGenericParameterChoiceAttribute: filterGenericParameterChoiceAttribute, + FilterDecoratorSequenceChoiceAttribute: filterDecoratorSequenceChoiceAttribute, + FilterConstructorChoiceAttribute: filterConstructorChoiceAttribute, + FilterPropertyChoiceAttribute: filterPropertyChoiceAttribute, + FilterImplementationChoiceAttribute: filterImplementationChoiceAttribute, + FilterImplementationCollectionChoiceAttribute: filterImplementationCollectionChoiceAttribute); + return true; + } + + wellKnownTypes = null!; + return false; + } +} \ No newline at end of file diff --git a/Main/WellKnownTypesMiscellaneous.cs b/Main/WellKnownTypesMiscellaneous.cs new file mode 100644 index 00000000..93842204 --- /dev/null +++ b/Main/WellKnownTypesMiscellaneous.cs @@ -0,0 +1,55 @@ +using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; + +namespace MrMeeseeks.DIE; + +internal record WellKnownTypesMiscellaneous( + INamedTypeSymbol TypeInitializerAttribute, + INamedTypeSymbol FilterTypeInitializerAttribute, + INamedTypeSymbol CustomScopeForRootTypesAttribute, + INamedTypeSymbol CreateFunctionAttribute, + INamedTypeSymbol ErrorDescriptionInsteadOfBuildFailureAttribute, + INamedTypeSymbol DieExceptionKind) +{ + internal static bool TryCreate(Compilation compilation, out WellKnownTypesMiscellaneous wellKnownTypes) + { + var customScopeForRootTypesAttribute = compilation + .GetTypeByMetadataName(typeof(CustomScopeForRootTypesAttribute).FullName ?? ""); + + var typeInitializerAttribute = compilation + .GetTypeByMetadataName(typeof(TypeInitializerAttribute).FullName ?? ""); + + var filterTypeInitializerAttribute = compilation + .GetTypeByMetadataName(typeof(FilterTypeInitializerAttribute).FullName ?? ""); + + var createFunctionAttribute = compilation + .GetTypeByMetadataName(typeof(CreateFunctionAttribute).FullName ?? ""); + + var errorDescriptionInsteadOfBuildFailureAttribute = compilation + .GetTypeByMetadataName(typeof(ErrorDescriptionInsteadOfBuildFailureAttribute).FullName ?? ""); + + var dieExceptionKind = compilation + .GetTypeByMetadataName(typeof(DieExceptionKind).FullName ?? ""); + + if (typeInitializerAttribute is not null + && filterTypeInitializerAttribute is not null + && customScopeForRootTypesAttribute is not null + && createFunctionAttribute is not null + && errorDescriptionInsteadOfBuildFailureAttribute is not null + && dieExceptionKind is not null) + { + + wellKnownTypes = new WellKnownTypesMiscellaneous( + TypeInitializerAttribute: typeInitializerAttribute, + FilterTypeInitializerAttribute: filterTypeInitializerAttribute, + CustomScopeForRootTypesAttribute: customScopeForRootTypesAttribute, + CreateFunctionAttribute: createFunctionAttribute, + ErrorDescriptionInsteadOfBuildFailureAttribute: errorDescriptionInsteadOfBuildFailureAttribute, + DieExceptionKind: dieExceptionKind); + return true; + } + + wellKnownTypes = null!; + return false; + } +} \ No newline at end of file diff --git a/Sample/Container.cs b/Sample/Container.cs index e6d9f8d0..e5b0f411 100644 --- a/Sample/Container.cs +++ b/Sample/Container.cs @@ -1,16 +1,16 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using MrMeeseeks.DIE.Sample; -[assembly:ContainerInstanceAggregation(typeof(IContainerInstance))] -[assembly:TransientScopeInstanceAggregation(typeof(ITransientScopeInstance))] -[assembly:ScopeInstanceAggregation(typeof(IScopeInstance))] -[assembly:TransientScopeRootAggregation(typeof(ITransientScopeRoot))] -[assembly:ScopeRootAggregation(typeof(IScopeRoot))] -[assembly:TransientAggregation(typeof(ITransient))] -[assembly:SyncTransientAggregation(typeof(ISyncTransient))] -[assembly:AsyncTransientAggregation(typeof(IAsyncTransient))] -[assembly:DecoratorAggregation(typeof(IDecorator<>))] -[assembly:CompositeAggregation(typeof(IComposite<>))] +[assembly:ContainerInstanceAbstractionAggregation(typeof(IContainerInstance))] +[assembly:TransientScopeInstanceAbstractionAggregation(typeof(ITransientScopeInstance))] +[assembly:ScopeInstanceAbstractionAggregation(typeof(IScopeInstance))] +[assembly:TransientScopeRootAbstractionAggregation(typeof(ITransientScopeRoot))] +[assembly:ScopeRootAbstractionAggregation(typeof(IScopeRoot))] +[assembly:TransientAbstractionAggregation(typeof(ITransient))] +[assembly:SyncTransientAbstractionAggregation(typeof(ISyncTransient))] +[assembly:AsyncTransientAbstractionAggregation(typeof(IAsyncTransient))] +[assembly:DecoratorAbstractionAggregation(typeof(IDecorator<>))] +[assembly:CompositeAbstractionAggregation(typeof(IComposite<>))] [assembly:TypeInitializer(typeof(ITypeInitializer), nameof(ITypeInitializer.Initialize))] [assembly:TypeInitializer(typeof(ITaskTypeInitializer), nameof(ITaskTypeInitializer.InitializeAsync))] [assembly:TypeInitializer(typeof(IValueTaskTypeInitializer), nameof(IValueTaskTypeInitializer.InitializeAsync))] diff --git a/Sample/Context.cs b/Sample/Context.cs index 853e9e90..e67f6241 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; namespace MrMeeseeks.DIE.Test.CycleDetection.Implementation; diff --git a/Test/AssemblyInfo.cs b/Test/AssemblyInfo.cs index 2f0a6533..bf61ebde 100644 --- a/Test/AssemblyInfo.cs +++ b/Test/AssemblyInfo.cs @@ -1,16 +1,16 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using MrMeeseeks.DIE.Test; -[assembly:ContainerInstanceAggregation(typeof(IContainerInstance))] -[assembly:TransientScopeInstanceAggregation(typeof(ITransientScopeInstance))] -[assembly:ScopeInstanceAggregation(typeof(IScopeInstance))] -[assembly:TransientScopeRootAggregation(typeof(ITransientScopeRoot))] -[assembly:ScopeRootAggregation(typeof(IScopeRoot))] -[assembly:TransientAggregation(typeof(ITransient))] -[assembly:SyncTransientAggregation(typeof(ISyncTransient))] -[assembly:AsyncTransientAggregation(typeof(IAsyncTransient))] -[assembly:DecoratorAggregation(typeof(IDecorator<>))] -[assembly:CompositeAggregation(typeof(IComposite<>))] +[assembly:ContainerInstanceAbstractionAggregation(typeof(IContainerInstance))] +[assembly:TransientScopeInstanceAbstractionAggregation(typeof(ITransientScopeInstance))] +[assembly:ScopeInstanceAbstractionAggregation(typeof(IScopeInstance))] +[assembly:TransientScopeRootAbstractionAggregation(typeof(ITransientScopeRoot))] +[assembly:ScopeRootAbstractionAggregation(typeof(IScopeRoot))] +[assembly:TransientAbstractionAggregation(typeof(ITransient))] +[assembly:SyncTransientAbstractionAggregation(typeof(ISyncTransient))] +[assembly:AsyncTransientAbstractionAggregation(typeof(IAsyncTransient))] +[assembly:DecoratorAbstractionAggregation(typeof(IDecorator<>))] +[assembly:CompositeAbstractionAggregation(typeof(IComposite<>))] [assembly:TypeInitializer(typeof(ITypeInitializer), nameof(ITypeInitializer.Initialize))] [assembly:TypeInitializer(typeof(ITaskTypeInitializer), nameof(ITaskTypeInitializer.InitializeAsync))] [assembly:TypeInitializer(typeof(IValueTaskTypeInitializer), nameof(IValueTaskTypeInitializer.InitializeAsync))] diff --git a/Test/Async/Awaited/AsyncScopeRootCallAsTask.cs b/Test/Async/Awaited/AsyncScopeRootCallAsTask.cs index edf104e6..1e905283 100644 --- a/Test/Async/Awaited/AsyncScopeRootCallAsTask.cs +++ b/Test/Async/Awaited/AsyncScopeRootCallAsTask.cs @@ -1,5 +1,5 @@ using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Async.Awaited.AsyncScopeRootCallAsTask; diff --git a/Test/Async/Awaited/AsyncScopeRootCallAsValueTask.cs b/Test/Async/Awaited/AsyncScopeRootCallAsValueTask.cs index f66179cc..74253960 100644 --- a/Test/Async/Awaited/AsyncScopeRootCallAsValueTask.cs +++ b/Test/Async/Awaited/AsyncScopeRootCallAsValueTask.cs @@ -1,5 +1,5 @@ using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Async.Awaited.AsyncScopeRootCallAsValueTask; diff --git a/Test/Async/Awaited/AsyncScopeRootCallAwaited.cs b/Test/Async/Awaited/AsyncScopeRootCallAwaited.cs index dc38a611..de20eb02 100644 --- a/Test/Async/Awaited/AsyncScopeRootCallAwaited.cs +++ b/Test/Async/Awaited/AsyncScopeRootCallAwaited.cs @@ -1,5 +1,5 @@ using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Async.Awaited.AsyncScopeRootCallAwaited; diff --git a/Test/Async/Awaited/ContainerInstanceFunctionAsTask.cs b/Test/Async/Awaited/ContainerInstanceFunctionAsTask.cs index cb249d24..051ec2b8 100644 --- a/Test/Async/Awaited/ContainerInstanceFunctionAsTask.cs +++ b/Test/Async/Awaited/ContainerInstanceFunctionAsTask.cs @@ -1,5 +1,5 @@ using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Async.Awaited.ContainerInstanceFunctionAsTask; diff --git a/Test/Async/Awaited/ContainerInstanceFunctionAsValueTask.cs b/Test/Async/Awaited/ContainerInstanceFunctionAsValueTask.cs index 94e22163..2398397a 100644 --- a/Test/Async/Awaited/ContainerInstanceFunctionAsValueTask.cs +++ b/Test/Async/Awaited/ContainerInstanceFunctionAsValueTask.cs @@ -1,5 +1,5 @@ using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Async.Awaited.ContainerInstanceFunctionAsValueTask; diff --git a/Test/Async/Awaited/ScopeInstanceFunctionAsTask.cs b/Test/Async/Awaited/ScopeInstanceFunctionAsTask.cs index 268e9c88..1fb5eae1 100644 --- a/Test/Async/Awaited/ScopeInstanceFunctionAsTask.cs +++ b/Test/Async/Awaited/ScopeInstanceFunctionAsTask.cs @@ -1,5 +1,5 @@ using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Async.Awaited.ScopeInstanceFunctionAsTask; diff --git a/Test/Async/Awaited/ScopeInstanceFunctionAsValueTask.cs b/Test/Async/Awaited/ScopeInstanceFunctionAsValueTask.cs index 7868d08e..2dfbe5fa 100644 --- a/Test/Async/Awaited/ScopeInstanceFunctionAsValueTask.cs +++ b/Test/Async/Awaited/ScopeInstanceFunctionAsValueTask.cs @@ -1,5 +1,5 @@ using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Async.Awaited.ScopeInstanceFunctionAsValueTask; diff --git a/Test/Async/Awaited/TaskTypeInitializerTask.cs b/Test/Async/Awaited/TaskTypeInitializerTask.cs index 5012db68..8724eb13 100644 --- a/Test/Async/Awaited/TaskTypeInitializerTask.cs +++ b/Test/Async/Awaited/TaskTypeInitializerTask.cs @@ -1,5 +1,5 @@ using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Async.Awaited.TaskTypeInitializerTask; diff --git a/Test/Async/Awaited/TaskTypeInitializerValueTask.cs b/Test/Async/Awaited/TaskTypeInitializerValueTask.cs index 64a09226..c5f7c28c 100644 --- a/Test/Async/Awaited/TaskTypeInitializerValueTask.cs +++ b/Test/Async/Awaited/TaskTypeInitializerValueTask.cs @@ -1,5 +1,5 @@ using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Async.Awaited.TaskTypeInitializerValueTask; diff --git a/Test/Async/Awaited/TransientScopeInstanceFunctionAsTask.cs b/Test/Async/Awaited/TransientScopeInstanceFunctionAsTask.cs index aea93a17..2a8f07bb 100644 --- a/Test/Async/Awaited/TransientScopeInstanceFunctionAsTask.cs +++ b/Test/Async/Awaited/TransientScopeInstanceFunctionAsTask.cs @@ -1,5 +1,5 @@ using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Async.Awaited.TransientScopeInstanceFunctionAsTask; diff --git a/Test/Async/Awaited/TransientScopeInstanceFunctionAsValueTask.cs b/Test/Async/Awaited/TransientScopeInstanceFunctionAsValueTask.cs index d956e93a..95366f22 100644 --- a/Test/Async/Awaited/TransientScopeInstanceFunctionAsValueTask.cs +++ b/Test/Async/Awaited/TransientScopeInstanceFunctionAsValueTask.cs @@ -1,5 +1,5 @@ using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Async.Awaited.TransientScopeInstanceFunctionAsValueTask; diff --git a/Test/Async/Awaited/TransientScopeInstanceFunction_DifferentSynchronicity.cs b/Test/Async/Awaited/TransientScopeInstanceFunction_DifferentSynchronicity.cs index e7ef889c..3b14c8e1 100644 --- a/Test/Async/Awaited/TransientScopeInstanceFunction_DifferentSynchronicity.cs +++ b/Test/Async/Awaited/TransientScopeInstanceFunction_DifferentSynchronicity.cs @@ -1,5 +1,5 @@ using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Async.Awaited.TransientScopeInstanceFunction_DifferentSynchronicity; diff --git a/Test/Async/Wrapped/ContainerInstanceFunctionAsTask.cs b/Test/Async/Wrapped/ContainerInstanceFunctionAsTask.cs index 678fb50d..202f11b2 100644 --- a/Test/Async/Wrapped/ContainerInstanceFunctionAsTask.cs +++ b/Test/Async/Wrapped/ContainerInstanceFunctionAsTask.cs @@ -1,5 +1,5 @@ using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Async.Wrapped.ContainerInstanceFunctionAsTask; diff --git a/Test/Async/Wrapped/ContainerInstanceFunctionAsValueTask.cs b/Test/Async/Wrapped/ContainerInstanceFunctionAsValueTask.cs index f4706d78..116c143c 100644 --- a/Test/Async/Wrapped/ContainerInstanceFunctionAsValueTask.cs +++ b/Test/Async/Wrapped/ContainerInstanceFunctionAsValueTask.cs @@ -1,5 +1,5 @@ using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Async.Wrapped.ContainerInstanceFunctionAsValueTask; diff --git a/Test/Async/Wrapped/DecorationChaining.cs b/Test/Async/Wrapped/DecorationChaining.cs index c6b59b03..40d7eaae 100644 --- a/Test/Async/Wrapped/DecorationChaining.cs +++ b/Test/Async/Wrapped/DecorationChaining.cs @@ -1,5 +1,5 @@ using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Async.Wrapped.DecorationChaining; diff --git a/Test/Async/Wrapped/Func.cs b/Test/Async/Wrapped/Func.cs index 021ad48f..d5f300ea 100644 --- a/Test/Async/Wrapped/Func.cs +++ b/Test/Async/Wrapped/Func.cs @@ -1,6 +1,6 @@ using System; using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Async.Wrapped.Func; diff --git a/Test/Async/Wrapped/Lazy.cs b/Test/Async/Wrapped/Lazy.cs index 9e03f4b0..824b23d4 100644 --- a/Test/Async/Wrapped/Lazy.cs +++ b/Test/Async/Wrapped/Lazy.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Async.Wrapped.Lazy; diff --git a/Test/Async/Wrapped/ScopeInstanceFunctionAsTask.cs b/Test/Async/Wrapped/ScopeInstanceFunctionAsTask.cs index ebfd8ecb..7edd277c 100644 --- a/Test/Async/Wrapped/ScopeInstanceFunctionAsTask.cs +++ b/Test/Async/Wrapped/ScopeInstanceFunctionAsTask.cs @@ -1,5 +1,5 @@ using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Async.Wrapped.ScopeInstanceFunctionAsTask; diff --git a/Test/Async/Wrapped/ScopeInstanceFunctionAsValueTask.cs b/Test/Async/Wrapped/ScopeInstanceFunctionAsValueTask.cs index c0968abf..5602d179 100644 --- a/Test/Async/Wrapped/ScopeInstanceFunctionAsValueTask.cs +++ b/Test/Async/Wrapped/ScopeInstanceFunctionAsValueTask.cs @@ -1,5 +1,5 @@ using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Async.Wrapped.ScopeInstanceFunctionAsValueTask; diff --git a/Test/Async/Wrapped/SyncToTask.cs b/Test/Async/Wrapped/SyncToTask.cs index 015fbed1..1f9a3717 100644 --- a/Test/Async/Wrapped/SyncToTask.cs +++ b/Test/Async/Wrapped/SyncToTask.cs @@ -1,5 +1,5 @@ using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Async.Wrapped.SyncToTask; diff --git a/Test/Async/Wrapped/SyncToValueTask.cs b/Test/Async/Wrapped/SyncToValueTask.cs index 205c469f..1148db60 100644 --- a/Test/Async/Wrapped/SyncToValueTask.cs +++ b/Test/Async/Wrapped/SyncToValueTask.cs @@ -1,5 +1,5 @@ using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Async.Wrapped.SyncToValueTask; diff --git a/Test/Async/Wrapped/TaskCollection.cs b/Test/Async/Wrapped/TaskCollection.cs index 02933f00..4ab0f251 100644 --- a/Test/Async/Wrapped/TaskCollection.cs +++ b/Test/Async/Wrapped/TaskCollection.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Async.Wrapped.TaskCollection; diff --git a/Test/Async/Wrapped/TaskComposition.cs b/Test/Async/Wrapped/TaskComposition.cs index 7f281822..ecce3c9d 100644 --- a/Test/Async/Wrapped/TaskComposition.cs +++ b/Test/Async/Wrapped/TaskComposition.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Async.Wrapped.TaskComposition; diff --git a/Test/Async/Wrapped/TaskToTask.cs b/Test/Async/Wrapped/TaskToTask.cs index 193f51e4..6ae97c79 100644 --- a/Test/Async/Wrapped/TaskToTask.cs +++ b/Test/Async/Wrapped/TaskToTask.cs @@ -1,6 +1,6 @@ using System; using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Async.Wrapped.TaskToTask; diff --git a/Test/Async/Wrapped/TaskToValueTask.cs b/Test/Async/Wrapped/TaskToValueTask.cs index c178bc8e..a3eee09e 100644 --- a/Test/Async/Wrapped/TaskToValueTask.cs +++ b/Test/Async/Wrapped/TaskToValueTask.cs @@ -1,6 +1,6 @@ using System; using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Async.Wrapped.TaskToValueTask; diff --git a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask.cs b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask.cs index a795ad3b..10638961 100644 --- a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask.cs +++ b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask.cs @@ -1,5 +1,5 @@ using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Async.Wrapped.TransientScopeInstanceFunctionAsTask; diff --git a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask_DifferentSynchronicity.cs b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask_DifferentSynchronicity.cs index e2a95b7b..59acf3f7 100644 --- a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask_DifferentSynchronicity.cs +++ b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask_DifferentSynchronicity.cs @@ -1,5 +1,5 @@ using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Async.Wrapped.TransientScopeInstanceFunctionAsTask_DifferentSynchronicity; diff --git a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask.cs b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask.cs index 9d2463b0..80df43ab 100644 --- a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask.cs +++ b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask.cs @@ -1,5 +1,5 @@ using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Async.Wrapped.TransientScopeInstanceFunctionAsValueTask; diff --git a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask_DifferentSynchronicity.cs b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask_DifferentSynchronicity.cs index 52d1b899..bef4ada1 100644 --- a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask_DifferentSynchronicity.cs +++ b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask_DifferentSynchronicity.cs @@ -1,5 +1,5 @@ using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Async.Wrapped.TransientScopeInstanceFunctionAsValueTask_DifferentSynchronicity; diff --git a/Test/Async/Wrapped/ValueTaskCollection.cs b/Test/Async/Wrapped/ValueTaskCollection.cs index 09ddba19..ccd776d0 100644 --- a/Test/Async/Wrapped/ValueTaskCollection.cs +++ b/Test/Async/Wrapped/ValueTaskCollection.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Async.Wrapped.ValueTaskCollection; diff --git a/Test/Async/Wrapped/ValueTaskComposition.cs b/Test/Async/Wrapped/ValueTaskComposition.cs index aa8d313d..25248bd0 100644 --- a/Test/Async/Wrapped/ValueTaskComposition.cs +++ b/Test/Async/Wrapped/ValueTaskComposition.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Async.Wrapped.ValueTaskComposition; diff --git a/Test/Async/Wrapped/ValueTaskToTask.cs b/Test/Async/Wrapped/ValueTaskToTask.cs index ea9598ca..99f4480e 100644 --- a/Test/Async/Wrapped/ValueTaskToTask.cs +++ b/Test/Async/Wrapped/ValueTaskToTask.cs @@ -1,6 +1,6 @@ using System; using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Async.Wrapped.ValueTaskToTask; diff --git a/Test/Async/Wrapped/ValueTaskToValueTask.cs b/Test/Async/Wrapped/ValueTaskToValueTask.cs index 1ecf33a7..ebb0bb0b 100644 --- a/Test/Async/Wrapped/ValueTaskToValueTask.cs +++ b/Test/Async/Wrapped/ValueTaskToValueTask.cs @@ -1,6 +1,6 @@ using System; using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Async.Wrapped.ValueTaskToValueTask; diff --git a/Test/Composite/Container.cs b/Test/Composite/Container.cs index dadaefe3..f6cdcc6c 100644 --- a/Test/Composite/Container.cs +++ b/Test/Composite/Container.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Composite.Container; diff --git a/Test/Composite/Decorated.cs b/Test/Composite/Decorated.cs index 20c81567..1fa0aae8 100644 --- a/Test/Composite/Decorated.cs +++ b/Test/Composite/Decorated.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Composite.Decorated; diff --git a/Test/Composite/MixedScoping.cs b/Test/Composite/MixedScoping.cs index ba5fe20b..0ea35b2b 100644 --- a/Test/Composite/MixedScoping.cs +++ b/Test/Composite/MixedScoping.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Composite.MixedScoping; diff --git a/Test/Composite/Normal.cs b/Test/Composite/Normal.cs index 5555287e..2eb5893d 100644 --- a/Test/Composite/Normal.cs +++ b/Test/Composite/Normal.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Composite.Normal; diff --git a/Test/Composite/ScopeRoot.cs b/Test/Composite/ScopeRoot.cs index ac396bc6..3cae8660 100644 --- a/Test/Composite/ScopeRoot.cs +++ b/Test/Composite/ScopeRoot.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Composite.ScopeRoot; diff --git a/Test/ConstructorChoice/Parameterless.cs b/Test/ConstructorChoice/Parameterless.cs index 4d749367..0d11e31d 100644 --- a/Test/ConstructorChoice/Parameterless.cs +++ b/Test/ConstructorChoice/Parameterless.cs @@ -1,5 +1,5 @@ using System; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.ConstructorChoice.Parameterless; diff --git a/Test/ConstructorChoice/WithParameter.cs b/Test/ConstructorChoice/WithParameter.cs index d2678992..1e89235e 100644 --- a/Test/ConstructorChoice/WithParameter.cs +++ b/Test/ConstructorChoice/WithParameter.cs @@ -1,6 +1,6 @@ using System; using System.IO; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.ConstructorChoice.WithParameter; diff --git a/Test/CustomEmbedding/FactoryInContainercs.cs b/Test/CustomEmbedding/FactoryInContainercs.cs index dfaf82a1..60ed0fcf 100644 --- a/Test/CustomEmbedding/FactoryInContainercs.cs +++ b/Test/CustomEmbedding/FactoryInContainercs.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.CustomEmbedding.FactoryInContainer; diff --git a/Test/CustomEmbedding/FactoryInScope.cs b/Test/CustomEmbedding/FactoryInScope.cs index a41e0f71..10ecd92a 100644 --- a/Test/CustomEmbedding/FactoryInScope.cs +++ b/Test/CustomEmbedding/FactoryInScope.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.CustomEmbedding.FactoryInScope; diff --git a/Test/CustomEmbedding/FactoryInTransientScope.cs b/Test/CustomEmbedding/FactoryInTransientScope.cs index dc7ae25a..895765ba 100644 --- a/Test/CustomEmbedding/FactoryInTransientScope.cs +++ b/Test/CustomEmbedding/FactoryInTransientScope.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.CustomEmbedding.FactoryInTransientScope; diff --git a/Test/CustomEmbedding/FactoryWithParameterInContainercs.cs b/Test/CustomEmbedding/FactoryWithParameterInContainercs.cs index 864a00d4..6971de6d 100644 --- a/Test/CustomEmbedding/FactoryWithParameterInContainercs.cs +++ b/Test/CustomEmbedding/FactoryWithParameterInContainercs.cs @@ -1,5 +1,5 @@ using System.IO; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.CustomEmbedding.FactoryWithParameterInContainer; diff --git a/Test/CustomEmbedding/FactoryWithParameterInScope.cs b/Test/CustomEmbedding/FactoryWithParameterInScope.cs index 70af6a09..b26cb5d9 100644 --- a/Test/CustomEmbedding/FactoryWithParameterInScope.cs +++ b/Test/CustomEmbedding/FactoryWithParameterInScope.cs @@ -1,5 +1,5 @@ using System.IO; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.CustomEmbedding.FactoryWithParameterInScope; diff --git a/Test/CustomEmbedding/FactoryWithParameterInTransientScope.cs b/Test/CustomEmbedding/FactoryWithParameterInTransientScope.cs index 4149b466..6c895e34 100644 --- a/Test/CustomEmbedding/FactoryWithParameterInTransientScope.cs +++ b/Test/CustomEmbedding/FactoryWithParameterInTransientScope.cs @@ -1,5 +1,5 @@ using System.IO; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.CustomEmbedding.FactoryWithParameterInTransientScope; diff --git a/Test/CustomEmbedding/FieldInContainercs.cs b/Test/CustomEmbedding/FieldInContainercs.cs index 11ef1332..31434164 100644 --- a/Test/CustomEmbedding/FieldInContainercs.cs +++ b/Test/CustomEmbedding/FieldInContainercs.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.CustomEmbedding.FieldInContainer; diff --git a/Test/CustomEmbedding/FieldInScope.cs b/Test/CustomEmbedding/FieldInScope.cs index 1115e884..bcf98799 100644 --- a/Test/CustomEmbedding/FieldInScope.cs +++ b/Test/CustomEmbedding/FieldInScope.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.CustomEmbedding.FieldInScope; diff --git a/Test/CustomEmbedding/FieldInTransientScope.cs b/Test/CustomEmbedding/FieldInTransientScope.cs index 6f1ef794..fc1fe5c1 100644 --- a/Test/CustomEmbedding/FieldInTransientScope.cs +++ b/Test/CustomEmbedding/FieldInTransientScope.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.CustomEmbedding.FieldInTransientScope; diff --git a/Test/CustomEmbedding/PropertyInContainercs.cs b/Test/CustomEmbedding/PropertyInContainercs.cs index 864f1a16..f6566267 100644 --- a/Test/CustomEmbedding/PropertyInContainercs.cs +++ b/Test/CustomEmbedding/PropertyInContainercs.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.CustomEmbedding.PropertyInContainer; diff --git a/Test/CustomEmbedding/PropertyInScope.cs b/Test/CustomEmbedding/PropertyInScope.cs index 1a7af579..2ed0e128 100644 --- a/Test/CustomEmbedding/PropertyInScope.cs +++ b/Test/CustomEmbedding/PropertyInScope.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.CustomEmbedding.PropertyInScope; diff --git a/Test/CustomEmbedding/PropertyInTransientScope.cs b/Test/CustomEmbedding/PropertyInTransientScope.cs index 8929e70c..bbea6a74 100644 --- a/Test/CustomEmbedding/PropertyInTransientScope.cs +++ b/Test/CustomEmbedding/PropertyInTransientScope.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.CustomEmbedding.PropertyInTransientScope; diff --git a/Test/CycleDetection/Implementation.cs b/Test/CycleDetection/Implementation.cs index 78ea7d46..fac8ba4e 100644 --- a/Test/CycleDetection/Implementation.cs +++ b/Test/CycleDetection/Implementation.cs @@ -1,5 +1,5 @@ using MrMeeseeks.DIE; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.CycleDetection.Implementation; diff --git a/Test/CycleDetection/ImplementationProxied.cs b/Test/CycleDetection/ImplementationProxied.cs index 4a6e69f3..bd32bb1f 100644 --- a/Test/CycleDetection/ImplementationProxied.cs +++ b/Test/CycleDetection/ImplementationProxied.cs @@ -1,5 +1,5 @@ using MrMeeseeks.DIE; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.CycleDetection.ImplementationProxied; diff --git a/Test/CycleDetection/NoCycleInParallel.cs b/Test/CycleDetection/NoCycleInParallel.cs index 4d9be513..e8d6531f 100644 --- a/Test/CycleDetection/NoCycleInParallel.cs +++ b/Test/CycleDetection/NoCycleInParallel.cs @@ -1,5 +1,5 @@ using MrMeeseeks.DIE; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.CycleDetection.NoCycleInParallel; diff --git a/Test/Decorator/ContainerInstance.cs b/Test/Decorator/ContainerInstance.cs index beee7022..6b3951b7 100644 --- a/Test/Decorator/ContainerInstance.cs +++ b/Test/Decorator/ContainerInstance.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Decorator.ContainerInstance; diff --git a/Test/Decorator/List.cs b/Test/Decorator/List.cs index 8ba7b830..f6261007 100644 --- a/Test/Decorator/List.cs +++ b/Test/Decorator/List.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Decorator.List; diff --git a/Test/Decorator/Multi.cs b/Test/Decorator/Multi.cs index 1ae52eab..00e82253 100644 --- a/Test/Decorator/Multi.cs +++ b/Test/Decorator/Multi.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Decorator.Multi; diff --git a/Test/Decorator/Normal.cs b/Test/Decorator/Normal.cs index 14224db8..f143eca3 100644 --- a/Test/Decorator/Normal.cs +++ b/Test/Decorator/Normal.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Decorator.Normal; diff --git a/Test/Decorator/ScopeDecoratorForContainerDependency.cs b/Test/Decorator/ScopeDecoratorForContainerDependency.cs index d10389b3..4e7b7656 100644 --- a/Test/Decorator/ScopeDecoratorForContainerDependency.cs +++ b/Test/Decorator/ScopeDecoratorForContainerDependency.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Decorator.ScopeDecoratorForContainerDependency; diff --git a/Test/Decorator/ScopeDecoratorForTransientScopeDependency.cs b/Test/Decorator/ScopeDecoratorForTransientScopeDependency.cs index 14dd59e4..674b24e3 100644 --- a/Test/Decorator/ScopeDecoratorForTransientScopeDependency.cs +++ b/Test/Decorator/ScopeDecoratorForTransientScopeDependency.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Decorator.ScopeDecoratorForTransientScopeDependency; diff --git a/Test/Decorator/SequenceEdgeCase.cs b/Test/Decorator/SequenceEdgeCase.cs index 9357558c..9df55b2e 100644 --- a/Test/Decorator/SequenceEdgeCase.cs +++ b/Test/Decorator/SequenceEdgeCase.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Decorator.SequenceEdgeCase; diff --git a/Test/Disposal/Async/InContainer.cs b/Test/Disposal/Async/InContainer.cs index 55e7b47d..e013fd1c 100644 --- a/Test/Disposal/Async/InContainer.cs +++ b/Test/Disposal/Async/InContainer.cs @@ -1,6 +1,6 @@ using System; using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Disposal.Async.InContainer; diff --git a/Test/Disposal/Async/InScope.cs b/Test/Disposal/Async/InScope.cs index b00a0ff2..c136d8dc 100644 --- a/Test/Disposal/Async/InScope.cs +++ b/Test/Disposal/Async/InScope.cs @@ -1,6 +1,6 @@ using System; using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Disposal.Async.InScope; diff --git a/Test/Disposal/Async/InScopeInTransientScope.cs b/Test/Disposal/Async/InScopeInTransientScope.cs index eb13b95c..345e611a 100644 --- a/Test/Disposal/Async/InScopeInTransientScope.cs +++ b/Test/Disposal/Async/InScopeInTransientScope.cs @@ -1,6 +1,6 @@ using System; using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Disposal.Async.InScopeInTransientScope; diff --git a/Test/Disposal/Async/InTransientScope.cs b/Test/Disposal/Async/InTransientScope.cs index 1bdc9873..f70296bc 100644 --- a/Test/Disposal/Async/InTransientScope.cs +++ b/Test/Disposal/Async/InTransientScope.cs @@ -1,6 +1,6 @@ using System; using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Disposal.Async.InTransientScope; diff --git a/Test/Disposal/Async/InTransientScopeInTransientScope.cs b/Test/Disposal/Async/InTransientScopeInTransientScope.cs index 1e8134aa..9cbabbef 100644 --- a/Test/Disposal/Async/InTransientScopeInTransientScope.cs +++ b/Test/Disposal/Async/InTransientScopeInTransientScope.cs @@ -1,6 +1,6 @@ using System; using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Disposal.Async.InTransientScopeInTransientScope; diff --git a/Test/Disposal/Sync/InContainer.cs b/Test/Disposal/Sync/InContainer.cs index d0d86066..919c4672 100644 --- a/Test/Disposal/Sync/InContainer.cs +++ b/Test/Disposal/Sync/InContainer.cs @@ -1,5 +1,5 @@ using System; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Disposal.Sync.InContainer; diff --git a/Test/Disposal/Sync/InScope.cs b/Test/Disposal/Sync/InScope.cs index fee5a612..4f52d3d0 100644 --- a/Test/Disposal/Sync/InScope.cs +++ b/Test/Disposal/Sync/InScope.cs @@ -1,5 +1,5 @@ using System; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Disposal.Sync.InScope; diff --git a/Test/Disposal/Sync/InScopeInTransientScope.cs b/Test/Disposal/Sync/InScopeInTransientScope.cs index fdadf842..7abb9ef4 100644 --- a/Test/Disposal/Sync/InScopeInTransientScope.cs +++ b/Test/Disposal/Sync/InScopeInTransientScope.cs @@ -1,6 +1,6 @@ using System; using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Disposal.Sync.InScopeInTransientScope; diff --git a/Test/Disposal/Sync/InTransientScope.cs b/Test/Disposal/Sync/InTransientScope.cs index 5c3d9756..399eae74 100644 --- a/Test/Disposal/Sync/InTransientScope.cs +++ b/Test/Disposal/Sync/InTransientScope.cs @@ -1,5 +1,5 @@ using System; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Disposal.Sync.InTransientScope; diff --git a/Test/Disposal/Sync/InTransientScopeInTransientScope.cs b/Test/Disposal/Sync/InTransientScopeInTransientScope.cs index fff30a3b..d164cafb 100644 --- a/Test/Disposal/Sync/InTransientScopeInTransientScope.cs +++ b/Test/Disposal/Sync/InTransientScopeInTransientScope.cs @@ -1,6 +1,6 @@ using System; using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Disposal.Sync.InTransientScopeInTransientScope; diff --git a/Test/Disposal/TransientScopeDisposalHandle/AsyncContainerToAsyncDisposalHandle.cs b/Test/Disposal/TransientScopeDisposalHandle/AsyncContainerToAsyncDisposalHandle.cs index e53351f1..b364468b 100644 --- a/Test/Disposal/TransientScopeDisposalHandle/AsyncContainerToAsyncDisposalHandle.cs +++ b/Test/Disposal/TransientScopeDisposalHandle/AsyncContainerToAsyncDisposalHandle.cs @@ -1,6 +1,6 @@ using System; using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Disposal.TransientScopeDisposalHandle.AsyncContainerToAsyncDisposalHandle; diff --git a/Test/Disposal/TransientScopeDisposalHandle/NoneContainerToAsyncDisposalHandle.cs b/Test/Disposal/TransientScopeDisposalHandle/NoneContainerToAsyncDisposalHandle.cs index 87d955f1..42931f5b 100644 --- a/Test/Disposal/TransientScopeDisposalHandle/NoneContainerToAsyncDisposalHandle.cs +++ b/Test/Disposal/TransientScopeDisposalHandle/NoneContainerToAsyncDisposalHandle.cs @@ -1,6 +1,6 @@ using System; using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Disposal.TransientScopeDisposalHandle.NoneContainerToAsyncDisposalHandle; diff --git a/Test/Disposal/TransientScopeDisposalHandle/NoneContainerToSyncDisposalHandle.cs b/Test/Disposal/TransientScopeDisposalHandle/NoneContainerToSyncDisposalHandle.cs index b6c94abc..f8cba235 100644 --- a/Test/Disposal/TransientScopeDisposalHandle/NoneContainerToSyncDisposalHandle.cs +++ b/Test/Disposal/TransientScopeDisposalHandle/NoneContainerToSyncDisposalHandle.cs @@ -1,5 +1,5 @@ using System; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Disposal.TransientScopeDisposalHandle.NoneContainerToSyncDisposalHandle; diff --git a/Test/Disposal/TransientScopeDisposalHandle/SyncContainerToAsyncDisposalHandle.cs b/Test/Disposal/TransientScopeDisposalHandle/SyncContainerToAsyncDisposalHandle.cs index 595957bb..46866d02 100644 --- a/Test/Disposal/TransientScopeDisposalHandle/SyncContainerToAsyncDisposalHandle.cs +++ b/Test/Disposal/TransientScopeDisposalHandle/SyncContainerToAsyncDisposalHandle.cs @@ -1,6 +1,6 @@ using System; using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Disposal.TransientScopeDisposalHandle.SyncContainerToAsyncDisposalHandle; diff --git a/Test/Disposal/TransientScopeDisposalHandle/SyncContainerToSyncDisposalHandle.cs b/Test/Disposal/TransientScopeDisposalHandle/SyncContainerToSyncDisposalHandle.cs index 91898a5d..7b63208b 100644 --- a/Test/Disposal/TransientScopeDisposalHandle/SyncContainerToSyncDisposalHandle.cs +++ b/Test/Disposal/TransientScopeDisposalHandle/SyncContainerToSyncDisposalHandle.cs @@ -1,5 +1,5 @@ using System; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Disposal.TransientScopeDisposalHandle.SyncContainerToSyncDisposalHandle; diff --git a/Test/Func/Double.cs b/Test/Func/Double.cs index 74dfc86f..11d2b74e 100644 --- a/Test/Func/Double.cs +++ b/Test/Func/Double.cs @@ -1,6 +1,6 @@ using System; using System.Collections.Generic; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Func.Double; diff --git a/Test/Func/Vanilla.cs b/Test/Func/Vanilla.cs index 4fa53200..17cb0605 100644 --- a/Test/Func/Vanilla.cs +++ b/Test/Func/Vanilla.cs @@ -1,6 +1,6 @@ using System; using System.Collections.Generic; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Func.Vanilla; diff --git a/Test/Generics/Choice/Double.cs b/Test/Generics/Choice/Double.cs index 63846c7f..17b87d14 100644 --- a/Test/Generics/Choice/Double.cs +++ b/Test/Generics/Choice/Double.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Choice.Double; diff --git a/Test/Generics/Choice/DoubleBothChosen.cs b/Test/Generics/Choice/DoubleBothChosen.cs index b603bb8e..044e71f8 100644 --- a/Test/Generics/Choice/DoubleBothChosen.cs +++ b/Test/Generics/Choice/DoubleBothChosen.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Choice.DoubleBothChosen; diff --git a/Test/Generics/Choice/DoubleBothChosenWithSingleOtherSubstitute.cs b/Test/Generics/Choice/DoubleBothChosenWithSingleOtherSubstitute.cs index d2699b74..aae135cb 100644 --- a/Test/Generics/Choice/DoubleBothChosenWithSingleOtherSubstitute.cs +++ b/Test/Generics/Choice/DoubleBothChosenWithSingleOtherSubstitute.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Choice.DoubleBothChosenWithSingleOtherSubstitute; diff --git a/Test/Generics/Choice/DoubleWithSingleOtherSubstitute.cs b/Test/Generics/Choice/DoubleWithSingleOtherSubstitute.cs index ec7d6087..a12100a4 100644 --- a/Test/Generics/Choice/DoubleWithSingleOtherSubstitute.cs +++ b/Test/Generics/Choice/DoubleWithSingleOtherSubstitute.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Choice.DoubleWithSingleOtherSubstitute; diff --git a/Test/Generics/Choice/Single.cs b/Test/Generics/Choice/Single.cs index 887a31bc..45ca8036 100644 --- a/Test/Generics/Choice/Single.cs +++ b/Test/Generics/Choice/Single.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Choice.Single; diff --git a/Test/Generics/Choice/SingleWithSingleOtherSubstitute.cs b/Test/Generics/Choice/SingleWithSingleOtherSubstitute.cs index 4fe0fef3..d16479d5 100644 --- a/Test/Generics/Choice/SingleWithSingleOtherSubstitute.cs +++ b/Test/Generics/Choice/SingleWithSingleOtherSubstitute.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Choice.SingleWithSingleOtherSubstitute; diff --git a/Test/Generics/ChoiceIndirectlyBySingleSubstitute/Double.cs b/Test/Generics/ChoiceIndirectlyBySingleSubstitute/Double.cs index ba1b8eb8..4d1c94c4 100644 --- a/Test/Generics/ChoiceIndirectlyBySingleSubstitute/Double.cs +++ b/Test/Generics/ChoiceIndirectlyBySingleSubstitute/Double.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.ChoiceIndirectlyBySingleSubstitute.Double; diff --git a/Test/Generics/ChoiceIndirectlyBySingleSubstitute/Single.cs b/Test/Generics/ChoiceIndirectlyBySingleSubstitute/Single.cs index 70374dd4..f3d74def 100644 --- a/Test/Generics/ChoiceIndirectlyBySingleSubstitute/Single.cs +++ b/Test/Generics/ChoiceIndirectlyBySingleSubstitute/Single.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.ChoiceIndirectlyBySingleSubstitute.Single; diff --git a/Test/Generics/Configuration/AsyncTransient.cs b/Test/Generics/Configuration/AsyncTransient.cs index 1f08c777..12f4b776 100644 --- a/Test/Generics/Configuration/AsyncTransient.cs +++ b/Test/Generics/Configuration/AsyncTransient.cs @@ -1,6 +1,6 @@ using System; using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Configuration.AsyncTransient; diff --git a/Test/Generics/Configuration/AsyncTransientWithJustTransient.cs b/Test/Generics/Configuration/AsyncTransientWithJustTransient.cs index 05605e9b..7a55ce93 100644 --- a/Test/Generics/Configuration/AsyncTransientWithJustTransient.cs +++ b/Test/Generics/Configuration/AsyncTransientWithJustTransient.cs @@ -1,6 +1,6 @@ using System; using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Configuration.AsyncTransientWithJustTransient; diff --git a/Test/Generics/Configuration/Composite.cs b/Test/Generics/Configuration/Composite.cs index c0174ae3..7fd9ea5c 100644 --- a/Test/Generics/Configuration/Composite.cs +++ b/Test/Generics/Configuration/Composite.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Configuration.Composite; diff --git a/Test/Generics/Configuration/ConstructorChoice.cs b/Test/Generics/Configuration/ConstructorChoice.cs index 66d00ded..91c92c2b 100644 --- a/Test/Generics/Configuration/ConstructorChoice.cs +++ b/Test/Generics/Configuration/ConstructorChoice.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Configuration.ConstructorChoiceFoo; diff --git a/Test/Generics/Configuration/ContainerInstance.cs b/Test/Generics/Configuration/ContainerInstance.cs index 4c9b0c3f..77ed6b20 100644 --- a/Test/Generics/Configuration/ContainerInstance.cs +++ b/Test/Generics/Configuration/ContainerInstance.cs @@ -1,5 +1,5 @@ using System; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Configuration.ContainerInstance; diff --git a/Test/Generics/Configuration/ContainerInstanceWithDifferentGenericParameter.cs b/Test/Generics/Configuration/ContainerInstanceWithDifferentGenericParameter.cs index b4b49cdd..32d404f1 100644 --- a/Test/Generics/Configuration/ContainerInstanceWithDifferentGenericParameter.cs +++ b/Test/Generics/Configuration/ContainerInstanceWithDifferentGenericParameter.cs @@ -1,5 +1,5 @@ using System; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Configuration.ContainerInstanceWithDifferentGenericParameter; diff --git a/Test/Generics/Configuration/Decorator.cs b/Test/Generics/Configuration/Decorator.cs index 52246c2f..5e958fa2 100644 --- a/Test/Generics/Configuration/Decorator.cs +++ b/Test/Generics/Configuration/Decorator.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Configuration.Decorator; diff --git a/Test/Generics/Configuration/InitializerImplementationAsync.cs b/Test/Generics/Configuration/InitializerImplementationAsync.cs index 3d5cf527..ba21ddd2 100644 --- a/Test/Generics/Configuration/InitializerImplementationAsync.cs +++ b/Test/Generics/Configuration/InitializerImplementationAsync.cs @@ -1,5 +1,5 @@ using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Configuration.InitializerImplementationAsync; diff --git a/Test/Generics/Configuration/InitializerImplementationAsyncValue.cs b/Test/Generics/Configuration/InitializerImplementationAsyncValue.cs index 24bf627c..b991fdbf 100644 --- a/Test/Generics/Configuration/InitializerImplementationAsyncValue.cs +++ b/Test/Generics/Configuration/InitializerImplementationAsyncValue.cs @@ -1,5 +1,5 @@ using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Configuration.InitializerImplementationAsyncValue; diff --git a/Test/Generics/Configuration/InitializerImplementationSync.cs b/Test/Generics/Configuration/InitializerImplementationSync.cs index 9424afb1..280242a5 100644 --- a/Test/Generics/Configuration/InitializerImplementationSync.cs +++ b/Test/Generics/Configuration/InitializerImplementationSync.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Configuration.InitializerImplementationSync; diff --git a/Test/Generics/Configuration/InitializerInterfaceAsync.cs b/Test/Generics/Configuration/InitializerInterfaceAsync.cs index d0032053..7d4d8107 100644 --- a/Test/Generics/Configuration/InitializerInterfaceAsync.cs +++ b/Test/Generics/Configuration/InitializerInterfaceAsync.cs @@ -1,5 +1,5 @@ using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Configuration.InitializerInterfaceAsync; diff --git a/Test/Generics/Configuration/InitializerInterfaceAsyncValue.cs b/Test/Generics/Configuration/InitializerInterfaceAsyncValue.cs index acb3c419..439e86ce 100644 --- a/Test/Generics/Configuration/InitializerInterfaceAsyncValue.cs +++ b/Test/Generics/Configuration/InitializerInterfaceAsyncValue.cs @@ -1,5 +1,5 @@ using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Configuration.InitializerInterfaceAsyncValue; diff --git a/Test/Generics/Configuration/InitializerInterfaceSync.cs b/Test/Generics/Configuration/InitializerInterfaceSync.cs index 152c69e5..ac49c0a5 100644 --- a/Test/Generics/Configuration/InitializerInterfaceSync.cs +++ b/Test/Generics/Configuration/InitializerInterfaceSync.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Configuration.InitializerInterfaceSync; diff --git a/Test/Generics/Configuration/InterfaceGenericComposite.cs b/Test/Generics/Configuration/InterfaceGenericComposite.cs index 901e5e96..87bd7067 100644 --- a/Test/Generics/Configuration/InterfaceGenericComposite.cs +++ b/Test/Generics/Configuration/InterfaceGenericComposite.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Configuration.InterfaceGenericComposite; diff --git a/Test/Generics/Configuration/InterfaceGenericDecorator.cs b/Test/Generics/Configuration/InterfaceGenericDecorator.cs index 95219d4d..8c0c9532 100644 --- a/Test/Generics/Configuration/InterfaceGenericDecorator.cs +++ b/Test/Generics/Configuration/InterfaceGenericDecorator.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Configuration.InterfaceGenericDecorator; diff --git a/Test/Generics/Configuration/ScopeInstance.cs b/Test/Generics/Configuration/ScopeInstance.cs index 757581ee..0aa42923 100644 --- a/Test/Generics/Configuration/ScopeInstance.cs +++ b/Test/Generics/Configuration/ScopeInstance.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Configuration.ScopeInstance; diff --git a/Test/Generics/Configuration/ScopeInstanceWithDifferentGenericParameter.cs b/Test/Generics/Configuration/ScopeInstanceWithDifferentGenericParameter.cs index 6d27b555..9359ba94 100644 --- a/Test/Generics/Configuration/ScopeInstanceWithDifferentGenericParameter.cs +++ b/Test/Generics/Configuration/ScopeInstanceWithDifferentGenericParameter.cs @@ -1,5 +1,5 @@ using System; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Configuration.ScopeInstanceWithDifferentGenericParameter; diff --git a/Test/Generics/Configuration/ScopeRoot.cs b/Test/Generics/Configuration/ScopeRoot.cs index 37e348c7..cae8e006 100644 --- a/Test/Generics/Configuration/ScopeRoot.cs +++ b/Test/Generics/Configuration/ScopeRoot.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Configuration.ScopeRoot; diff --git a/Test/Generics/Configuration/SyncTransient.cs b/Test/Generics/Configuration/SyncTransient.cs index 18a5d083..3294cc11 100644 --- a/Test/Generics/Configuration/SyncTransient.cs +++ b/Test/Generics/Configuration/SyncTransient.cs @@ -1,5 +1,5 @@ using System; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Configuration.SyncTransient; diff --git a/Test/Generics/Configuration/SyncTransientWithJustTransient.cs b/Test/Generics/Configuration/SyncTransientWithJustTransient.cs index 5e599db0..befd2cc8 100644 --- a/Test/Generics/Configuration/SyncTransientWithJustTransient.cs +++ b/Test/Generics/Configuration/SyncTransientWithJustTransient.cs @@ -1,5 +1,5 @@ using System; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Configuration.SyncTransientWithJustTransient; diff --git a/Test/Generics/Configuration/TransientScopeInstance.cs b/Test/Generics/Configuration/TransientScopeInstance.cs index 80ff9953..b597dd4f 100644 --- a/Test/Generics/Configuration/TransientScopeInstance.cs +++ b/Test/Generics/Configuration/TransientScopeInstance.cs @@ -1,5 +1,5 @@ using System; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Configuration.TransientScopeInstance; diff --git a/Test/Generics/Configuration/TransientScopeInstanceWithDifferentGenericParameter.cs b/Test/Generics/Configuration/TransientScopeInstanceWithDifferentGenericParameter.cs index c4005714..844a45ae 100644 --- a/Test/Generics/Configuration/TransientScopeInstanceWithDifferentGenericParameter.cs +++ b/Test/Generics/Configuration/TransientScopeInstanceWithDifferentGenericParameter.cs @@ -1,5 +1,5 @@ using System; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Configuration.TransientScopeInstanceWithDifferentGenericParameter; diff --git a/Test/Generics/Configuration/TransientScopeRoot.cs b/Test/Generics/Configuration/TransientScopeRoot.cs index bf4ffa5d..5beea17b 100644 --- a/Test/Generics/Configuration/TransientScopeRoot.cs +++ b/Test/Generics/Configuration/TransientScopeRoot.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Configuration.TransientScopeRoot; diff --git a/Test/Generics/Implementation/Double.cs b/Test/Generics/Implementation/Double.cs index ba57cfe9..adbe96d4 100644 --- a/Test/Generics/Implementation/Double.cs +++ b/Test/Generics/Implementation/Double.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Implementation.Double; diff --git a/Test/Generics/Implementation/Single.cs b/Test/Generics/Implementation/Single.cs index 2f764587..9af95f0b 100644 --- a/Test/Generics/Implementation/Single.cs +++ b/Test/Generics/Implementation/Single.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Implementation.Single; diff --git a/Test/Generics/Interface/Double.cs b/Test/Generics/Interface/Double.cs index 194e11a8..2086ea1c 100644 --- a/Test/Generics/Interface/Double.cs +++ b/Test/Generics/Interface/Double.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Interface.Double; diff --git a/Test/Generics/Interface/DoubleAndOneFixed.cs b/Test/Generics/Interface/DoubleAndOneFixed.cs index 746a71d9..a87a73f9 100644 --- a/Test/Generics/Interface/DoubleAndOneFixed.cs +++ b/Test/Generics/Interface/DoubleAndOneFixed.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Interface.DoubleAndOneFixed; diff --git a/Test/Generics/Interface/DoubleAndSetToSame.cs b/Test/Generics/Interface/DoubleAndSetToSame.cs index f512baef..38774160 100644 --- a/Test/Generics/Interface/DoubleAndSetToSame.cs +++ b/Test/Generics/Interface/DoubleAndSetToSame.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Interface.DoubleAndSetToSame; diff --git a/Test/Generics/Interface/DoubleSwitched.cs b/Test/Generics/Interface/DoubleSwitched.cs index eea62625..47aa5037 100644 --- a/Test/Generics/Interface/DoubleSwitched.cs +++ b/Test/Generics/Interface/DoubleSwitched.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Interface.DoubleSwitched; diff --git a/Test/Generics/Interface/Single.cs b/Test/Generics/Interface/Single.cs index 0262cc46..79bf18da 100644 --- a/Test/Generics/Interface/Single.cs +++ b/Test/Generics/Interface/Single.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Interface.Single; diff --git a/Test/Generics/Interface/SingleAndBaseImplementationDoubleButOneFixed.cs b/Test/Generics/Interface/SingleAndBaseImplementationDoubleButOneFixed.cs index 470d1817..2f08919e 100644 --- a/Test/Generics/Interface/SingleAndBaseImplementationDoubleButOneFixed.cs +++ b/Test/Generics/Interface/SingleAndBaseImplementationDoubleButOneFixed.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Interface.SingleAndBaseImplementationDoubleButOneFixed; diff --git a/Test/Generics/SubstituteCollection/Double.cs b/Test/Generics/SubstituteCollection/Double.cs index ba52c25a..59063804 100644 --- a/Test/Generics/SubstituteCollection/Double.cs +++ b/Test/Generics/SubstituteCollection/Double.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.SubstituteCollection.Double; diff --git a/Test/Generics/SubstituteCollection/DoubleBothSubstituted.cs b/Test/Generics/SubstituteCollection/DoubleBothSubstituted.cs index fb9a72e0..92bebeff 100644 --- a/Test/Generics/SubstituteCollection/DoubleBothSubstituted.cs +++ b/Test/Generics/SubstituteCollection/DoubleBothSubstituted.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.SubstituteCollection.BothSubstituted; diff --git a/Test/Generics/SubstituteCollection/DoubleBothSubstitutedWithChoice.cs b/Test/Generics/SubstituteCollection/DoubleBothSubstitutedWithChoice.cs index 777f083b..b9ee3e85 100644 --- a/Test/Generics/SubstituteCollection/DoubleBothSubstitutedWithChoice.cs +++ b/Test/Generics/SubstituteCollection/DoubleBothSubstitutedWithChoice.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.SubstituteCollection.BothSubstitutedWithChoice; diff --git a/Test/Generics/SubstituteCollection/DoubleWithChoice.cs b/Test/Generics/SubstituteCollection/DoubleWithChoice.cs index 895f9eeb..4932c774 100644 --- a/Test/Generics/SubstituteCollection/DoubleWithChoice.cs +++ b/Test/Generics/SubstituteCollection/DoubleWithChoice.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.SubstituteCollection.DoubleWithChoice; diff --git a/Test/Generics/SubstituteCollection/Single.cs b/Test/Generics/SubstituteCollection/Single.cs index 5a1b9567..225955ed 100644 --- a/Test/Generics/SubstituteCollection/Single.cs +++ b/Test/Generics/SubstituteCollection/Single.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.SubstituteCollection.SingleWithChoice; diff --git a/Test/Generics/SubstituteCollection/SingleWithChoice.cs b/Test/Generics/SubstituteCollection/SingleWithChoice.cs index 010beb03..f5f809f3 100644 --- a/Test/Generics/SubstituteCollection/SingleWithChoice.cs +++ b/Test/Generics/SubstituteCollection/SingleWithChoice.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.SubstituteCollection.Single; diff --git a/Test/Generics/SubstituteCollection/TripleInsanity.cs b/Test/Generics/SubstituteCollection/TripleInsanity.cs index a193d032..adfc8b6e 100644 --- a/Test/Generics/SubstituteCollection/TripleInsanity.cs +++ b/Test/Generics/SubstituteCollection/TripleInsanity.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.SubstituteCollection.TripleInsanity; diff --git a/Test/Implementation/Aggregation/AssemblyImplementationsAggregation.cs b/Test/Implementation/Aggregation/AssemblyImplementationsAggregation.cs index d3021c65..1bb9d882 100644 --- a/Test/Implementation/Aggregation/AssemblyImplementationsAggregation.cs +++ b/Test/Implementation/Aggregation/AssemblyImplementationsAggregation.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using MrMeeseeks.DIE.TestNotInternalsVisibleToChild.Public; using MrMeeseeks.DIE.TestNotInternalsVisibleToChild; using Xunit; diff --git a/Test/Implementation/Aggregation/ExternalType.cs b/Test/Implementation/Aggregation/ExternalType.cs index 55551d3d..954c7d20 100644 --- a/Test/Implementation/Aggregation/ExternalType.cs +++ b/Test/Implementation/Aggregation/ExternalType.cs @@ -1,6 +1,6 @@ using System; using System.IO; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Implementation.Aggregation.ExternalType; diff --git a/Test/Implementation/Aggregation/FilterAllImplementations.cs b/Test/Implementation/Aggregation/FilterAllImplementations.cs index 5edb9125..d1aec496 100644 --- a/Test/Implementation/Aggregation/FilterAllImplementations.cs +++ b/Test/Implementation/Aggregation/FilterAllImplementations.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Implementation.Aggregation.FilterAllImplementations; diff --git a/Test/Implementation/Aggregation/InternalsVisibleTo.cs b/Test/Implementation/Aggregation/InternalsVisibleTo.cs index a0dd64e7..ba7797b1 100644 --- a/Test/Implementation/Aggregation/InternalsVisibleTo.cs +++ b/Test/Implementation/Aggregation/InternalsVisibleTo.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using MrMeeseeks.DIE.TestInternalsVisibleToChild.Internal; using Xunit; diff --git a/Test/Implementation/Choice/Collection.cs b/Test/Implementation/Choice/Collection.cs index b864e8ef..d266db46 100644 --- a/Test/Implementation/Choice/Collection.cs +++ b/Test/Implementation/Choice/Collection.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Implementation.Choice.Collection; diff --git a/Test/Implementation/Choice/CollectionWithoutChoice.cs b/Test/Implementation/Choice/CollectionWithoutChoice.cs index 35aae97a..16781f93 100644 --- a/Test/Implementation/Choice/CollectionWithoutChoice.cs +++ b/Test/Implementation/Choice/CollectionWithoutChoice.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Implementation.Choice.CollectionWithoutChoice; diff --git a/Test/Implementation/Choice/SingleInCollection.cs b/Test/Implementation/Choice/SingleInCollection.cs index bfa5c39a..2d6fe5ac 100644 --- a/Test/Implementation/Choice/SingleInCollection.cs +++ b/Test/Implementation/Choice/SingleInCollection.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Implementation.Choice.SingleInCollection; diff --git a/Test/Implementation/Choice/Vanilla.cs b/Test/Implementation/Choice/Vanilla.cs index 050f86d6..ee9c8156 100644 --- a/Test/Implementation/Choice/Vanilla.cs +++ b/Test/Implementation/Choice/Vanilla.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Implementation.Choice.Vanilla; diff --git a/Test/Implementation/Choice/VanillaWithoutChoice.cs b/Test/Implementation/Choice/VanillaWithoutChoice.cs index 00660552..dfc72913 100644 --- a/Test/Implementation/Choice/VanillaWithoutChoice.cs +++ b/Test/Implementation/Choice/VanillaWithoutChoice.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Implementation.Choice.VanillaWithoutChoice; diff --git a/Test/Implementation/Choice/WithSingleInCollection.cs b/Test/Implementation/Choice/WithSingleInCollection.cs index 5b8c3478..d97cc148 100644 --- a/Test/Implementation/Choice/WithSingleInCollection.cs +++ b/Test/Implementation/Choice/WithSingleInCollection.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Implementation.Choice.WithSingleInCollection; diff --git a/Test/InitProperty/Vanilla.cs b/Test/InitProperty/Vanilla.cs index 79caff84..e275ddd9 100644 --- a/Test/InitProperty/Vanilla.cs +++ b/Test/InitProperty/Vanilla.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.InitProperty.Vanilla; diff --git a/Test/Lazy/Vanilla.cs b/Test/Lazy/Vanilla.cs index a76279a7..83f77c36 100644 --- a/Test/Lazy/Vanilla.cs +++ b/Test/Lazy/Vanilla.cs @@ -1,5 +1,5 @@ using System; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Lazy.Vanilla; diff --git a/Test/Nullability/NonOptional/MultipleImplementations.cs b/Test/Nullability/NonOptional/MultipleImplementations.cs index b243eba2..0404979b 100644 --- a/Test/Nullability/NonOptional/MultipleImplementations.cs +++ b/Test/Nullability/NonOptional/MultipleImplementations.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Nullability.NonOptional.MultipleImplementations; diff --git a/Test/Nullability/NonOptional/NoImplementation.cs b/Test/Nullability/NonOptional/NoImplementation.cs index 54ac5931..b61a3735 100644 --- a/Test/Nullability/NonOptional/NoImplementation.cs +++ b/Test/Nullability/NonOptional/NoImplementation.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Nullability.NonOptional.NoImplementation; diff --git a/Test/Nullability/Optional/MultipleImplementations.cs b/Test/Nullability/Optional/MultipleImplementations.cs index 4e933972..77df9a08 100644 --- a/Test/Nullability/Optional/MultipleImplementations.cs +++ b/Test/Nullability/Optional/MultipleImplementations.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Nullability.Optional.MultipleImplementations; diff --git a/Test/Nullability/Optional/NoImplementation.cs b/Test/Nullability/Optional/NoImplementation.cs index b461709d..2ab9638e 100644 --- a/Test/Nullability/Optional/NoImplementation.cs +++ b/Test/Nullability/Optional/NoImplementation.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Nullability.Optional.NoImplementation; diff --git a/Test/Record/CustomProperty.cs b/Test/Record/CustomProperty.cs index ca37247e..2c7245ab 100644 --- a/Test/Record/CustomProperty.cs +++ b/Test/Record/CustomProperty.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Record.CustomPropert; diff --git a/Test/Record/PrimaryConstr.cs b/Test/Record/PrimaryConstr.cs index 330c26b2..f8987bc4 100644 --- a/Test/Record/PrimaryConstr.cs +++ b/Test/Record/PrimaryConstr.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Record.PrimaryConstr; diff --git a/Test/Record/Vanilla.cs b/Test/Record/Vanilla.cs index fccdb594..2a9341a2 100644 --- a/Test/Record/Vanilla.cs +++ b/Test/Record/Vanilla.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Record.Vanilla; diff --git a/Test/Scoping/ScopeSpecificAttributes/Decorator.cs b/Test/Scoping/ScopeSpecificAttributes/Decorator.cs index df23fac2..bd325016 100644 --- a/Test/Scoping/ScopeSpecificAttributes/Decorator.cs +++ b/Test/Scoping/ScopeSpecificAttributes/Decorator.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Scoping.ScopeSpecificAttributes.Decorator; diff --git a/Test/Scoping/ScopeSpecificAttributes/Implementation.cs b/Test/Scoping/ScopeSpecificAttributes/Implementation.cs index 0e4ad6fa..23a96aef 100644 --- a/Test/Scoping/ScopeSpecificAttributes/Implementation.cs +++ b/Test/Scoping/ScopeSpecificAttributes/Implementation.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Scoping.ScopeSpecificAttributes.Implementation; diff --git a/Test/Scoping/ScopeSpecificAttributes/ImplementationCollection.cs b/Test/Scoping/ScopeSpecificAttributes/ImplementationCollection.cs index 31f0a4b9..5e50fe8b 100644 --- a/Test/Scoping/ScopeSpecificAttributes/ImplementationCollection.cs +++ b/Test/Scoping/ScopeSpecificAttributes/ImplementationCollection.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Scoping.ScopeSpecificAttributes.ImplementationCollection; diff --git a/Test/Scoping/TransientScopeInstance/InContainer.cs b/Test/Scoping/TransientScopeInstance/InContainer.cs index 6e0b4109..6e7dc364 100644 --- a/Test/Scoping/TransientScopeInstance/InContainer.cs +++ b/Test/Scoping/TransientScopeInstance/InContainer.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Scoping.TransientScopeInstance.InContainer; diff --git a/Test/Scoping/TransientScopeInstance/InScope.cs b/Test/Scoping/TransientScopeInstance/InScope.cs index 1ced8047..462ffc55 100644 --- a/Test/Scoping/TransientScopeInstance/InScope.cs +++ b/Test/Scoping/TransientScopeInstance/InScope.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Scoping.TransientScopeInstance.InContainer.InScope; diff --git a/Test/Scoping/TransientScopeInstance/InScopeInScope.cs b/Test/Scoping/TransientScopeInstance/InScopeInScope.cs index 79c64d5e..826bcd90 100644 --- a/Test/Scoping/TransientScopeInstance/InScopeInScope.cs +++ b/Test/Scoping/TransientScopeInstance/InScopeInScope.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Scoping.TransientScopeInstance.InContainer.InScopeInScope; diff --git a/Test/Scoping/TransientScopeInstance/InTransientScope.cs b/Test/Scoping/TransientScopeInstance/InTransientScope.cs index 501f200e..9fffbc54 100644 --- a/Test/Scoping/TransientScopeInstance/InTransientScope.cs +++ b/Test/Scoping/TransientScopeInstance/InTransientScope.cs @@ -1,5 +1,5 @@ using System; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Scoping.TransientScopeInstance.InContainer.InTransientScope; diff --git a/Test/Scoping/TransientScopeInstance/InTransientScopeWithScopes.cs b/Test/Scoping/TransientScopeInstance/InTransientScopeWithScopes.cs index 01657ebd..da4371d7 100644 --- a/Test/Scoping/TransientScopeInstance/InTransientScopeWithScopes.cs +++ b/Test/Scoping/TransientScopeInstance/InTransientScopeWithScopes.cs @@ -1,5 +1,5 @@ using System; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Scoping.TransientScopeInstance.InContainer.InTransientScopeWithScopes; diff --git a/Test/Struct/NoExplicitConstructor.cs b/Test/Struct/NoExplicitConstructor.cs index 767af494..ce9c3109 100644 --- a/Test/Struct/NoExplicitConstructor.cs +++ b/Test/Struct/NoExplicitConstructor.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Struct.NoExplicitConstructor; diff --git a/Test/Struct/OneExplicitConstructor.cs b/Test/Struct/OneExplicitConstructor.cs index 86f4a7ff..1df204f0 100644 --- a/Test/Struct/OneExplicitConstructor.cs +++ b/Test/Struct/OneExplicitConstructor.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Struct.OneExplicitConstructor; diff --git a/Test/Struct/RecordNoExplicitConstructor.cs b/Test/Struct/RecordNoExplicitConstructor.cs index f10a51f8..5063e1a0 100644 --- a/Test/Struct/RecordNoExplicitConstructor.cs +++ b/Test/Struct/RecordNoExplicitConstructor.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Struct.RecordNoExplicitConstructor; diff --git a/Test/Struct/RecordOneExplicitConstructor.cs b/Test/Struct/RecordOneExplicitConstructor.cs index 28842425..5857b1c2 100644 --- a/Test/Struct/RecordOneExplicitConstructor.cs +++ b/Test/Struct/RecordOneExplicitConstructor.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Struct.RecordOneExplicitConstructor; diff --git a/Test/TypeInitializer/AsyncTask.cs b/Test/TypeInitializer/AsyncTask.cs index 41b4bf1f..376fa518 100644 --- a/Test/TypeInitializer/AsyncTask.cs +++ b/Test/TypeInitializer/AsyncTask.cs @@ -1,5 +1,5 @@ using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.TypeInitializer.AsyncTask; diff --git a/Test/TypeInitializer/AsyncValueTask.cs b/Test/TypeInitializer/AsyncValueTask.cs index 7d355aa5..d5e4df4f 100644 --- a/Test/TypeInitializer/AsyncValueTask.cs +++ b/Test/TypeInitializer/AsyncValueTask.cs @@ -1,5 +1,5 @@ using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.TypeInitializer.AsyncValueTask; diff --git a/Test/TypeInitializer/Sync.cs b/Test/TypeInitializer/Sync.cs index 396b275d..5f00598a 100644 --- a/Test/TypeInitializer/Sync.cs +++ b/Test/TypeInitializer/Sync.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.TypeInitializer.Sync; diff --git a/Test/ValueTuple/NonSyntaxVariant.cs b/Test/ValueTuple/NonSyntaxVariant.cs index 6e782a7a..c874d470 100644 --- a/Test/ValueTuple/NonSyntaxVariant.cs +++ b/Test/ValueTuple/NonSyntaxVariant.cs @@ -1,5 +1,5 @@ using System; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.ValueTuple.NonSyntaxVariant; diff --git a/Test/ValueTuple/NonSyntaxVariantSingleItem.cs b/Test/ValueTuple/NonSyntaxVariantSingleItem.cs index 3589babb..754fee05 100644 --- a/Test/ValueTuple/NonSyntaxVariantSingleItem.cs +++ b/Test/ValueTuple/NonSyntaxVariantSingleItem.cs @@ -1,5 +1,5 @@ using System; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.ValueTuple.NonSyntaxVariantSingleItem; diff --git a/Test/ValueTuple/SyntaxVariant.cs b/Test/ValueTuple/SyntaxVariant.cs index b9deaef2..9d4eb84b 100644 --- a/Test/ValueTuple/SyntaxVariant.cs +++ b/Test/ValueTuple/SyntaxVariant.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.ValueTuple.SyntaxVariant; diff --git a/Test/ValueTuple/ValueTupleTests.cs b/Test/ValueTuple/ValueTupleTests.cs index fb0acf1d..ff1b468f 100644 --- a/Test/ValueTuple/ValueTupleTests.cs +++ b/Test/ValueTuple/ValueTupleTests.cs @@ -1,5 +1,5 @@ using System; -using MrMeeseeks.DIE.Configuration; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.ValueTuple.NonSyntaxVariantDoubleItem; From 05ad2c6e26862db981cbec83342c7cb9457c8dc1 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Thu, 26 May 2022 11:18:36 +0200 Subject: [PATCH 074/162] Preparations --- Main/Configuration/Attributes/Aggregation.cs | 4 +- .../Configuration/CurrentlyConsideredTypes.cs | 2 +- Main/Configuration/TypesFromAttributes.cs | 64 ++++++++++- Main/WellKnownTypesAggregation.cs | 104 +++++++++++++++++- 4 files changed, 163 insertions(+), 11 deletions(-) diff --git a/Main/Configuration/Attributes/Aggregation.cs b/Main/Configuration/Attributes/Aggregation.cs index e3050c93..21c94a45 100644 --- a/Main/Configuration/Attributes/Aggregation.cs +++ b/Main/Configuration/Attributes/Aggregation.cs @@ -167,9 +167,9 @@ public FilterScopeInstanceAbstractionAggregationAttribute(params Type[] types) { } [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] -public class ScopeInstanceAbstractionImplementationAttribute : Attribute +public class ScopeInstanceImplementationAggregationAttribute : Attribute { - public ScopeInstanceAbstractionImplementationAttribute(params Type[] types) {} + public ScopeInstanceImplementationAggregationAttribute(params Type[] types) {} } [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] diff --git a/Main/Configuration/CurrentlyConsideredTypes.cs b/Main/Configuration/CurrentlyConsideredTypes.cs index a238a25e..68b76226 100644 --- a/Main/Configuration/CurrentlyConsideredTypes.cs +++ b/Main/Configuration/CurrentlyConsideredTypes.cs @@ -151,7 +151,7 @@ public CurrentlyConsideredTypes( t => t.FilterAsyncTransientAbstraction.Concat(t.FilterTransientAbstraction).ToList()); ContainerInstanceTypes = GetSetOfTypesWithProperties(t => t.ContainerInstanceAbstraction, t => t.FilterContainerInstanceAbstraction); TransientScopeInstanceTypes = GetSetOfTypesWithProperties(t => t.TransientScopeInstanceAbstraction, t => t.FilterTransientScopeInstanceAbstraction); - ScopeInstanceTypes = GetSetOfTypesWithProperties(t => t.ScopeInstance, t => t.FilterScopeInstanceAbstraction); + ScopeInstanceTypes = GetSetOfTypesWithProperties(t => t.ScopeInstanceAbstraction, t => t.FilterScopeInstanceAbstraction); TransientScopeRootTypes = GetSetOfTypesWithProperties(t => t.TransientScopeRootAbstraction, t => t.FilterTransientScopeRootAbstraction); ScopeRootTypes = GetSetOfTypesWithProperties(t => t.ScopeRootAbstraction, t => t.FilterScopeRootAbstraction); diff --git a/Main/Configuration/TypesFromAttributes.cs b/Main/Configuration/TypesFromAttributes.cs index 3cd34c2b..720b8e76 100644 --- a/Main/Configuration/TypesFromAttributes.cs +++ b/Main/Configuration/TypesFromAttributes.cs @@ -10,11 +10,19 @@ internal interface ITypesFromAttributes IReadOnlyList AsyncTransientAbstraction { get; } IReadOnlyList ContainerInstanceAbstraction { get; } IReadOnlyList TransientScopeInstanceAbstraction { get; } - IReadOnlyList ScopeInstance { get; } + IReadOnlyList ScopeInstanceAbstraction { get; } IReadOnlyList TransientScopeRootAbstraction { get; } IReadOnlyList ScopeRootAbstraction { get; } IReadOnlyList DecoratorAbstraction { get; } IReadOnlyList CompositeAbstraction { get; } + IReadOnlyList TransientImplementation { get; } + IReadOnlyList SyncTransientImplementation { get; } + IReadOnlyList AsyncTransientImplementation { get; } + IReadOnlyList ContainerInstanceImplementation { get; } + IReadOnlyList TransientScopeInstanceImplementation { get; } + IReadOnlyList ScopeInstanceImplementation { get; } + IReadOnlyList TransientScopeRootImplementation { get; } + IReadOnlyList ScopeRootImplementation { get; } IReadOnlyList<(INamedTypeSymbol, IReadOnlyList)> DecoratorSequenceChoices { get; } IReadOnlyList<(INamedTypeSymbol, IMethodSymbol)> ConstructorChoices { get; } IReadOnlyList<(INamedTypeSymbol, IMethodSymbol)> TypeInitializers { get; } @@ -36,6 +44,14 @@ internal interface ITypesFromAttributes IReadOnlyList FilterScopeRootAbstraction { get; } IReadOnlyList FilterDecoratorAbstraction { get; } IReadOnlyList FilterCompositeAbstraction { get; } + IReadOnlyList FilterTransientImplementation { get; } + IReadOnlyList FilterSyncTransientImplementation { get; } + IReadOnlyList FilterAsyncTransientImplementation { get; } + IReadOnlyList FilterContainerInstanceImplementation { get; } + IReadOnlyList FilterTransientScopeInstanceImplementation { get; } + IReadOnlyList FilterScopeInstanceImplementation { get; } + IReadOnlyList FilterTransientScopeRootImplementation { get; } + IReadOnlyList FilterScopeRootImplementation { get; } IReadOnlyList FilterDecoratorSequenceChoices { get; } IReadOnlyList FilterConstructorChoices { get; } IReadOnlyList FilterTypeInitializers { get; } @@ -64,10 +80,18 @@ internal TypesFromAttributes( TransientScopeInstanceAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.TransientScopeInstanceAbstractionAggregationAttribute).ToList(); TransientScopeRootAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.TransientScopeRootAbstractionAggregationAttribute).ToList(); ScopeRootAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.ScopeRootAbstractionAggregationAttribute).ToList(); + ContainerInstanceImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.ContainerInstanceImplementationAggregationAttribute).ToList(); + TransientScopeInstanceImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.TransientScopeInstanceImplementationAggregationAttribute).ToList(); + TransientScopeRootImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.TransientScopeRootImplementationAggregationAttribute).ToList(); + ScopeRootImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.ScopeRootImplementationAggregationAttribute).ToList(); FilterContainerInstanceAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.FilterContainerInstanceAbstractionAggregationAttribute).ToList(); FilterTransientScopeInstanceAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.FilterTransientScopeInstanceAbstractionAggregationAttribute).ToList(); FilterTransientScopeRootAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.FilterTransientScopeRootAbstractionAggregationAttribute).ToList(); FilterScopeRootAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.FilterScopeRootAbstractionAggregationAttribute).ToList(); + FilterContainerInstanceImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.FilterContainerInstanceImplementationAggregationAttribute).ToList(); + FilterTransientScopeInstanceImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.FilterTransientScopeInstanceImplementationAggregationAttribute).ToList(); + FilterTransientScopeRootImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.FilterTransientScopeRootImplementationAggregationAttribute).ToList(); + FilterScopeRootImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.FilterScopeRootImplementationAggregationAttribute).ToList(); } } @@ -92,11 +116,19 @@ internal ScopeTypesFromAttributes( AsyncTransientAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.AsyncTransientAbstractionAggregationAttribute).ToList(); ContainerInstanceAbstraction = new List(); TransientScopeInstanceAbstraction = new List(); - ScopeInstance = GetTypesFromAttribute(wellKnownTypesAggregation.ScopeInstanceAbstractionAggregationAttribute).ToList(); + ScopeInstanceAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.ScopeInstanceAbstractionAggregationAttribute).ToList(); TransientScopeRootAbstraction = new List(); ScopeRootAbstraction = new List(); DecoratorAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.DecoratorAbstractionAggregationAttribute).ToList(); CompositeAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.CompositeAbstractionAggregationAttribute).ToList(); + TransientImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.TransientImplementationAggregationAttribute).ToList(); + SyncTransientImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.SyncTransientImplementationAggregationAttribute).ToList(); + AsyncTransientImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.AsyncTransientImplementationAggregationAttribute).ToList(); + ContainerInstanceImplementation = new List(); + TransientScopeInstanceImplementation = new List(); + ScopeInstanceImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.ScopeInstanceImplementationAggregationAttribute).ToList(); + TransientScopeRootImplementation = new List(); + ScopeRootImplementation = new List(); FilterImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.FilterImplementationAggregationAttribute).ToList(); FilterTransientAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.FilterTransientAbstractionAggregationAttribute).ToList(); @@ -109,6 +141,14 @@ internal ScopeTypesFromAttributes( FilterScopeRootAbstraction = new List(); FilterDecoratorAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.FilterDecoratorAbstractionAggregationAttribute).ToList(); FilterCompositeAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.FilterCompositeAbstractionAggregationAttribute).ToList(); + FilterTransientImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.FilterTransientImplementationAggregationAttribute).ToList(); + FilterSyncTransientImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.FilterSyncTransientImplementationAggregationAttribute).ToList(); + FilterAsyncTransientImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.FilterAsyncTransientImplementationAggregationAttribute).ToList(); + FilterContainerInstanceImplementation = new List(); + FilterTransientScopeInstanceImplementation = new List(); + FilterScopeInstanceImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.FilterScopeInstanceImplementationAggregationAttribute).ToList(); + FilterTransientScopeRootImplementation = new List(); + FilterScopeRootImplementation = new List(); DecoratorSequenceChoices = (AttributeDictionary.TryGetValue(wellKnownTypesChoice.DecoratorSequenceChoiceAttribute, out var decoratorSequenceChoiceAttributes) ? decoratorSequenceChoiceAttributes @@ -413,7 +453,7 @@ internal ScopeTypesFromAttributes( .OfType() .ToList(); - FilterAssemblyImplementations = (AttributeDictionary.TryGetValue(wellKnownTypesAggregation.FilterAllImplementationsAggregationAttribute, out var filterAssemblyImplementationsAttributes) + FilterAssemblyImplementations = (AttributeDictionary.TryGetValue(wellKnownTypesAggregation.FilterAssemblyImplementationsAggregationAttribute, out var filterAssemblyImplementationsAttributes) ? filterAssemblyImplementationsAttributes : Enumerable.Empty()) .SelectMany(ad => ad.ConstructorArguments.Length < 1 @@ -499,11 +539,19 @@ bool CheckValidType(TypedConstant typedConstant, out INamedTypeSymbol type) public IReadOnlyList AsyncTransientAbstraction { get; } public IReadOnlyList ContainerInstanceAbstraction { get; protected init; } public IReadOnlyList TransientScopeInstanceAbstraction { get; protected init; } - public IReadOnlyList ScopeInstance { get; } + public IReadOnlyList ScopeInstanceAbstraction { get; } public IReadOnlyList TransientScopeRootAbstraction { get; protected init; } public IReadOnlyList ScopeRootAbstraction { get; protected init; } public IReadOnlyList DecoratorAbstraction { get; } public IReadOnlyList CompositeAbstraction { get; } + public IReadOnlyList TransientImplementation { get; } + public IReadOnlyList SyncTransientImplementation { get; } + public IReadOnlyList AsyncTransientImplementation { get; } + public IReadOnlyList ContainerInstanceImplementation { get; protected init; } + public IReadOnlyList TransientScopeInstanceImplementation { get; protected init; } + public IReadOnlyList ScopeInstanceImplementation { get; } + public IReadOnlyList TransientScopeRootImplementation { get; protected init; } + public IReadOnlyList ScopeRootImplementation { get; protected init; } public IReadOnlyList<(INamedTypeSymbol, IReadOnlyList)> DecoratorSequenceChoices { get; } public IReadOnlyList<(INamedTypeSymbol, IMethodSymbol)> ConstructorChoices { get; } public IReadOnlyList<(INamedTypeSymbol, IMethodSymbol)> TypeInitializers { get; } @@ -525,6 +573,14 @@ bool CheckValidType(TypedConstant typedConstant, out INamedTypeSymbol type) public IReadOnlyList FilterScopeRootAbstraction { get; protected init; } public IReadOnlyList FilterDecoratorAbstraction { get; } public IReadOnlyList FilterCompositeAbstraction { get; } + public IReadOnlyList FilterTransientImplementation { get; } + public IReadOnlyList FilterSyncTransientImplementation { get; } + public IReadOnlyList FilterAsyncTransientImplementation { get; } + public IReadOnlyList FilterContainerInstanceImplementation { get; protected init; } + public IReadOnlyList FilterTransientScopeInstanceImplementation { get; protected init; } + public IReadOnlyList FilterScopeInstanceImplementation { get; } + public IReadOnlyList FilterTransientScopeRootImplementation { get; protected init; } + public IReadOnlyList FilterScopeRootImplementation { get; protected init; } public IReadOnlyList FilterDecoratorSequenceChoices { get; } public IReadOnlyList FilterConstructorChoices { get; } public IReadOnlyList FilterTypeInitializers { get; } diff --git a/Main/WellKnownTypesAggregation.cs b/Main/WellKnownTypesAggregation.cs index 9abef691..7db77db3 100644 --- a/Main/WellKnownTypesAggregation.cs +++ b/Main/WellKnownTypesAggregation.cs @@ -14,6 +14,14 @@ internal record WellKnownTypesAggregation( INamedTypeSymbol ScopeRootAbstractionAggregationAttribute, INamedTypeSymbol DecoratorAbstractionAggregationAttribute, INamedTypeSymbol CompositeAbstractionAggregationAttribute, + INamedTypeSymbol TransientImplementationAggregationAttribute, + INamedTypeSymbol SyncTransientImplementationAggregationAttribute, + INamedTypeSymbol AsyncTransientImplementationAggregationAttribute, + INamedTypeSymbol ContainerInstanceImplementationAggregationAttribute, + INamedTypeSymbol TransientScopeInstanceImplementationAggregationAttribute, + INamedTypeSymbol ScopeInstanceImplementationAggregationAttribute, + INamedTypeSymbol TransientScopeRootImplementationAggregationAttribute, + INamedTypeSymbol ScopeRootImplementationAggregationAttribute, INamedTypeSymbol AllImplementationsAggregationAttribute, INamedTypeSymbol AssemblyImplementationsAggregationAttribute, INamedTypeSymbol FilterImplementationAggregationAttribute, @@ -27,6 +35,14 @@ internal record WellKnownTypesAggregation( INamedTypeSymbol FilterScopeRootAbstractionAggregationAttribute, INamedTypeSymbol FilterDecoratorAbstractionAggregationAttribute, INamedTypeSymbol FilterCompositeAbstractionAggregationAttribute, + INamedTypeSymbol FilterTransientImplementationAggregationAttribute, + INamedTypeSymbol FilterSyncTransientImplementationAggregationAttribute, + INamedTypeSymbol FilterAsyncTransientImplementationAggregationAttribute, + INamedTypeSymbol FilterContainerInstanceImplementationAggregationAttribute, + INamedTypeSymbol FilterTransientScopeInstanceImplementationAggregationAttribute, + INamedTypeSymbol FilterScopeInstanceImplementationAggregationAttribute, + INamedTypeSymbol FilterTransientScopeRootImplementationAggregationAttribute, + INamedTypeSymbol FilterScopeRootImplementationAggregationAttribute, INamedTypeSymbol FilterAllImplementationsAggregationAttribute, INamedTypeSymbol FilterAssemblyImplementationsAggregationAttribute) { @@ -65,6 +81,30 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypesAggreg var compositeAbstractionAggregationAttribute = compilation .GetTypeByMetadataName(typeof(CompositeAbstractionAggregationAttribute).FullName ?? ""); + var transientImplementationAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(TransientImplementationAggregationAttribute).FullName ?? ""); + + var syncTransientImplementationAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(SyncTransientImplementationAggregationAttribute).FullName ?? ""); + + var asyncTransientImplementationAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(AsyncTransientImplementationAggregationAttribute).FullName ?? ""); + + var containerInstanceImplementationAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(ContainerInstanceImplementationAggregationAttribute).FullName ?? ""); + + var transientScopeInstanceImplementationAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(TransientScopeInstanceImplementationAggregationAttribute).FullName ?? ""); + + var scopeInstanceImplementationAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(ScopeInstanceImplementationAggregationAttribute).FullName ?? ""); + + var transientScopeRootImplementationAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(TransientScopeRootImplementationAggregationAttribute).FullName ?? ""); + + var scopeRootImplementationAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(ScopeRootImplementationAggregationAttribute).FullName ?? ""); + var allImplementationsAggregationAttribute = compilation .GetTypeByMetadataName(typeof(AllImplementationsAggregationAttribute).FullName ?? ""); @@ -110,6 +150,30 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypesAggreg var filterCompositeAbstractionAggregationAttribute = compilation .GetTypeByMetadataName(typeof(FilterCompositeAbstractionAggregationAttribute).FullName ?? ""); + var filterTransientImplementationAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(FilterTransientImplementationAggregationAttribute).FullName ?? ""); + + var filterSyncTransientImplementationAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(FilterSyncTransientImplementationAggregationAttribute).FullName ?? ""); + + var filterAsyncTransientImplementationAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(FilterAsyncTransientImplementationAggregationAttribute).FullName ?? ""); + + var filterContainerInstanceImplementationAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(FilterContainerInstanceImplementationAggregationAttribute).FullName ?? ""); + + var filterTransientScopeInstanceImplementationAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(FilterTransientScopeInstanceImplementationAggregationAttribute).FullName ?? ""); + + var filterScopeInstanceAggregationImplementationAttribute = compilation + .GetTypeByMetadataName(typeof(FilterScopeInstanceImplementationAggregationAttribute).FullName ?? ""); + + var filterTransientScopeRootAggregationImplementationAttribute = compilation + .GetTypeByMetadataName(typeof(FilterTransientScopeRootImplementationAggregationAttribute).FullName ?? ""); + + var filterScopeRootImplementationAggregationAttribute = compilation + .GetTypeByMetadataName(typeof(FilterScopeRootImplementationAggregationAttribute).FullName ?? ""); + var filterAllImplementationsAggregationAttribute = compilation .GetTypeByMetadataName(typeof(FilterAllImplementationsAggregationAttribute).FullName ?? ""); @@ -123,14 +187,22 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypesAggreg && containerInstanceAbstractionAggregationAttribute is not null && transientScopeInstanceAbstractionAggregationAttribute is not null && scopeInstanceAbstractionAggregationAttribute is not null - && allImplementationsAggregationAttribute is not null - && assemblyImplementationsAggregationAttribute is not null - && implementationChoiceAttribute is not null - && implementationCollectionChoiceAttribute is not null && transientScopeRootAbstractionAggregationAttribute is not null && scopeRootAbstractionAggregationAttribute is not null && decoratorAbstractionAggregationAttribute is not null && compositeAbstractionAggregationAttribute is not null + && transientImplementationAggregationAttribute is not null + && syncTransientImplementationAggregationAttribute is not null + && asyncTransientImplementationAggregationAttribute is not null + && containerInstanceImplementationAggregationAttribute is not null + && transientScopeInstanceImplementationAggregationAttribute is not null + && scopeInstanceImplementationAggregationAttribute is not null + && transientScopeRootImplementationAggregationAttribute is not null + && scopeRootImplementationAggregationAttribute is not null + && allImplementationsAggregationAttribute is not null + && assemblyImplementationsAggregationAttribute is not null + && implementationChoiceAttribute is not null + && implementationCollectionChoiceAttribute is not null && filterImplementationAggregationAttribute is not null && filterTransientAbstractionAggregationAttribute is not null && filterSyncTransientAbstractionAggregationAttribute is not null @@ -142,6 +214,14 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypesAggreg && filterScopeRootAbstractionAggregationAttribute is not null && filterDecoratorAbstractionAggregationAttribute is not null && filterCompositeAbstractionAggregationAttribute is not null + && filterTransientImplementationAggregationAttribute is not null + && filterSyncTransientImplementationAggregationAttribute is not null + && filterAsyncTransientImplementationAggregationAttribute is not null + && filterContainerInstanceImplementationAggregationAttribute is not null + && filterTransientScopeInstanceImplementationAggregationAttribute is not null + && filterScopeInstanceAggregationImplementationAttribute is not null + && filterTransientScopeRootAggregationImplementationAttribute is not null + && filterScopeRootImplementationAggregationAttribute is not null && filterAllImplementationsAggregationAttribute is not null && filterAssemblyImplementationsAggregationAttribute is not null) { @@ -158,6 +238,14 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypesAggreg ScopeRootAbstractionAggregationAttribute: scopeRootAbstractionAggregationAttribute, DecoratorAbstractionAggregationAttribute: decoratorAbstractionAggregationAttribute, CompositeAbstractionAggregationAttribute: compositeAbstractionAggregationAttribute, + TransientImplementationAggregationAttribute: transientImplementationAggregationAttribute, + SyncTransientImplementationAggregationAttribute: syncTransientImplementationAggregationAttribute, + AsyncTransientImplementationAggregationAttribute: asyncTransientImplementationAggregationAttribute, + ContainerInstanceImplementationAggregationAttribute: containerInstanceImplementationAggregationAttribute, + TransientScopeInstanceImplementationAggregationAttribute: transientScopeInstanceImplementationAggregationAttribute, + ScopeInstanceImplementationAggregationAttribute: scopeInstanceImplementationAggregationAttribute, + TransientScopeRootImplementationAggregationAttribute: transientScopeRootImplementationAggregationAttribute, + ScopeRootImplementationAggregationAttribute: scopeRootImplementationAggregationAttribute, AllImplementationsAggregationAttribute: allImplementationsAggregationAttribute, AssemblyImplementationsAggregationAttribute: assemblyImplementationsAggregationAttribute, FilterImplementationAggregationAttribute: filterImplementationAggregationAttribute, @@ -171,6 +259,14 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypesAggreg FilterScopeRootAbstractionAggregationAttribute: filterScopeRootAbstractionAggregationAttribute, FilterDecoratorAbstractionAggregationAttribute: filterDecoratorAbstractionAggregationAttribute, FilterCompositeAbstractionAggregationAttribute: filterCompositeAbstractionAggregationAttribute, + FilterTransientImplementationAggregationAttribute: filterTransientImplementationAggregationAttribute, + FilterSyncTransientImplementationAggregationAttribute: filterSyncTransientImplementationAggregationAttribute, + FilterAsyncTransientImplementationAggregationAttribute: filterAsyncTransientImplementationAggregationAttribute, + FilterContainerInstanceImplementationAggregationAttribute: filterContainerInstanceImplementationAggregationAttribute, + FilterTransientScopeInstanceImplementationAggregationAttribute: filterTransientScopeInstanceImplementationAggregationAttribute, + FilterScopeInstanceImplementationAggregationAttribute: filterScopeInstanceAggregationImplementationAttribute, + FilterTransientScopeRootImplementationAggregationAttribute: filterTransientScopeRootAggregationImplementationAttribute, + FilterScopeRootImplementationAggregationAttribute: filterScopeRootImplementationAggregationAttribute, FilterAllImplementationsAggregationAttribute: filterAllImplementationsAggregationAttribute, FilterAssemblyImplementationsAggregationAttribute: filterAssemblyImplementationsAggregationAttribute); return true; From 2b68bce8787d96d8d8f2abba759b1027465adfd7 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Fri, 27 May 2022 14:02:37 +0200 Subject: [PATCH 075/162] Performance improvements by not iterating over all implementations unnecessarily --- Main/Configuration/CheckTypeProperties.cs | 74 ++- .../Configuration/CurrentlyConsideredTypes.cs | 224 +++++---- Main/Configuration/TypesFromAttributes.cs | 461 +++++++++--------- .../Function/FunctionResolutionBuilder.cs | 4 +- .../NamedTypeSymbolEqualityComparer.cs | 18 + Sample/Context.cs | 35 +- Sample/Program.cs | 2 +- Sample/Sample.csproj | 3 +- Test/Test.csproj | 3 +- 9 files changed, 471 insertions(+), 353 deletions(-) create mode 100644 Main/Utility/NamedTypeSymbolEqualityComparer.cs diff --git a/Main/Configuration/CheckTypeProperties.cs b/Main/Configuration/CheckTypeProperties.cs index 97eaac87..dbef8b5b 100644 --- a/Main/Configuration/CheckTypeProperties.cs +++ b/Main/Configuration/CheckTypeProperties.cs @@ -66,18 +66,23 @@ public DisposalType ShouldDisposalBeManaged(INamedTypeSymbol implementationType) public ScopeLevel ShouldBeScopeRoot(INamedTypeSymbol implementationType) { - if (_currentlyConsideredTypes.TransientScopeRootTypes.Contains(implementationType.UnboundIfGeneric())) return ScopeLevel.TransientScope; - return _currentlyConsideredTypes.ScopeRootTypes.Contains(implementationType.UnboundIfGeneric()) ? ScopeLevel.Scope : ScopeLevel.None; + var unbound = implementationType.UnboundIfGeneric(); + if (_currentlyConsideredTypes.TransientScopeRootTypes.Contains(implementationType.UnboundIfGeneric())) + return ScopeLevel.TransientScope; + if (_currentlyConsideredTypes.ScopeRootTypes.Contains(implementationType.UnboundIfGeneric())) + return ScopeLevel.Scope; + return ScopeLevel.None; } public bool ShouldBeComposite(INamedTypeSymbol interfaceType) => _currentlyConsideredTypes.InterfaceToComposite.ContainsKey(interfaceType.UnboundIfGeneric()); public ScopeLevel GetScopeLevelFor(INamedTypeSymbol implementationType) { - if (_currentlyConsideredTypes.ContainerInstanceTypes.Contains(implementationType.UnboundIfGeneric())) + var unbound = implementationType.UnboundIfGeneric(); + if (_currentlyConsideredTypes.ContainerInstanceTypes.Contains(unbound)) return ScopeLevel.Container; - if (_currentlyConsideredTypes.TransientScopeInstanceTypes.Contains(implementationType.UnboundIfGeneric())) + if (_currentlyConsideredTypes.TransientScopeInstanceTypes.Contains(unbound)) return ScopeLevel.TransientScope; - if (_currentlyConsideredTypes.ScopeInstanceTypes.Contains(implementationType.UnboundIfGeneric())) + if (_currentlyConsideredTypes.ScopeInstanceTypes.Contains(unbound)) return ScopeLevel.Scope; return ScopeLevel.None; } @@ -87,8 +92,10 @@ public ScopeLevel GetScopeLevelFor(INamedTypeSymbol implementationType) var compositeImplementation = _currentlyConsideredTypes.InterfaceToComposite[interfaceType.UnboundIfGeneric()]; var implementations = GetClosedImplementations( interfaceType, - new[] { compositeImplementation }, - true); + ImmutableHashSet.Create(compositeImplementation), + true, + true, + false); if (implementations.Count != 1) return null; @@ -106,20 +113,20 @@ public ScopeLevel GetScopeLevelFor(INamedTypeSymbol implementationType) return typeToChoseFrom switch { // If reference record and two constructors, decide for the constructor which isn't the copy-constructor - { IsRecord: true, IsReferenceType: true, IsValueType: false, Constructors.Length: 2 } + { IsRecord: true, IsReferenceType: true, IsValueType: false, InstanceConstructors.Length: 2 } when typeToChoseFrom - .Constructors.SingleOrDefault(c => + .InstanceConstructors.SingleOrDefault(c => c.Parameters.Length != 1 || !SymbolEqualityComparer.Default.Equals(c.Parameters[0].Type, implementationType)) is { } constructor => constructor, // If value type and two constructors, decide for the constructor which isn't the parameterless constructor - { IsRecord: true or false, IsReferenceType: false, IsValueType: true, Constructors.Length: 2 } - when typeToChoseFrom.Constructors.SingleOrDefault(c => c.Parameters.Length > 0) + { IsRecord: true or false, IsReferenceType: false, IsValueType: true, InstanceConstructors.Length: 2 } + when typeToChoseFrom.InstanceConstructors.SingleOrDefault(c => c.Parameters.Length > 0) is { } constructor => constructor, // If only one constructor, just choose it - { Constructors.Length: 1 } when typeToChoseFrom.Constructors.SingleOrDefault() + { InstanceConstructors.Length: 1 } when typeToChoseFrom.InstanceConstructors.SingleOrDefault() is { } constructor => constructor, _ => null @@ -143,7 +150,9 @@ public IReadOnlyList GetSequenceFor(INamedTypeSymbol interface { var implementations = GetClosedImplementations( interfaceType, - new[] { imp }, + ImmutableHashSet.Create(imp), + true, + false, true); if (implementations.Count != 1) return null; @@ -166,7 +175,7 @@ public IReadOnlyList GetSequenceFor(INamedTypeSymbol interface if (choice is not null) { - var possibleChoices = GetClosedImplementations(type, new [] { choice }, true); + var possibleChoices = GetClosedImplementations(type, ImmutableHashSet.Create(choice), true, false, false); return possibleChoices.Count == 1 ? possibleChoices.FirstOrDefault() : null; @@ -174,14 +183,14 @@ public IReadOnlyList GetSequenceFor(INamedTypeSymbol interface if (type is { TypeKind: not TypeKind.Interface, IsAbstract: false, IsStatic: false }) { - var possibleConcreteTypeImplementations = GetClosedImplementations(type, new [] { type }, true); + var possibleConcreteTypeImplementations = GetClosedImplementations(type, ImmutableHashSet.Create(type), true, false, false); return possibleConcreteTypeImplementations.Count == 1 ? possibleConcreteTypeImplementations.FirstOrDefault() : null; } var possibleImplementations = _currentlyConsideredTypes.ImplementationMap.TryGetValue(type.UnboundIfGeneric(), out var implementations) - ? GetClosedImplementations(type, implementations, true) + ? GetClosedImplementations(type, implementations, true, false, false) : Array.Empty(); return possibleImplementations.Count == 1 @@ -210,19 +219,21 @@ public IReadOnlyList MapToImplementations(INamedTypeSymbol typ : Enumerable.Empty()); if (isChoice && choice is { }) set = set.Add(choice); - return GetClosedImplementations(typeSymbol, set.ToList(), false); + return GetClosedImplementations(typeSymbol, set, false, false, false); } return _currentlyConsideredTypes.ImplementationMap.TryGetValue(typeSymbol.UnboundIfGeneric(), out var implementations) - ? GetClosedImplementations(typeSymbol, implementations, false) + ? GetClosedImplementations(typeSymbol, implementations, false, false, false) : Array.Empty(); } private IReadOnlyList GetClosedImplementations( INamedTypeSymbol targetType, - IReadOnlyList rawImplementations, - bool preferChoicesForOpenGenericParameters) + IImmutableSet rawImplementations, + bool preferChoicesForOpenGenericParameters, + bool chooseComposite, + bool chooseDecorator) { var targetClosedGenericParameters = targetType .TypeArguments @@ -238,7 +249,7 @@ private IReadOnlyList GetClosedImplementations( { if (!implementation.IsGenericType || implementation.TypeArguments.All(ta => ta is INamedTypeSymbol and not IErrorTypeSymbol)) { - ret.Add(implementation); + AddImplementation(ret, implementation); continue; } @@ -288,7 +299,7 @@ ITypeSymbol ForTypeParameterSymbol(ITypeParameterSymbol tps) .AllDerivedTypesAndSelf() .Any(t => SymbolEqualityComparer.Default.Equals(targetType, t))) { - ret.Add(closedImplementation); + AddImplementation(ret, closedImplementation); } } else if (newTypeArguments.Length == originalImplementation.TypeArguments.Length @@ -328,7 +339,7 @@ ITypeSymbol ForTypeParameterSymbol(ITypeParameterSymbol tps) .AllDerivedTypesAndSelf() .Any(t => SymbolEqualityComparer.Default.Equals(targetType, t))) { - ret.Add(closedImplementation); + AddImplementation(ret, closedImplementation); } } } @@ -358,6 +369,23 @@ IEnumerable> GetAll } return ret; + + void AddImplementation(IList implementations, INamedTypeSymbol added) + { + var unbound = added.UnboundIfGeneric(); + if (chooseComposite + && !chooseDecorator + && _currentlyConsideredTypes.CompositeTypes.Contains(unbound)) + implementations.Add(added); + if (!chooseComposite + && chooseDecorator + && _currentlyConsideredTypes.DecoratorTypes.Contains(unbound)) + implementations.Add(added); + if (!chooseComposite && !chooseDecorator + && !_currentlyConsideredTypes.DecoratorTypes.Contains(unbound) + && !_currentlyConsideredTypes.CompositeTypes.Contains(unbound)) + implementations.Add(added); + } } public (INamedTypeSymbol Type, IMethodSymbol Initializer)? GetInitializerFor(INamedTypeSymbol implementationType) diff --git a/Main/Configuration/CurrentlyConsideredTypes.cs b/Main/Configuration/CurrentlyConsideredTypes.cs index 68b76226..dd7cad1a 100644 --- a/Main/Configuration/CurrentlyConsideredTypes.cs +++ b/Main/Configuration/CurrentlyConsideredTypes.cs @@ -4,19 +4,21 @@ namespace MrMeeseeks.DIE.Configuration; internal interface ICurrentlyConsideredTypes { - IImmutableSet SyncTransientTypes { get; } - IImmutableSet AsyncTransientTypes { get; } - IImmutableSet ContainerInstanceTypes { get; } - IImmutableSet TransientScopeInstanceTypes { get; } - IImmutableSet ScopeInstanceTypes { get; } - IImmutableSet TransientScopeRootTypes { get; } - IImmutableSet ScopeRootTypes { get; } + IImmutableSet SyncTransientTypes { get; } + IImmutableSet AsyncTransientTypes { get; } + IImmutableSet ContainerInstanceTypes { get; } + IImmutableSet TransientScopeInstanceTypes { get; } + IImmutableSet ScopeInstanceTypes { get; } + IImmutableSet TransientScopeRootTypes { get; } + IImmutableSet ScopeRootTypes { get; } + IImmutableSet DecoratorTypes { get; } + IImmutableSet CompositeTypes { get; } IReadOnlyDictionary InterfaceToComposite { get; } IReadOnlyDictionary ImplementationToConstructorChoice { get; } IReadOnlyDictionary> InterfaceToDecorators { get; } IReadOnlyDictionary> DecoratorInterfaceSequenceChoices { get; } IReadOnlyDictionary> DecoratorImplementationSequenceChoices { get; } - IReadOnlyDictionary> ImplementationMap { get; } + IReadOnlyDictionary> ImplementationMap { get; } IReadOnlyDictionary ImplementationToInitializer { get; } IReadOnlyDictionary<(INamedTypeSymbol, ITypeParameterSymbol), IReadOnlyList> GenericParameterSubstitutesChoices { get; } IReadOnlyDictionary<(INamedTypeSymbol, ITypeParameterSymbol), INamedTypeSymbol> GenericParameterChoices { get; } @@ -142,19 +144,72 @@ public CurrentlyConsideredTypes( (current, assembly) => current.Union(implementationTypeSetCache.ForAssembly(assembly))); } } + + ImplementationMap = allImplementations + .SelectMany(i => { return i.AllDerivedTypesAndSelf().Select(ii => (ii, i)); }) + .GroupBy(t => t.Item1.UnboundIfGeneric(), t => t.Item2) + .ToDictionary(g => g.Key, g => (IImmutableSet) ImmutableHashSet.CreateRange(g)); + + var transientTypes = GetSetOfTypesWithProperties( + t => t.TransientAbstraction, + t => t.FilterTransientAbstraction, + t => t.TransientImplementation, + t => t.FilterTransientImplementation, + ImplementationMap); + + var syncTransientTypes = GetSetOfTypesWithProperties( + t => t.SyncTransientAbstraction, + t => t.FilterSyncTransientAbstraction, + t => t.SyncTransientImplementation, + t => t.FilterSyncTransientImplementation, + ImplementationMap); + + var asyncTransientTypes = GetSetOfTypesWithProperties( + t => t.AsyncTransientAbstraction, + t => t.FilterAsyncTransientAbstraction, + t => t.AsyncTransientImplementation, + t => t.FilterAsyncTransientImplementation, + ImplementationMap); - SyncTransientTypes = GetSetOfTypesWithProperties( - t => t.SyncTransientAbstraction.Concat(t.TransientAbstraction).ToList(), - t => t.FilterSyncTransientAbstraction.Concat(t.FilterTransientAbstraction).ToList()); - AsyncTransientTypes = GetSetOfTypesWithProperties( - t => t.AsyncTransientAbstraction.Concat(t.TransientAbstraction).ToList(), - t => t.FilterAsyncTransientAbstraction.Concat(t.FilterTransientAbstraction).ToList()); - ContainerInstanceTypes = GetSetOfTypesWithProperties(t => t.ContainerInstanceAbstraction, t => t.FilterContainerInstanceAbstraction); - TransientScopeInstanceTypes = GetSetOfTypesWithProperties(t => t.TransientScopeInstanceAbstraction, t => t.FilterTransientScopeInstanceAbstraction); - ScopeInstanceTypes = GetSetOfTypesWithProperties(t => t.ScopeInstanceAbstraction, t => t.FilterScopeInstanceAbstraction); - TransientScopeRootTypes = GetSetOfTypesWithProperties(t => t.TransientScopeRootAbstraction, t => t.FilterTransientScopeRootAbstraction); - ScopeRootTypes = GetSetOfTypesWithProperties(t => t.ScopeRootAbstraction, t => t.FilterScopeRootAbstraction); + SyncTransientTypes = syncTransientTypes.Union(transientTypes); + AsyncTransientTypes = asyncTransientTypes.Union(transientTypes); + + ContainerInstanceTypes = GetSetOfTypesWithProperties( + t => t.ContainerInstanceAbstraction, + t => t.FilterContainerInstanceAbstraction, + t => t.ContainerInstanceImplementation, + t => t.FilterContainerInstanceImplementation, + ImplementationMap); + + TransientScopeInstanceTypes = GetSetOfTypesWithProperties( + t => t.TransientScopeInstanceAbstraction, + t => t.FilterTransientScopeInstanceAbstraction, + t => t.TransientScopeInstanceImplementation, + t => t.FilterTransientScopeInstanceImplementation, + ImplementationMap); + + ScopeInstanceTypes = GetSetOfTypesWithProperties( + t => t.ScopeInstanceAbstraction, + t => t.FilterScopeInstanceAbstraction, + t => t.ScopeInstanceImplementation, + t => t.FilterScopeInstanceImplementation, + ImplementationMap); + + TransientScopeRootTypes = GetSetOfTypesWithProperties( + t => t.TransientScopeRootAbstraction, + t => t.FilterTransientScopeRootAbstraction, + t => t.TransientScopeRootImplementation, + t => t.FilterTransientScopeRootImplementation, + ImplementationMap); + + ScopeRootTypes = GetSetOfTypesWithProperties( + t => t.ScopeRootAbstraction, + t => t.FilterScopeRootAbstraction, + t => t.ScopeRootImplementation, + t => t.FilterScopeRootImplementation, + ImplementationMap); + var compositeInterfaces = ImmutableHashSet.Empty; foreach (var types in typesFromAttributes) { @@ -162,8 +217,14 @@ public CurrentlyConsideredTypes( compositeInterfaces = compositeInterfaces.Union(types.CompositeAbstraction.Select(c => c.UnboundIfGeneric())); } - var compositeTypes = GetSetOfTypesWithProperties(t => t.CompositeAbstraction, t => t.FilterCompositeAbstraction); - InterfaceToComposite = compositeTypes + CompositeTypes = GetSetOfTypesWithProperties( + t => t.CompositeAbstraction, + t => t.FilterCompositeAbstraction, + _ => ImmutableHashSet.Empty, + _ => ImmutableHashSet.Empty, + ImplementationMap); + + InterfaceToComposite = CompositeTypes .OfType() .GroupBy(nts => { @@ -209,10 +270,14 @@ public CurrentlyConsideredTypes( decoratorInterfaces = decoratorInterfaces.Union(types.DecoratorAbstraction.Select(c => c.UnboundIfGeneric())); } - var decoratorTypes = GetSetOfTypesWithProperties( + DecoratorTypes = GetSetOfTypesWithProperties( t => t.DecoratorAbstraction, - t => t.FilterDecoratorAbstraction); - InterfaceToDecorators = decoratorTypes + t => t.FilterDecoratorAbstraction, + _ => ImmutableHashSet.Empty, + _ => ImmutableHashSet.Empty, + ImplementationMap); + + InterfaceToDecorators = DecoratorTypes .OfType() .GroupBy(nts => { @@ -242,13 +307,6 @@ public CurrentlyConsideredTypes( DecoratorImplementationSequenceChoices = decoratorSequenceChoices .Where(kvp => kvp.Key.TypeKind is TypeKind.Class or TypeKind.Struct) .ToDictionary(kvp => kvp.Key, kvp => kvp.Value); - - ImplementationMap = allImplementations - .Where(t => !decoratorTypes.Contains(t.UnboundIfGeneric())) - .Where(t => !compositeTypes.Contains(t.UnboundIfGeneric())) - .SelectMany(i => { return i.AllDerivedTypesAndSelf().Select(ii => (ii, i)); }) - .GroupBy(t => t.Item1.UnboundIfGeneric(), t => t.Item2) - .ToDictionary(g => g.Key, g => (IReadOnlyList) g.Distinct(SymbolEqualityComparer.Default).OfType().ToList()); var initializers = new Dictionary(SymbolEqualityComparer.Default); @@ -256,17 +314,16 @@ public CurrentlyConsideredTypes( { var filterInterfaceTypes = types .FilterTypeInitializers - .Where(t => t.TypeKind is TypeKind.Interface) - .ToImmutableHashSet(SymbolEqualityComparer.Default); - - foreach (var filterConcreteType in allImplementations - .Where(i => i.OriginalDefinitionIfUnbound().AllDerivedTypesAndSelf() - .Any(inter => filterInterfaceTypes.Contains(inter)))) - initializers.Remove(filterConcreteType); + .Where(t => t is { TypeKind: TypeKind.Interface} or { TypeKind: not TypeKind.Interface, IsAbstract: true}); + + foreach (var interfaceType in filterInterfaceTypes) + if (ImplementationMap.TryGetValue(interfaceType.UnboundIfGeneric(), out var set)) + foreach (var concreteType in set) + initializers.Remove(concreteType.UnboundIfGeneric()); var filterConcreteTypes = types .FilterTypeInitializers - .Where(t => t.TypeKind is TypeKind.Class or TypeKind.Struct) + .Where(t => t is { TypeKind: TypeKind.Class or TypeKind.Struct, IsAbstract: false }) .ToList(); foreach (var filterConcreteType in filterConcreteTypes) @@ -274,28 +331,17 @@ public CurrentlyConsideredTypes( var interfaceTypes = types .TypeInitializers - .Where(ti => ti.Item1.TypeKind is TypeKind.Interface) + .Where(t => t.Item1 is { TypeKind: TypeKind.Interface} or { TypeKind: not TypeKind.Interface, IsAbstract: true}) .ToList(); - - foreach (var (implementationType, interfaceType, initializerMethod) in allImplementations - .Select(i => - { - foreach (var (interfaceType, initializer) in interfaceTypes) - { - if (i.OriginalDefinitionIfUnbound().AllDerivedTypesAndSelf().Contains(interfaceType, SymbolEqualityComparer.Default)) - { - return ((INamedTypeSymbol, INamedTypeSymbol, IMethodSymbol)?) (i, interfaceType, initializer); - } - } - - return null; - }) - .OfType<(INamedTypeSymbol, INamedTypeSymbol, IMethodSymbol)>()) - initializers[implementationType.UnboundIfGeneric()] = (interfaceType, initializerMethod); + + foreach (var tuple in interfaceTypes) + if (ImplementationMap.TryGetValue(tuple.Item1.UnboundIfGeneric(), out var set)) + foreach (var concreteType in set) + initializers[concreteType.UnboundIfGeneric()] = (tuple.Item1.UnboundIfGeneric(), tuple.Item2); var concreteTypes = types .TypeInitializers - .Where(ti => ti.Item1.TypeKind is TypeKind.Class or TypeKind.Struct) + .Where(t => t.Item1 is { TypeKind: TypeKind.Class or TypeKind.Struct, IsAbstract: false }) .ToList(); foreach (var (implementation, initializer) in concreteTypes) @@ -366,53 +412,53 @@ public CurrentlyConsideredTypes( ImplementationCollectionChoices = implementationCollectionChoices; - IImmutableSet GetSetOfTypesWithProperties( - Func> propertyGivingTypesGetter, - Func> filteredPropertyGivingTypesGetter) + IImmutableSet GetSetOfTypesWithProperties( + Func> propertyGivingAbstractTypesGetter, + Func> filteredPropertyGivingAbstractTypesGetter, + Func> propertyGivingImplementationTypesGetter, + Func> filteredPropertyGivingImplementationTypesGetter, + IReadOnlyDictionary> implementationMap) { - var ret = ImmutableHashSet.Empty; + var ret = ImmutableHashSet.Empty; + foreach (var types in typesFromAttributes) { - var filterPropertyGivingTypes = filteredPropertyGivingTypesGetter(types); - ret = ret.Except(allImplementations - .Where(i => - { - var derivedTypes = i.AllDerivedTypesAndSelf().Select(t => t.UnboundIfGeneric()).ToList(); - return filterPropertyGivingTypes.Any(t => - derivedTypes.Contains(t.UnboundIfGeneric(), SymbolEqualityComparer.Default)); - }) - .Select(i => i.UnboundIfGeneric()) - .ToImmutableHashSet(SymbolEqualityComparer.Default)); + var filteredTypes = ImmutableHashSet.CreateRange( + filteredPropertyGivingImplementationTypesGetter(types).Select(t => t.UnboundIfGeneric())); + foreach (var type in filteredPropertyGivingAbstractTypesGetter(types)) + if (implementationMap.TryGetValue(type.UnboundIfGeneric(), out var set)) + filteredTypes = filteredTypes.Union(set.Select(t => t.UnboundIfGeneric())); + + ret = ret.Except(filteredTypes); + + var addedTypes = ImmutableHashSet.CreateRange( + propertyGivingImplementationTypesGetter(types).Select(t => t.UnboundIfGeneric())); + foreach (var type in propertyGivingAbstractTypesGetter(types)) + if (implementationMap.TryGetValue(type.UnboundIfGeneric(), out var set)) + addedTypes = addedTypes.Union(set.Select(t => t.UnboundIfGeneric())); - var propertyGivingTypes = propertyGivingTypesGetter(types); - ret = ret.Union(allImplementations - .Where(i => - { - var derivedTypes = i.AllDerivedTypesAndSelf().Select(t => t.UnboundIfGeneric()).ToList(); - return propertyGivingTypes.Any(t => - derivedTypes.Contains(t.UnboundIfGeneric(), SymbolEqualityComparer.Default)); - }) - .Select(i => i.UnboundIfGeneric()) - .ToImmutableHashSet(SymbolEqualityComparer.Default)); + ret = ret.Union(addedTypes); } return ret; } } - public IImmutableSet SyncTransientTypes { get; } - public IImmutableSet AsyncTransientTypes { get; } - public IImmutableSet ContainerInstanceTypes { get; } - public IImmutableSet TransientScopeInstanceTypes { get; } - public IImmutableSet ScopeInstanceTypes { get; } - public IImmutableSet TransientScopeRootTypes { get; } - public IImmutableSet ScopeRootTypes { get; } + public IImmutableSet SyncTransientTypes { get; } + public IImmutableSet AsyncTransientTypes { get; } + public IImmutableSet ContainerInstanceTypes { get; } + public IImmutableSet TransientScopeInstanceTypes { get; } + public IImmutableSet ScopeInstanceTypes { get; } + public IImmutableSet TransientScopeRootTypes { get; } + public IImmutableSet ScopeRootTypes { get; } + public IImmutableSet DecoratorTypes { get; } + public IImmutableSet CompositeTypes { get; } public IReadOnlyDictionary InterfaceToComposite { get; } public IReadOnlyDictionary ImplementationToConstructorChoice { get; } public IReadOnlyDictionary> InterfaceToDecorators { get; } public IReadOnlyDictionary> DecoratorInterfaceSequenceChoices { get; } public IReadOnlyDictionary> DecoratorImplementationSequenceChoices { get; } - public IReadOnlyDictionary> ImplementationMap { get; } + public IReadOnlyDictionary> ImplementationMap { get; } public IReadOnlyDictionary ImplementationToInitializer { get; } public IReadOnlyDictionary<(INamedTypeSymbol, ITypeParameterSymbol), IReadOnlyList> GenericParameterSubstitutesChoices { get; } public IReadOnlyDictionary<(INamedTypeSymbol, ITypeParameterSymbol), INamedTypeSymbol> GenericParameterChoices { get; } diff --git a/Main/Configuration/TypesFromAttributes.cs b/Main/Configuration/TypesFromAttributes.cs index 720b8e76..69b52104 100644 --- a/Main/Configuration/TypesFromAttributes.cs +++ b/Main/Configuration/TypesFromAttributes.cs @@ -4,64 +4,64 @@ namespace MrMeeseeks.DIE.Configuration; internal interface ITypesFromAttributes { - IReadOnlyList Implementation { get; } - IReadOnlyList TransientAbstraction { get; } - IReadOnlyList SyncTransientAbstraction { get; } - IReadOnlyList AsyncTransientAbstraction { get; } - IReadOnlyList ContainerInstanceAbstraction { get; } - IReadOnlyList TransientScopeInstanceAbstraction { get; } - IReadOnlyList ScopeInstanceAbstraction { get; } - IReadOnlyList TransientScopeRootAbstraction { get; } - IReadOnlyList ScopeRootAbstraction { get; } - IReadOnlyList DecoratorAbstraction { get; } - IReadOnlyList CompositeAbstraction { get; } - IReadOnlyList TransientImplementation { get; } - IReadOnlyList SyncTransientImplementation { get; } - IReadOnlyList AsyncTransientImplementation { get; } - IReadOnlyList ContainerInstanceImplementation { get; } - IReadOnlyList TransientScopeInstanceImplementation { get; } - IReadOnlyList ScopeInstanceImplementation { get; } - IReadOnlyList TransientScopeRootImplementation { get; } - IReadOnlyList ScopeRootImplementation { get; } - IReadOnlyList<(INamedTypeSymbol, IReadOnlyList)> DecoratorSequenceChoices { get; } - IReadOnlyList<(INamedTypeSymbol, IMethodSymbol)> ConstructorChoices { get; } - IReadOnlyList<(INamedTypeSymbol, IMethodSymbol)> TypeInitializers { get; } - IReadOnlyList<(INamedTypeSymbol, ITypeParameterSymbol, IReadOnlyList)> GenericParameterSubstitutesChoices { get; } - IReadOnlyList<(INamedTypeSymbol, ITypeParameterSymbol, INamedTypeSymbol)> GenericParameterChoices { get; } - IReadOnlyList<(INamedTypeSymbol, IReadOnlyList)> PropertyChoices { get; } + IImmutableSet Implementation { get; } + IImmutableSet TransientAbstraction { get; } + IImmutableSet SyncTransientAbstraction { get; } + IImmutableSet AsyncTransientAbstraction { get; } + IImmutableSet ContainerInstanceAbstraction { get; } + IImmutableSet TransientScopeInstanceAbstraction { get; } + IImmutableSet ScopeInstanceAbstraction { get; } + IImmutableSet TransientScopeRootAbstraction { get; } + IImmutableSet ScopeRootAbstraction { get; } + IImmutableSet DecoratorAbstraction { get; } + IImmutableSet CompositeAbstraction { get; } + IImmutableSet TransientImplementation { get; } + IImmutableSet SyncTransientImplementation { get; } + IImmutableSet AsyncTransientImplementation { get; } + IImmutableSet ContainerInstanceImplementation { get; } + IImmutableSet TransientScopeInstanceImplementation { get; } + IImmutableSet ScopeInstanceImplementation { get; } + IImmutableSet TransientScopeRootImplementation { get; } + IImmutableSet ScopeRootImplementation { get; } + IImmutableSet<(INamedTypeSymbol, IReadOnlyList)> DecoratorSequenceChoices { get; } + IImmutableSet<(INamedTypeSymbol, IMethodSymbol)> ConstructorChoices { get; } + IImmutableSet<(INamedTypeSymbol, IMethodSymbol)> TypeInitializers { get; } + IImmutableSet<(INamedTypeSymbol, ITypeParameterSymbol, IReadOnlyList)> GenericParameterSubstitutesChoices { get; } + IImmutableSet<(INamedTypeSymbol, ITypeParameterSymbol, INamedTypeSymbol)> GenericParameterChoices { get; } + IImmutableSet<(INamedTypeSymbol, IReadOnlyList)> PropertyChoices { get; } bool AllImplementations { get; } - IReadOnlyList AssemblyImplementations { get; } - IReadOnlyList<(INamedTypeSymbol, INamedTypeSymbol)> ImplementationChoices { get; } - IReadOnlyList<(INamedTypeSymbol, IReadOnlyList)> ImplementationCollectionChoices { get; } - IReadOnlyList FilterImplementation { get; } - IReadOnlyList FilterTransientAbstraction { get; } - IReadOnlyList FilterSyncTransientAbstraction { get; } - IReadOnlyList FilterAsyncTransientAbstraction { get; } - IReadOnlyList FilterContainerInstanceAbstraction { get; } - IReadOnlyList FilterTransientScopeInstanceAbstraction { get; } - IReadOnlyList FilterScopeInstanceAbstraction { get; } - IReadOnlyList FilterTransientScopeRootAbstraction { get; } - IReadOnlyList FilterScopeRootAbstraction { get; } - IReadOnlyList FilterDecoratorAbstraction { get; } - IReadOnlyList FilterCompositeAbstraction { get; } - IReadOnlyList FilterTransientImplementation { get; } - IReadOnlyList FilterSyncTransientImplementation { get; } - IReadOnlyList FilterAsyncTransientImplementation { get; } - IReadOnlyList FilterContainerInstanceImplementation { get; } - IReadOnlyList FilterTransientScopeInstanceImplementation { get; } - IReadOnlyList FilterScopeInstanceImplementation { get; } - IReadOnlyList FilterTransientScopeRootImplementation { get; } - IReadOnlyList FilterScopeRootImplementation { get; } - IReadOnlyList FilterDecoratorSequenceChoices { get; } - IReadOnlyList FilterConstructorChoices { get; } - IReadOnlyList FilterTypeInitializers { get; } - IReadOnlyList<(INamedTypeSymbol, ITypeParameterSymbol)> FilterGenericParameterSubstitutesChoices { get; } - IReadOnlyList<(INamedTypeSymbol, ITypeParameterSymbol)> FilterGenericParameterChoices { get; } - IReadOnlyList FilterPropertyChoices { get; } + IImmutableSet AssemblyImplementations { get; } + IImmutableSet<(INamedTypeSymbol, INamedTypeSymbol)> ImplementationChoices { get; } + IImmutableSet<(INamedTypeSymbol, IReadOnlyList)> ImplementationCollectionChoices { get; } + IImmutableSet FilterImplementation { get; } + IImmutableSet FilterTransientAbstraction { get; } + IImmutableSet FilterSyncTransientAbstraction { get; } + IImmutableSet FilterAsyncTransientAbstraction { get; } + IImmutableSet FilterContainerInstanceAbstraction { get; } + IImmutableSet FilterTransientScopeInstanceAbstraction { get; } + IImmutableSet FilterScopeInstanceAbstraction { get; } + IImmutableSet FilterTransientScopeRootAbstraction { get; } + IImmutableSet FilterScopeRootAbstraction { get; } + IImmutableSet FilterDecoratorAbstraction { get; } + IImmutableSet FilterCompositeAbstraction { get; } + IImmutableSet FilterTransientImplementation { get; } + IImmutableSet FilterSyncTransientImplementation { get; } + IImmutableSet FilterAsyncTransientImplementation { get; } + IImmutableSet FilterContainerInstanceImplementation { get; } + IImmutableSet FilterTransientScopeInstanceImplementation { get; } + IImmutableSet FilterScopeInstanceImplementation { get; } + IImmutableSet FilterTransientScopeRootImplementation { get; } + IImmutableSet FilterScopeRootImplementation { get; } + IImmutableSet FilterDecoratorSequenceChoices { get; } + IImmutableSet FilterConstructorChoices { get; } + IImmutableSet FilterTypeInitializers { get; } + IImmutableSet<(INamedTypeSymbol, ITypeParameterSymbol)> FilterGenericParameterSubstitutesChoices { get; } + IImmutableSet<(INamedTypeSymbol, ITypeParameterSymbol)> FilterGenericParameterChoices { get; } + IImmutableSet FilterPropertyChoices { get; } bool FilterAllImplementations { get; } - IReadOnlyList FilterAssemblyImplementations { get; } - IReadOnlyList FilterImplementationChoices { get; } - IReadOnlyList FilterImplementationCollectionChoices { get; } + IImmutableSet FilterAssemblyImplementations { get; } + IImmutableSet FilterImplementationChoices { get; } + IImmutableSet FilterImplementationCollectionChoices { get; } } internal class TypesFromAttributes : ScopeTypesFromAttributes @@ -76,22 +76,22 @@ internal TypesFromAttributes( WellKnownTypesMiscellaneous wellKnownTypesMiscellaneous) : base(attributeData, wellKnownTypesAggregation, wellKnownTypesChoice, wellKnownTypesMiscellaneous) { - ContainerInstanceAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.ContainerInstanceAbstractionAggregationAttribute).ToList(); - TransientScopeInstanceAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.TransientScopeInstanceAbstractionAggregationAttribute).ToList(); - TransientScopeRootAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.TransientScopeRootAbstractionAggregationAttribute).ToList(); - ScopeRootAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.ScopeRootAbstractionAggregationAttribute).ToList(); - ContainerInstanceImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.ContainerInstanceImplementationAggregationAttribute).ToList(); - TransientScopeInstanceImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.TransientScopeInstanceImplementationAggregationAttribute).ToList(); - TransientScopeRootImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.TransientScopeRootImplementationAggregationAttribute).ToList(); - ScopeRootImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.ScopeRootImplementationAggregationAttribute).ToList(); - FilterContainerInstanceAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.FilterContainerInstanceAbstractionAggregationAttribute).ToList(); - FilterTransientScopeInstanceAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.FilterTransientScopeInstanceAbstractionAggregationAttribute).ToList(); - FilterTransientScopeRootAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.FilterTransientScopeRootAbstractionAggregationAttribute).ToList(); - FilterScopeRootAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.FilterScopeRootAbstractionAggregationAttribute).ToList(); - FilterContainerInstanceImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.FilterContainerInstanceImplementationAggregationAttribute).ToList(); - FilterTransientScopeInstanceImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.FilterTransientScopeInstanceImplementationAggregationAttribute).ToList(); - FilterTransientScopeRootImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.FilterTransientScopeRootImplementationAggregationAttribute).ToList(); - FilterScopeRootImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.FilterScopeRootImplementationAggregationAttribute).ToList(); + ContainerInstanceAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.ContainerInstanceAbstractionAggregationAttribute); + TransientScopeInstanceAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.TransientScopeInstanceAbstractionAggregationAttribute); + TransientScopeRootAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.TransientScopeRootAbstractionAggregationAttribute); + ScopeRootAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.ScopeRootAbstractionAggregationAttribute); + ContainerInstanceImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.ContainerInstanceImplementationAggregationAttribute); + TransientScopeInstanceImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.TransientScopeInstanceImplementationAggregationAttribute); + TransientScopeRootImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.TransientScopeRootImplementationAggregationAttribute); + ScopeRootImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.ScopeRootImplementationAggregationAttribute); + FilterContainerInstanceAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.FilterContainerInstanceAbstractionAggregationAttribute); + FilterTransientScopeInstanceAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.FilterTransientScopeInstanceAbstractionAggregationAttribute); + FilterTransientScopeRootAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.FilterTransientScopeRootAbstractionAggregationAttribute); + FilterScopeRootAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.FilterScopeRootAbstractionAggregationAttribute); + FilterContainerInstanceImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.FilterContainerInstanceImplementationAggregationAttribute); + FilterTransientScopeInstanceImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.FilterTransientScopeInstanceImplementationAggregationAttribute); + FilterTransientScopeRootImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.FilterTransientScopeRootImplementationAggregationAttribute); + FilterScopeRootImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.FilterScopeRootImplementationAggregationAttribute); } } @@ -110,47 +110,48 @@ internal ScopeTypesFromAttributes( .GroupBy(ad => ad.AttributeClass, SymbolEqualityComparer.Default) .ToDictionary(g => g.Key, g => g); - Implementation = GetTypesFromAttribute(wellKnownTypesAggregation.ImplementationAggregationAttribute).ToList(); - TransientAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.TransientAbstractionAggregationAttribute).ToList(); - SyncTransientAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.SyncTransientAbstractionAggregationAttribute).ToList(); - AsyncTransientAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.AsyncTransientAbstractionAggregationAttribute).ToList(); - ContainerInstanceAbstraction = new List(); - TransientScopeInstanceAbstraction = new List(); - ScopeInstanceAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.ScopeInstanceAbstractionAggregationAttribute).ToList(); - TransientScopeRootAbstraction = new List(); - ScopeRootAbstraction = new List(); - DecoratorAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.DecoratorAbstractionAggregationAttribute).ToList(); - CompositeAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.CompositeAbstractionAggregationAttribute).ToList(); - TransientImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.TransientImplementationAggregationAttribute).ToList(); - SyncTransientImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.SyncTransientImplementationAggregationAttribute).ToList(); - AsyncTransientImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.AsyncTransientImplementationAggregationAttribute).ToList(); - ContainerInstanceImplementation = new List(); - TransientScopeInstanceImplementation = new List(); - ScopeInstanceImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.ScopeInstanceImplementationAggregationAttribute).ToList(); - TransientScopeRootImplementation = new List(); - ScopeRootImplementation = new List(); - - FilterImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.FilterImplementationAggregationAttribute).ToList(); - FilterTransientAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.FilterTransientAbstractionAggregationAttribute).ToList(); - FilterSyncTransientAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.FilterSyncTransientAbstractionAggregationAttribute).ToList(); - FilterAsyncTransientAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.FilterAsyncTransientAbstractionAggregationAttribute).ToList(); - FilterContainerInstanceAbstraction = new List(); - FilterTransientScopeInstanceAbstraction = new List(); - FilterScopeInstanceAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.FilterScopeInstanceAbstractionAggregationAttribute).ToList(); - FilterTransientScopeRootAbstraction = new List(); - FilterScopeRootAbstraction = new List(); - FilterDecoratorAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.FilterDecoratorAbstractionAggregationAttribute).ToList(); - FilterCompositeAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.FilterCompositeAbstractionAggregationAttribute).ToList(); - FilterTransientImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.FilterTransientImplementationAggregationAttribute).ToList(); - FilterSyncTransientImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.FilterSyncTransientImplementationAggregationAttribute).ToList(); - FilterAsyncTransientImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.FilterAsyncTransientImplementationAggregationAttribute).ToList(); - FilterContainerInstanceImplementation = new List(); - FilterTransientScopeInstanceImplementation = new List(); - FilterScopeInstanceImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.FilterScopeInstanceImplementationAggregationAttribute).ToList(); - FilterTransientScopeRootImplementation = new List(); - FilterScopeRootImplementation = new List(); + Implementation = GetTypesFromAttribute(wellKnownTypesAggregation.ImplementationAggregationAttribute); + TransientAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.TransientAbstractionAggregationAttribute); + SyncTransientAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.SyncTransientAbstractionAggregationAttribute); + AsyncTransientAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.AsyncTransientAbstractionAggregationAttribute); + ContainerInstanceAbstraction = ImmutableHashSet.Empty; + TransientScopeInstanceAbstraction = ImmutableHashSet.Empty; + ScopeInstanceAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.ScopeInstanceAbstractionAggregationAttribute); + TransientScopeRootAbstraction = ImmutableHashSet.Empty; + ScopeRootAbstraction = ImmutableHashSet.Empty; + DecoratorAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.DecoratorAbstractionAggregationAttribute); + CompositeAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.CompositeAbstractionAggregationAttribute); + TransientImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.TransientImplementationAggregationAttribute); + SyncTransientImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.SyncTransientImplementationAggregationAttribute); + AsyncTransientImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.AsyncTransientImplementationAggregationAttribute); + ContainerInstanceImplementation = ImmutableHashSet.Empty; + TransientScopeInstanceImplementation = ImmutableHashSet.Empty; + ScopeInstanceImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.ScopeInstanceImplementationAggregationAttribute); + TransientScopeRootImplementation = ImmutableHashSet.Empty; + ScopeRootImplementation = ImmutableHashSet.Empty; + + FilterImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.FilterImplementationAggregationAttribute); + FilterTransientAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.FilterTransientAbstractionAggregationAttribute); + FilterSyncTransientAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.FilterSyncTransientAbstractionAggregationAttribute); + FilterAsyncTransientAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.FilterAsyncTransientAbstractionAggregationAttribute); + FilterContainerInstanceAbstraction = ImmutableHashSet.Empty; + FilterTransientScopeInstanceAbstraction = ImmutableHashSet.Empty; + FilterScopeInstanceAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.FilterScopeInstanceAbstractionAggregationAttribute); + FilterTransientScopeRootAbstraction = ImmutableHashSet.Empty; + FilterScopeRootAbstraction = ImmutableHashSet.Empty; + FilterDecoratorAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.FilterDecoratorAbstractionAggregationAttribute); + FilterCompositeAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.FilterCompositeAbstractionAggregationAttribute); + FilterTransientImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.FilterTransientImplementationAggregationAttribute); + FilterSyncTransientImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.FilterSyncTransientImplementationAggregationAttribute); + FilterAsyncTransientImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.FilterAsyncTransientImplementationAggregationAttribute); + FilterContainerInstanceImplementation = ImmutableHashSet.Empty; + FilterTransientScopeInstanceImplementation = ImmutableHashSet.Empty; + FilterScopeInstanceImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.FilterScopeInstanceImplementationAggregationAttribute); + FilterTransientScopeRootImplementation = ImmutableHashSet.Empty; + FilterScopeRootImplementation = ImmutableHashSet.Empty; - DecoratorSequenceChoices = (AttributeDictionary.TryGetValue(wellKnownTypesChoice.DecoratorSequenceChoiceAttribute, out var decoratorSequenceChoiceAttributes) + DecoratorSequenceChoices = ImmutableHashSet.CreateRange( + (AttributeDictionary.TryGetValue(wellKnownTypesChoice.DecoratorSequenceChoiceAttribute, out var decoratorSequenceChoiceAttributes) ? decoratorSequenceChoiceAttributes : Enumerable.Empty()) .Select(ad => @@ -169,10 +170,10 @@ internal ScopeTypesFromAttributes( ? null : ((INamedTypeSymbol, IReadOnlyList)?) (decoratedType, decorators); }) - .OfType<(INamedTypeSymbol, IReadOnlyList)>() - .ToList(); + .OfType<(INamedTypeSymbol, IReadOnlyList)>()); - FilterDecoratorSequenceChoices = (AttributeDictionary.TryGetValue(wellKnownTypesChoice.FilterDecoratorSequenceChoiceAttribute, out var filterDecoratorSequenceChoiceAttributes) + FilterDecoratorSequenceChoices = ImmutableHashSet.CreateRange( + (AttributeDictionary.TryGetValue(wellKnownTypesChoice.FilterDecoratorSequenceChoiceAttribute, out var filterDecoratorSequenceChoiceAttributes) ? filterDecoratorSequenceChoiceAttributes : Enumerable.Empty()) .Select(ad => @@ -182,10 +183,10 @@ internal ScopeTypesFromAttributes( return ad.ConstructorArguments[0].Value as INamedTypeSymbol; }) - .OfType() - .ToList(); + .OfType()); - ConstructorChoices = (AttributeDictionary.TryGetValue(wellKnownTypesChoice.ConstructorChoiceAttribute, out var constructorChoiceAttributes) + ConstructorChoices = ImmutableHashSet.CreateRange( + (AttributeDictionary.TryGetValue(wellKnownTypesChoice.ConstructorChoiceAttribute, out var constructorChoiceAttributes) ? constructorChoiceAttributes : Enumerable.Empty()) .Select(ad => @@ -214,7 +215,7 @@ internal ScopeTypesFromAttributes( if (implementationType is null) return null; var constructorChoice = implementationType - .Constructors + .InstanceConstructors .Where(c => c.Parameters.Length == parameterTypes.Count) .SingleOrDefault(c => c.Parameters.Select(p => p.Type) .Zip(parameterTypes, @@ -225,19 +226,19 @@ internal ScopeTypesFromAttributes( : ((INamedTypeSymbol, IMethodSymbol)?)null; }) - .OfType<(INamedTypeSymbol, IMethodSymbol)>() - .ToList(); + .OfType<(INamedTypeSymbol, IMethodSymbol)>()); - FilterConstructorChoices = (AttributeDictionary.TryGetValue(wellKnownTypesChoice.FilterConstructorChoiceAttribute, out var filterConstructorChoiceAttributes) + FilterConstructorChoices = ImmutableHashSet.CreateRange( + (AttributeDictionary.TryGetValue(wellKnownTypesChoice.FilterConstructorChoiceAttribute, out var filterConstructorChoiceAttributes) ? filterConstructorChoiceAttributes : Enumerable.Empty()) .Select(ad => ad.ConstructorArguments.Length < 1 ? null : ad.ConstructorArguments[0].Value as INamedTypeSymbol) - .OfType() - .ToList(); + .OfType()); - PropertyChoices = (AttributeDictionary.TryGetValue(wellKnownTypesChoice.PropertyChoiceAttribute, out var propertyChoiceGroup) + PropertyChoices = ImmutableHashSet.CreateRange( + (AttributeDictionary.TryGetValue(wellKnownTypesChoice.PropertyChoiceAttribute, out var propertyChoiceGroup) ? propertyChoiceGroup : Enumerable.Empty()) .Select(ad => @@ -262,10 +263,10 @@ internal ScopeTypesFromAttributes( return (implementationType, properties); }) - .OfType<(INamedTypeSymbol, IReadOnlyList)>() - .ToList(); + .OfType<(INamedTypeSymbol, IReadOnlyList)>()); - FilterPropertyChoices = (AttributeDictionary.TryGetValue(wellKnownTypesChoice.FilterPropertyChoiceAttribute, out var filterPropertyChoicesGroup) + FilterPropertyChoices = ImmutableHashSet.CreateRange( + (AttributeDictionary.TryGetValue(wellKnownTypesChoice.FilterPropertyChoiceAttribute, out var filterPropertyChoicesGroup) ? filterPropertyChoicesGroup : Enumerable.Empty()) .Select(ad => @@ -274,10 +275,10 @@ internal ScopeTypesFromAttributes( return null; return ad.ConstructorArguments[0].Value as INamedTypeSymbol; }) - .OfType() - .ToList(); + .OfType()); - TypeInitializers = (AttributeDictionary.TryGetValue(wellKnownTypesMiscellaneous.TypeInitializerAttribute, out var typeInitializerAttributes) + TypeInitializers = ImmutableHashSet.CreateRange( + (AttributeDictionary.TryGetValue(wellKnownTypesMiscellaneous.TypeInitializerAttribute, out var typeInitializerAttributes) ? typeInitializerAttributes : Enumerable.Empty()) .Select(ad => @@ -300,10 +301,10 @@ internal ScopeTypesFromAttributes( return null; }) - .OfType<(INamedTypeSymbol, IMethodSymbol)>() - .ToList(); + .OfType<(INamedTypeSymbol, IMethodSymbol)>()); - FilterTypeInitializers = (AttributeDictionary.TryGetValue(wellKnownTypesMiscellaneous.FilterTypeInitializerAttribute, out var filterTypeInitializerAttributes) + FilterTypeInitializers = ImmutableHashSet.CreateRange( + (AttributeDictionary.TryGetValue(wellKnownTypesMiscellaneous.FilterTypeInitializerAttribute, out var filterTypeInitializerAttributes) ? filterTypeInitializerAttributes : Enumerable.Empty()) .Select(ad => @@ -312,10 +313,10 @@ internal ScopeTypesFromAttributes( return null; return ad.ConstructorArguments[0].Value as INamedTypeSymbol; }) - .OfType() - .ToList(); + .OfType()); - GenericParameterSubstitutesChoices = (AttributeDictionary.TryGetValue(wellKnownTypesChoice.GenericParameterSubstitutesChoiceAttribute, out var genericParameterSubstitutesChoiceAttributes) + GenericParameterSubstitutesChoices = ImmutableHashSet.CreateRange( + (AttributeDictionary.TryGetValue(wellKnownTypesChoice.GenericParameterSubstitutesChoiceAttribute, out var genericParameterSubstitutesChoiceAttributes) ? genericParameterSubstitutesChoiceAttributes : Enumerable.Empty()) .Select(ad => @@ -345,10 +346,10 @@ internal ScopeTypesFromAttributes( ? null : ((INamedTypeSymbol, ITypeParameterSymbol, IReadOnlyList)?) (genericType, typeParameterSymbol, substitutes); }) - .OfType<(INamedTypeSymbol, ITypeParameterSymbol, IReadOnlyList)>() - .ToList(); + .OfType<(INamedTypeSymbol, ITypeParameterSymbol, IReadOnlyList)>()); - GenericParameterChoices = (AttributeDictionary.TryGetValue(wellKnownTypesChoice.GenericParameterChoiceAttribute, out var genericParameterChoiceAttributes) + GenericParameterChoices = ImmutableHashSet.CreateRange( + (AttributeDictionary.TryGetValue(wellKnownTypesChoice.GenericParameterChoiceAttribute, out var genericParameterChoiceAttributes) ? genericParameterChoiceAttributes : Enumerable.Empty()) .Select(ad => @@ -373,10 +374,10 @@ internal ScopeTypesFromAttributes( ? null : ((INamedTypeSymbol, ITypeParameterSymbol, INamedTypeSymbol)?) (genericType, typeParameterSymbol, typeChoice); }) - .OfType<(INamedTypeSymbol, ITypeParameterSymbol, INamedTypeSymbol)>() - .ToList(); + .OfType<(INamedTypeSymbol, ITypeParameterSymbol, INamedTypeSymbol)>()); - FilterGenericParameterSubstitutesChoices = (AttributeDictionary.TryGetValue(wellKnownTypesChoice.FilterGenericParameterSubstitutesChoiceAttribute, out var filterGenericParameterSubstitutesChoiceAttributes) + FilterGenericParameterSubstitutesChoices = ImmutableHashSet.CreateRange( + (AttributeDictionary.TryGetValue(wellKnownTypesChoice.FilterGenericParameterSubstitutesChoiceAttribute, out var filterGenericParameterSubstitutesChoiceAttributes) ? filterGenericParameterSubstitutesChoiceAttributes : Enumerable.Empty()) .Select(ad => @@ -399,10 +400,10 @@ internal ScopeTypesFromAttributes( ? null : ((INamedTypeSymbol, ITypeParameterSymbol)?) (genericType, typeParameterSymbol); }) - .OfType<(INamedTypeSymbol, ITypeParameterSymbol)>() - .ToList(); + .OfType<(INamedTypeSymbol, ITypeParameterSymbol)>()); - FilterGenericParameterChoices = (AttributeDictionary.TryGetValue(wellKnownTypesChoice.FilterGenericParameterChoiceAttribute, out var filterGenericParameterChoiceAttributes) + FilterGenericParameterChoices = ImmutableHashSet.CreateRange( + (AttributeDictionary.TryGetValue(wellKnownTypesChoice.FilterGenericParameterChoiceAttribute, out var filterGenericParameterChoiceAttributes) ? filterGenericParameterChoiceAttributes : Enumerable.Empty()) .Select(ad => @@ -425,8 +426,7 @@ internal ScopeTypesFromAttributes( ? null : ((INamedTypeSymbol, ITypeParameterSymbol)?) (genericType, typeParameterSymbol); }) - .OfType<(INamedTypeSymbol, ITypeParameterSymbol)>() - .ToList(); + .OfType<(INamedTypeSymbol, ITypeParameterSymbol)>()); AllImplementations = (AttributeDictionary.TryGetValue(wellKnownTypesAggregation.AllImplementationsAggregationAttribute, out var allImplementationsAttributes) ? allImplementationsAttributes @@ -438,7 +438,8 @@ internal ScopeTypesFromAttributes( : Enumerable.Empty()) .Any(); - AssemblyImplementations = (AttributeDictionary.TryGetValue(wellKnownTypesAggregation.AssemblyImplementationsAggregationAttribute, out var assemblyImplementationsAttributes) + AssemblyImplementations = ImmutableHashSet.CreateRange( + (AttributeDictionary.TryGetValue(wellKnownTypesAggregation.AssemblyImplementationsAggregationAttribute, out var assemblyImplementationsAttributes) ? assemblyImplementationsAttributes : Enumerable.Empty()) .SelectMany(ad => ad.ConstructorArguments.Length < 1 @@ -450,10 +451,10 @@ internal ScopeTypesFromAttributes( .Select(t => t.ContainingAssembly) .OfType()) .Distinct(SymbolEqualityComparer.Default) - .OfType() - .ToList(); + .OfType()); - FilterAssemblyImplementations = (AttributeDictionary.TryGetValue(wellKnownTypesAggregation.FilterAssemblyImplementationsAggregationAttribute, out var filterAssemblyImplementationsAttributes) + FilterAssemblyImplementations = ImmutableHashSet.CreateRange( + (AttributeDictionary.TryGetValue(wellKnownTypesAggregation.FilterAssemblyImplementationsAggregationAttribute, out var filterAssemblyImplementationsAttributes) ? filterAssemblyImplementationsAttributes : Enumerable.Empty()) .SelectMany(ad => ad.ConstructorArguments.Length < 1 @@ -465,10 +466,10 @@ internal ScopeTypesFromAttributes( .Select(t => t.ContainingAssembly) .OfType()) .Distinct(SymbolEqualityComparer.Default) - .OfType() - .ToList(); + .OfType()); - ImplementationChoices = (AttributeDictionary.TryGetValue(wellKnownTypesChoice.ImplementationChoiceAttribute, out var implementationChoiceAttributes) + ImplementationChoices = ImmutableHashSet.CreateRange( + (AttributeDictionary.TryGetValue(wellKnownTypesChoice.ImplementationChoiceAttribute, out var implementationChoiceAttributes) ? implementationChoiceAttributes : Enumerable.Empty()) .Select(ad => @@ -477,10 +478,10 @@ internal ScopeTypesFromAttributes( || ad.ConstructorArguments[1].Value is not INamedTypeSymbol implementation ? null : ((INamedTypeSymbol, INamedTypeSymbol)?) (type, implementation)) - .OfType<(INamedTypeSymbol, INamedTypeSymbol)>() - .ToList(); + .OfType<(INamedTypeSymbol, INamedTypeSymbol)>()); - ImplementationCollectionChoices = (AttributeDictionary.TryGetValue(wellKnownTypesChoice.ImplementationCollectionChoiceAttribute, out var implementationCollectionChoicesAttributes) + ImplementationCollectionChoices = ImmutableHashSet.CreateRange( + (AttributeDictionary.TryGetValue(wellKnownTypesChoice.ImplementationCollectionChoiceAttribute, out var implementationCollectionChoicesAttributes) ? implementationCollectionChoicesAttributes : Enumerable.Empty()) .Select(ad => @@ -501,30 +502,30 @@ internal ScopeTypesFromAttributes( ? null : ((INamedTypeSymbol, IReadOnlyList)?) (type, implementations); }) - .OfType<(INamedTypeSymbol, IReadOnlyList)>() - .ToList(); + .OfType<(INamedTypeSymbol, IReadOnlyList)>()); - FilterImplementationChoices = GetTypesFromAttribute(wellKnownTypesChoice.FilterImplementationChoiceAttribute).ToList(); + FilterImplementationChoices = GetTypesFromAttribute(wellKnownTypesChoice.FilterImplementationChoiceAttribute); - FilterImplementationCollectionChoices = GetTypesFromAttribute(wellKnownTypesChoice.FilterImplementationCollectionChoiceAttribute).ToList(); + FilterImplementationCollectionChoices = GetTypesFromAttribute(wellKnownTypesChoice.FilterImplementationCollectionChoiceAttribute); } private IReadOnlyDictionary> AttributeDictionary { get; } - protected IEnumerable GetTypesFromAttribute( + protected IImmutableSet GetTypesFromAttribute( INamedTypeSymbol attribute) { - return (AttributeDictionary.TryGetValue(attribute, out var attributes) ? attributes : Enumerable.Empty()) - .SelectMany(ad => ad.ConstructorArguments - .Where(tc => tc.Kind == TypedConstantKind.Type) - .OfType() - .Concat(ad.ConstructorArguments.SelectMany(ca => ca.Kind is TypedConstantKind.Array - ? (IEnumerable)ca.Values - : Array.Empty()))) - .Select(tc => !CheckValidType(tc, out var type) ? null : type) - .Where(t => t is not null) - .OfType() - .Select(t => t.OriginalDefinition); + return ImmutableHashSet.CreateRange( + (AttributeDictionary.TryGetValue(attribute, out var attributes) ? attributes : Enumerable.Empty()) + .SelectMany(ad => ad.ConstructorArguments + .Where(tc => tc.Kind == TypedConstantKind.Type) + .OfType() + .Concat(ad.ConstructorArguments.SelectMany(ca => ca.Kind is TypedConstantKind.Array + ? (IEnumerable)ca.Values + : Array.Empty()))) + .Select(tc => !CheckValidType(tc, out var type) ? null : type) + .Where(t => t is not null) + .OfType() + .Select(t => t.OriginalDefinition)); bool CheckValidType(TypedConstant typedConstant, out INamedTypeSymbol type) { @@ -533,62 +534,62 @@ bool CheckValidType(TypedConstant typedConstant, out INamedTypeSymbol type) } } - public IReadOnlyList Implementation { get; } - public IReadOnlyList TransientAbstraction { get; } - public IReadOnlyList SyncTransientAbstraction { get; } - public IReadOnlyList AsyncTransientAbstraction { get; } - public IReadOnlyList ContainerInstanceAbstraction { get; protected init; } - public IReadOnlyList TransientScopeInstanceAbstraction { get; protected init; } - public IReadOnlyList ScopeInstanceAbstraction { get; } - public IReadOnlyList TransientScopeRootAbstraction { get; protected init; } - public IReadOnlyList ScopeRootAbstraction { get; protected init; } - public IReadOnlyList DecoratorAbstraction { get; } - public IReadOnlyList CompositeAbstraction { get; } - public IReadOnlyList TransientImplementation { get; } - public IReadOnlyList SyncTransientImplementation { get; } - public IReadOnlyList AsyncTransientImplementation { get; } - public IReadOnlyList ContainerInstanceImplementation { get; protected init; } - public IReadOnlyList TransientScopeInstanceImplementation { get; protected init; } - public IReadOnlyList ScopeInstanceImplementation { get; } - public IReadOnlyList TransientScopeRootImplementation { get; protected init; } - public IReadOnlyList ScopeRootImplementation { get; protected init; } - public IReadOnlyList<(INamedTypeSymbol, IReadOnlyList)> DecoratorSequenceChoices { get; } - public IReadOnlyList<(INamedTypeSymbol, IMethodSymbol)> ConstructorChoices { get; } - public IReadOnlyList<(INamedTypeSymbol, IMethodSymbol)> TypeInitializers { get; } - public IReadOnlyList<(INamedTypeSymbol, ITypeParameterSymbol, IReadOnlyList)> GenericParameterSubstitutesChoices { get; } - public IReadOnlyList<(INamedTypeSymbol, ITypeParameterSymbol, INamedTypeSymbol)> GenericParameterChoices { get; } - public IReadOnlyList<(INamedTypeSymbol, IReadOnlyList)> PropertyChoices { get; } + public IImmutableSet Implementation { get; } + public IImmutableSet TransientAbstraction { get; } + public IImmutableSet SyncTransientAbstraction { get; } + public IImmutableSet AsyncTransientAbstraction { get; } + public IImmutableSet ContainerInstanceAbstraction { get; protected init; } + public IImmutableSet TransientScopeInstanceAbstraction { get; protected init; } + public IImmutableSet ScopeInstanceAbstraction { get; } + public IImmutableSet TransientScopeRootAbstraction { get; protected init; } + public IImmutableSet ScopeRootAbstraction { get; protected init; } + public IImmutableSet DecoratorAbstraction { get; } + public IImmutableSet CompositeAbstraction { get; } + public IImmutableSet TransientImplementation { get; } + public IImmutableSet SyncTransientImplementation { get; } + public IImmutableSet AsyncTransientImplementation { get; } + public IImmutableSet ContainerInstanceImplementation { get; protected init; } + public IImmutableSet TransientScopeInstanceImplementation { get; protected init; } + public IImmutableSet ScopeInstanceImplementation { get; } + public IImmutableSet TransientScopeRootImplementation { get; protected init; } + public IImmutableSet ScopeRootImplementation { get; protected init; } + public IImmutableSet<(INamedTypeSymbol, IReadOnlyList)> DecoratorSequenceChoices { get; } + public IImmutableSet<(INamedTypeSymbol, IMethodSymbol)> ConstructorChoices { get; } + public IImmutableSet<(INamedTypeSymbol, IMethodSymbol)> TypeInitializers { get; } + public IImmutableSet<(INamedTypeSymbol, ITypeParameterSymbol, IReadOnlyList)> GenericParameterSubstitutesChoices { get; } + public IImmutableSet<(INamedTypeSymbol, ITypeParameterSymbol, INamedTypeSymbol)> GenericParameterChoices { get; } + public IImmutableSet<(INamedTypeSymbol, IReadOnlyList)> PropertyChoices { get; } public bool AllImplementations { get; } - public IReadOnlyList AssemblyImplementations { get; } - public IReadOnlyList<(INamedTypeSymbol, INamedTypeSymbol)> ImplementationChoices { get; } - public IReadOnlyList<(INamedTypeSymbol, IReadOnlyList)> ImplementationCollectionChoices { get; } - public IReadOnlyList FilterImplementation { get; } - public IReadOnlyList FilterTransientAbstraction { get; } - public IReadOnlyList FilterSyncTransientAbstraction { get; } - public IReadOnlyList FilterAsyncTransientAbstraction { get; } - public IReadOnlyList FilterContainerInstanceAbstraction { get; protected init; } - public IReadOnlyList FilterTransientScopeInstanceAbstraction { get; protected init; } - public IReadOnlyList FilterScopeInstanceAbstraction { get; } - public IReadOnlyList FilterTransientScopeRootAbstraction { get; protected init; } - public IReadOnlyList FilterScopeRootAbstraction { get; protected init; } - public IReadOnlyList FilterDecoratorAbstraction { get; } - public IReadOnlyList FilterCompositeAbstraction { get; } - public IReadOnlyList FilterTransientImplementation { get; } - public IReadOnlyList FilterSyncTransientImplementation { get; } - public IReadOnlyList FilterAsyncTransientImplementation { get; } - public IReadOnlyList FilterContainerInstanceImplementation { get; protected init; } - public IReadOnlyList FilterTransientScopeInstanceImplementation { get; protected init; } - public IReadOnlyList FilterScopeInstanceImplementation { get; } - public IReadOnlyList FilterTransientScopeRootImplementation { get; protected init; } - public IReadOnlyList FilterScopeRootImplementation { get; protected init; } - public IReadOnlyList FilterDecoratorSequenceChoices { get; } - public IReadOnlyList FilterConstructorChoices { get; } - public IReadOnlyList FilterTypeInitializers { get; } - public IReadOnlyList<(INamedTypeSymbol, ITypeParameterSymbol)> FilterGenericParameterSubstitutesChoices { get; } - public IReadOnlyList<(INamedTypeSymbol, ITypeParameterSymbol)> FilterGenericParameterChoices { get; } - public IReadOnlyList FilterPropertyChoices { get; } + public IImmutableSet AssemblyImplementations { get; } + public IImmutableSet<(INamedTypeSymbol, INamedTypeSymbol)> ImplementationChoices { get; } + public IImmutableSet<(INamedTypeSymbol, IReadOnlyList)> ImplementationCollectionChoices { get; } + public IImmutableSet FilterImplementation { get; } + public IImmutableSet FilterTransientAbstraction { get; } + public IImmutableSet FilterSyncTransientAbstraction { get; } + public IImmutableSet FilterAsyncTransientAbstraction { get; } + public IImmutableSet FilterContainerInstanceAbstraction { get; protected init; } + public IImmutableSet FilterTransientScopeInstanceAbstraction { get; protected init; } + public IImmutableSet FilterScopeInstanceAbstraction { get; } + public IImmutableSet FilterTransientScopeRootAbstraction { get; protected init; } + public IImmutableSet FilterScopeRootAbstraction { get; protected init; } + public IImmutableSet FilterDecoratorAbstraction { get; } + public IImmutableSet FilterCompositeAbstraction { get; } + public IImmutableSet FilterTransientImplementation { get; } + public IImmutableSet FilterSyncTransientImplementation { get; } + public IImmutableSet FilterAsyncTransientImplementation { get; } + public IImmutableSet FilterContainerInstanceImplementation { get; protected init; } + public IImmutableSet FilterTransientScopeInstanceImplementation { get; protected init; } + public IImmutableSet FilterScopeInstanceImplementation { get; } + public IImmutableSet FilterTransientScopeRootImplementation { get; protected init; } + public IImmutableSet FilterScopeRootImplementation { get; protected init; } + public IImmutableSet FilterDecoratorSequenceChoices { get; } + public IImmutableSet FilterConstructorChoices { get; } + public IImmutableSet FilterTypeInitializers { get; } + public IImmutableSet<(INamedTypeSymbol, ITypeParameterSymbol)> FilterGenericParameterSubstitutesChoices { get; } + public IImmutableSet<(INamedTypeSymbol, ITypeParameterSymbol)> FilterGenericParameterChoices { get; } + public IImmutableSet FilterPropertyChoices { get; } public bool FilterAllImplementations { get; } - public IReadOnlyList FilterAssemblyImplementations { get; } - public IReadOnlyList FilterImplementationChoices { get; } - public IReadOnlyList FilterImplementationCollectionChoices { get; } + public IImmutableSet FilterAssemblyImplementations { get; } + public IImmutableSet FilterImplementationChoices { get; } + public IImmutableSet FilterImplementationCollectionChoices { get; } } \ No newline at end of file diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs index a6e0a6ca..e1befbc9 100644 --- a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs @@ -640,14 +640,14 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup return implementationType.NullableAnnotation == NullableAnnotation.Annotated ? (new NullResolution(RootReferenceGenerator.Generate(implementationType), implementationType.FullName()), null) // todo warning - : (new ErrorTreeItem(implementationType.Constructors.Length switch + : (new ErrorTreeItem(implementationType.InstanceConstructors.Length switch { 0 => $"[{implementationType.FullName()}] Class.Constructor: No constructor found for implementation {implementationType.FullName()}", > 1 => $"[{implementationType.FullName()}] Class.Constructor: More than one constructor found for implementation {implementationType.FullName()}", _ => - $"[{implementationType.FullName()}] Class.Constructor: {implementationType.Constructors[0].Name} is not a method symbol" + $"[{implementationType.FullName()}] Class.Constructor: {implementationType.InstanceConstructors[0].Name} is not a method symbol" }), null); } diff --git a/Main/Utility/NamedTypeSymbolEqualityComparer.cs b/Main/Utility/NamedTypeSymbolEqualityComparer.cs new file mode 100644 index 00000000..871e2106 --- /dev/null +++ b/Main/Utility/NamedTypeSymbolEqualityComparer.cs @@ -0,0 +1,18 @@ +namespace MrMeeseeks.DIE.Utility; + +public class NamedTypeSymbolEqualityComparer : IEqualityComparer +{ + private readonly IEqualityComparer _innerEqualityComparer; + + public static readonly NamedTypeSymbolEqualityComparer Default = new (SymbolEqualityComparer.Default); + public static readonly NamedTypeSymbolEqualityComparer IncludeNullability = new (SymbolEqualityComparer.IncludeNullability); + + private NamedTypeSymbolEqualityComparer(IEqualityComparer innerEqualityComparer) => + _innerEqualityComparer = innerEqualityComparer; + + public bool Equals(INamedTypeSymbol? x, INamedTypeSymbol? y) => + _innerEqualityComparer.Equals(x, y); + + public int GetHashCode(INamedTypeSymbol? obj) => + _innerEqualityComparer.GetHashCode(obj); +} \ No newline at end of file diff --git a/Sample/Context.cs b/Sample/Context.cs index e67f6241..4b76ae56 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -1,13 +1,40 @@ using MrMeeseeks.DIE.Configuration.Attributes; +using MrMeeseeks.DIE.Sample; -namespace MrMeeseeks.DIE.Test.CycleDetection.Implementation; +namespace MrMeeseeks.DIE.Test.Generics.Configuration.Decorator; -internal class Dependency +internal interface IInterface { - internal Dependency(Dependency inner) {} + IInterface Decorated { get; } } -[CreateFunction(typeof(Dependency), "Create")] +internal class Implementation : IInterface +{ + public IInterface Decorated => this; +} + +internal class DecoratorA : IInterface, IDecorator +{ + public IInterface Decorated { get; } + + internal DecoratorA( + IInterface decorated) => + Decorated = decorated; +} + +internal class DecoratorB : IInterface, IDecorator +{ + public IInterface Decorated { get; } + + internal DecoratorB( + IInterface decorated) => + Decorated = decorated; +} + +[GenericParameterChoice(typeof(DecoratorA<>), "T0", typeof(int))] +[GenericParameterChoice(typeof(DecoratorB<>), "T0", typeof(string))] +[DecoratorSequenceChoice(typeof(IInterface), typeof(DecoratorA<>), typeof(DecoratorB<>))] +[CreateFunction(typeof(IInterface), "Create")] internal partial class Container { diff --git a/Sample/Program.cs b/Sample/Program.cs index 09575040..f3b070c4 100644 --- a/Sample/Program.cs +++ b/Sample/Program.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE.Test.CycleDetection.Implementation; +using MrMeeseeks.DIE.Test.Generics.Configuration.Decorator; internal class Program { diff --git a/Sample/Sample.csproj b/Sample/Sample.csproj index 098a068e..1b755e49 100644 --- a/Sample/Sample.csproj +++ b/Sample/Sample.csproj @@ -18,8 +18,7 @@ - - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Test/Test.csproj b/Test/Test.csproj index 74b61a79..06a3b29b 100644 --- a/Test/Test.csproj +++ b/Test/Test.csproj @@ -28,8 +28,7 @@ - - + all runtime; build; native; contentfiles; analyzers; buildtransitive From f6d0575d3502466b56d9d219333078a787f0a0d0 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Fri, 27 May 2022 14:44:20 +0200 Subject: [PATCH 076/162] Fixing ignorance of aggregated implementations when resolving concrete types --- Main/Configuration/CheckTypeProperties.cs | 4 +- .../Configuration/CurrentlyConsideredTypes.cs | 7 ++- Main/Extensions/INamedTypeSymbolExtensions.cs | 11 +++++ Sample/Context.cs | 44 +++---------------- Sample/Program.cs | 6 +-- .../AssemblyImplementationsAggregation.cs | 3 +- 6 files changed, 30 insertions(+), 45 deletions(-) diff --git a/Main/Configuration/CheckTypeProperties.cs b/Main/Configuration/CheckTypeProperties.cs index dbef8b5b..14652810 100644 --- a/Main/Configuration/CheckTypeProperties.cs +++ b/Main/Configuration/CheckTypeProperties.cs @@ -383,7 +383,9 @@ void AddImplementation(IList implementations, INamedTypeSymbol implementations.Add(added); if (!chooseComposite && !chooseDecorator && !_currentlyConsideredTypes.DecoratorTypes.Contains(unbound) - && !_currentlyConsideredTypes.CompositeTypes.Contains(unbound)) + && !_currentlyConsideredTypes.CompositeTypes.Contains(unbound) + && _currentlyConsideredTypes.AllConsideredImplementations.Contains(unbound) + ) implementations.Add(added); } } diff --git a/Main/Configuration/CurrentlyConsideredTypes.cs b/Main/Configuration/CurrentlyConsideredTypes.cs index dd7cad1a..3edb49db 100644 --- a/Main/Configuration/CurrentlyConsideredTypes.cs +++ b/Main/Configuration/CurrentlyConsideredTypes.cs @@ -4,6 +4,7 @@ namespace MrMeeseeks.DIE.Configuration; internal interface ICurrentlyConsideredTypes { + IImmutableSet AllConsideredImplementations { get; } IImmutableSet SyncTransientTypes { get; } IImmutableSet AsyncTransientTypes { get; } IImmutableSet ContainerInstanceTypes { get; } @@ -85,6 +86,7 @@ private IImmutableSet GetImplementationsFrom(IAssemblySymbol a return GetAllNamespaces(assemblySymbol.GlobalNamespace) .SelectMany(ns => ns.GetTypeMembers()) + .SelectMany(t => t.AllNestedTypesAndSelf()) .Where(nts => nts is { IsAbstract: false, @@ -144,6 +146,8 @@ public CurrentlyConsideredTypes( (current, assembly) => current.Union(implementationTypeSetCache.ForAssembly(assembly))); } } + + AllConsideredImplementations = ImmutableHashSet.CreateRange(allImplementations.Select(t => t.UnboundIfGeneric())); ImplementationMap = allImplementations .SelectMany(i => { return i.AllDerivedTypesAndSelf().Select(ii => (ii, i)); }) @@ -443,7 +447,8 @@ IImmutableSet GetSetOfTypesWithProperties( return ret; } } - + + public IImmutableSet AllConsideredImplementations { get; } public IImmutableSet SyncTransientTypes { get; } public IImmutableSet AsyncTransientTypes { get; } public IImmutableSet ContainerInstanceTypes { get; } diff --git a/Main/Extensions/INamedTypeSymbolExtensions.cs b/Main/Extensions/INamedTypeSymbolExtensions.cs index 149bf1d1..9155e831 100644 --- a/Main/Extensions/INamedTypeSymbolExtensions.cs +++ b/Main/Extensions/INamedTypeSymbolExtensions.cs @@ -21,6 +21,17 @@ internal static IEnumerable AllDerivedTypesAndSelf(this INamed .AllInterfaces .Concat(baseTypesAndSelf); } + internal static IEnumerable AllNestedTypesAndSelf(this INamedTypeSymbol type) + { + yield return type; + foreach (var typeMember in type.GetTypeMembers()) + { + foreach (var nestedType in typeMember.AllNestedTypesAndSelf()) + { + yield return nestedType; + } + } + } internal static INamedTypeSymbol UnboundIfGeneric(this INamedTypeSymbol type) => type.IsGenericType && !type.IsUnboundGenericType diff --git a/Sample/Context.cs b/Sample/Context.cs index 4b76ae56..ff4b3b50 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -1,41 +1,11 @@ using MrMeeseeks.DIE.Configuration.Attributes; -using MrMeeseeks.DIE.Sample; +using MrMeeseeks.DIE.SampleChild; -namespace MrMeeseeks.DIE.Test.Generics.Configuration.Decorator; -internal interface IInterface -{ - IInterface Decorated { get; } -} +namespace MrMeeseeks.DIE.Test.Implementation.Aggregation.AssemblyImplementationsAggregation; -internal class Implementation : IInterface -{ - public IInterface Decorated => this; -} - -internal class DecoratorA : IInterface, IDecorator -{ - public IInterface Decorated { get; } - - internal DecoratorA( - IInterface decorated) => - Decorated = decorated; -} - -internal class DecoratorB : IInterface, IDecorator -{ - public IInterface Decorated { get; } - - internal DecoratorB( - IInterface decorated) => - Decorated = decorated; -} - -[GenericParameterChoice(typeof(DecoratorA<>), "T0", typeof(int))] -[GenericParameterChoice(typeof(DecoratorB<>), "T0", typeof(string))] -[DecoratorSequenceChoice(typeof(IInterface), typeof(DecoratorA<>), typeof(DecoratorB<>))] -[CreateFunction(typeof(IInterface), "Create")] -internal partial class Container -{ - -} \ No newline at end of file +[FilterAllImplementationsAggregation] +[AssemblyImplementationsAggregation(typeof(MrMeeseeks.DIE.SampleChild.AssemblyInfo))] +[ConstructorChoice(typeof(Parent.ClassToo))] +[CreateFunction(typeof(Parent.ClassToo), "Create")] +internal partial class Container {} \ No newline at end of file diff --git a/Sample/Program.cs b/Sample/Program.cs index f3b070c4..9f85a5e1 100644 --- a/Sample/Program.cs +++ b/Sample/Program.cs @@ -1,9 +1,7 @@ -using MrMeeseeks.DIE.Test.Generics.Configuration.Decorator; - -internal class Program +internal class Program { private static void Main() { - var container = new Container(); + } } \ No newline at end of file diff --git a/Test/Implementation/Aggregation/AssemblyImplementationsAggregation.cs b/Test/Implementation/Aggregation/AssemblyImplementationsAggregation.cs index 1bb9d882..b55c4992 100644 --- a/Test/Implementation/Aggregation/AssemblyImplementationsAggregation.cs +++ b/Test/Implementation/Aggregation/AssemblyImplementationsAggregation.cs @@ -1,12 +1,11 @@ using MrMeeseeks.DIE.Configuration.Attributes; using MrMeeseeks.DIE.TestNotInternalsVisibleToChild.Public; -using MrMeeseeks.DIE.TestNotInternalsVisibleToChild; using Xunit; namespace MrMeeseeks.DIE.Test.Implementation.Aggregation.AssemblyImplementationsAggregation; [FilterAllImplementationsAggregation] -[AssemblyImplementationsAggregation(typeof(AssemblyInfo))] +[AssemblyImplementationsAggregation(typeof(MrMeeseeks.DIE.TestNotInternalsVisibleToChild.AssemblyInfo))] [ConstructorChoice(typeof(Parent.ClassToo))] [CreateFunction(typeof(Parent.ClassToo), "Create")] internal partial class Container {} From 16f31a5e1eba69d78a8205358739e2d93bf578a9 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sun, 29 May 2022 16:31:40 +0200 Subject: [PATCH 077/162] Cycle detection for functions --- Main/CodeBuilding/RangeCodeBaseBuilder.cs | 4 +- Main/ExecuteImpl.cs | 1 + .../ContainerResolutionBuilder.cs | 10 ++++- ...ontainerCreateFunctionResolutionBuilder.cs | 16 +++++-- .../Function/FunctionCycleTracker.cs | 39 +++++++++++++++++ .../Function/FunctionResolutionBuilder.cs | 20 ++++++++- .../FunctionResolutionBuilderHandle.cs | 5 +++ .../LocalFunctionResolutionBuilder.cs | 14 ++++++- .../RangedFunctionGroupResolutionBuilder.cs | 10 ++++- .../RangedFunctionResolutionBuilder.cs | 15 ++++++- ...copeRootCreateFunctionResolutionBuilder.cs | 14 ++++++- ...entScopeImplementationResolutionBuilder.cs | 2 +- Main/ResolutionBuilding/ResolutionDtos.cs | 5 ++- .../ScopeResolutionBuilder.cs | 2 +- ...ransientScopeInterfaceResolutionBuilder.cs | 42 ++++++++++++------- .../TransientScopeResolutionBuilder.cs | 4 +- Main/ResolutionTreeItem.cs | 3 +- Main/SourceGenerator.cs | 15 +++++-- Sample/Context.cs | 21 ++++++---- .../Cycle/DirectRecursionContainer.cs | 25 +++++++++++ .../Function/Cycle/DirectRecursionScope.cs | 25 +++++++++++ .../Cycle/DirectRecursionTransientScope.cs | 25 +++++++++++ .../NoCycle/DirectRecursionContainerFunc.cs | 27 ++++++++++++ .../NoCycle/DirectRecursionContainerLazy.cs | 27 ++++++++++++ .../NoCycle/DirectRecursionScopeFunc.cs | 27 ++++++++++++ .../NoCycle/DirectRecursionScopeLazy.cs | 27 ++++++++++++ .../DirectRecursionTransientScopeFunc.cs | 27 ++++++++++++ .../DirectRecursionTransientScopeLazy.cs | 27 ++++++++++++ .../Cycle/DirectRecursion.cs} | 2 +- .../Cycle}/ImplementationProxied.cs | 3 +- .../NoCycle}/NoCycleInParallel.cs | 2 +- Test/Scoping/InScope.cs | 25 +++++++++++ 32 files changed, 459 insertions(+), 52 deletions(-) create mode 100644 Main/ResolutionBuilding/Function/FunctionCycleTracker.cs create mode 100644 Main/ResolutionBuilding/Function/FunctionResolutionBuilderHandle.cs create mode 100644 Test/CycleDetection/Function/Cycle/DirectRecursionContainer.cs create mode 100644 Test/CycleDetection/Function/Cycle/DirectRecursionScope.cs create mode 100644 Test/CycleDetection/Function/Cycle/DirectRecursionTransientScope.cs create mode 100644 Test/CycleDetection/Function/NoCycle/DirectRecursionContainerFunc.cs create mode 100644 Test/CycleDetection/Function/NoCycle/DirectRecursionContainerLazy.cs create mode 100644 Test/CycleDetection/Function/NoCycle/DirectRecursionScopeFunc.cs create mode 100644 Test/CycleDetection/Function/NoCycle/DirectRecursionScopeLazy.cs create mode 100644 Test/CycleDetection/Function/NoCycle/DirectRecursionTransientScopeFunc.cs create mode 100644 Test/CycleDetection/Function/NoCycle/DirectRecursionTransientScopeLazy.cs rename Test/CycleDetection/{Implementation.cs => Implementation/Cycle/DirectRecursion.cs} (84%) rename Test/CycleDetection/{ => Implementation/Cycle}/ImplementationProxied.cs (84%) rename Test/CycleDetection/{ => Implementation/NoCycle}/NoCycleInParallel.cs (87%) create mode 100644 Test/Scoping/InScope.cs diff --git a/Main/CodeBuilding/RangeCodeBaseBuilder.cs b/Main/CodeBuilding/RangeCodeBaseBuilder.cs index 00b154a5..ad8083e6 100644 --- a/Main/CodeBuilding/RangeCodeBaseBuilder.cs +++ b/Main/CodeBuilding/RangeCodeBaseBuilder.cs @@ -595,7 +595,9 @@ private StringBuilder GenerateRangedInstanceFunction(StringBuilder stringBuilder .AppendLine($"{{") .AppendLine($"this.{rangedInstanceFunctionGroupResolution.LockReference}.Release();") .AppendLine($"}}") - .AppendLine($"return this.{rangedInstanceFunctionGroupResolution.FieldReference};") + .AppendLine($"return this.{rangedInstanceFunctionGroupResolution.FieldReference};"); + + stringBuilder = overload.LocalFunctions.Aggregate(stringBuilder, GenerateResolutionFunction) .AppendLine($"}}"); } diff --git a/Main/ExecuteImpl.cs b/Main/ExecuteImpl.cs index 6edd8c92..0a3a0433 100644 --- a/Main/ExecuteImpl.cs +++ b/Main/ExecuteImpl.cs @@ -77,6 +77,7 @@ public void Execute() containerResolutionBuilder.DoWork(); } + containerResolutionBuilder.FunctionCycleTracker.DetectCycle(); var containerResolution = containerResolutionBuilder.Build(); var errorTreeItems = _resolutionTreeCreationErrorHarvester.Harvest(containerResolution); if (errorTreeItems.Any()) diff --git a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs index d0e5b0db..5c6b385c 100644 --- a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs @@ -10,6 +10,8 @@ internal interface IContainerResolutionBuilder : IRangeResolutionBaseBuilder, IR MultiSynchronicityFunctionCallResolution CreateContainerInstanceReferenceResolution( ForConstructorParameter parameter, string containerReference); + + IFunctionCycleTracker FunctionCycleTracker { get; } } internal class ContainerResolutionBuilder : RangeResolutionBaseBuilder, IContainerResolutionBuilder, ITransientScopeImplementationResolutionBuilder @@ -39,7 +41,8 @@ internal ContainerResolutionBuilder( Func createFunctionResolutionBuilderFactory, Func rangedFunctionGroupResolutionBuilderFactory, Func synchronicityDecisionMakerFactory, - IUserProvidedScopeElements userProvidedScopeElement) + IUserProvidedScopeElements userProvidedScopeElement, + IFunctionCycleTracker functionCycleTracker) : base( containerInfo.Name, checkTypeProperties, @@ -54,6 +57,7 @@ internal ContainerResolutionBuilder( _wellKnownTypes = wellKnownTypes; _createFunctionResolutionBuilderFactory = createFunctionResolutionBuilderFactory; _synchronicityDecisionMakerFactory = synchronicityDecisionMakerFactory; + FunctionCycleTracker = functionCycleTracker; _scopeManager = scopeManagerFactory(this, transientScopeInterfaceResolutionBuilder); transientScopeInterfaceResolutionBuilder.AddImplementation(this); @@ -74,6 +78,8 @@ public MultiSynchronicityFunctionCallResolution CreateContainerInstanceReference containerReference, new (_synchronicityDecisionMakerFactory)); + public IFunctionCycleTracker FunctionCycleTracker { get; } + public override MultiSynchronicityFunctionCallResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter) => CreateContainerInstanceReferenceResolution(parameter, "this"); @@ -337,7 +343,7 @@ public ContainerResolution Build() RootReferenceGenerator.Generate("_disposable"))); } - public void EnqueueRangedInstanceResolution( + public MultiSynchronicityFunctionCallResolution EnqueueRangedInstanceResolution( ForConstructorParameter parameter, string label, string reference, diff --git a/Main/ResolutionBuilding/Function/ContainerCreateFunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/ContainerCreateFunctionResolutionBuilder.cs index bf6d09af..896aa238 100644 --- a/Main/ResolutionBuilding/Function/ContainerCreateFunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/ContainerCreateFunctionResolutionBuilder.cs @@ -13,13 +13,23 @@ public ContainerCreateFunctionResolutionBuilder( IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, INamedTypeSymbol returnType, IFunctionResolutionSynchronicityDecisionMaker synchronicityDecisionMaker, - - + // dependencies WellKnownTypes wellKnownTypes, IReferenceGeneratorFactory referenceGeneratorFactory, + IFunctionCycleTracker functionCycleTracker, Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) - : base(rangeResolutionBaseBuilder, returnType, Array.Empty<(ITypeSymbol, ParameterResolution)>(), synchronicityDecisionMaker, wellKnownTypes, referenceGeneratorFactory, localFunctionResolutionBuilderFactory) + : base( + rangeResolutionBaseBuilder, + returnType, + Array.Empty<(ITypeSymbol, ParameterResolution)>(), + synchronicityDecisionMaker, + new object(), + + wellKnownTypes, + referenceGeneratorFactory, + functionCycleTracker, + localFunctionResolutionBuilderFactory) { _returnType = returnType; diff --git a/Main/ResolutionBuilding/Function/FunctionCycleTracker.cs b/Main/ResolutionBuilding/Function/FunctionCycleTracker.cs new file mode 100644 index 00000000..4ff10520 --- /dev/null +++ b/Main/ResolutionBuilding/Function/FunctionCycleTracker.cs @@ -0,0 +1,39 @@ +namespace MrMeeseeks.DIE.ResolutionBuilding.Function; + +internal interface IFunctionCycleTracker +{ + void TrackFunctionCall(FunctionResolutionBuilderHandle from, FunctionResolutionBuilderHandle to); + + void DetectCycle(); +} + +internal class FunctionCycleTracker : IFunctionCycleTracker +{ + private readonly Dictionary> _adjacencyMap = new (); + + public void TrackFunctionCall(FunctionResolutionBuilderHandle from, FunctionResolutionBuilderHandle to) + { + if (_adjacencyMap.TryGetValue(from, out var neighbors)) + neighbors.Add(to); + else + _adjacencyMap[from] = new List { to }; + } + + public void DetectCycle() + { + foreach (var function in _adjacencyMap.Keys) + DetectCycleInner(function, ImmutableStack.Empty); + + void DetectCycleInner(FunctionResolutionBuilderHandle current, IImmutableStack stack) + { + if (stack.Any(h => h.Identity == current.Identity)) + throw new FunctionCycleDieException(); + if (_adjacencyMap.TryGetValue(current, out var neighbors)) + { + stack = stack.Push(current); + foreach (var neighbor in neighbors) + DetectCycleInner(neighbor, stack); + } + } + } +} \ No newline at end of file diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs index e1befbc9..348c1229 100644 --- a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs @@ -56,6 +56,7 @@ internal abstract partial class FunctionResolutionBuilder : IFunctionResolutionB private readonly IRangeResolutionBaseBuilder _rangeResolutionBaseBuilder; private readonly IFunctionResolutionSynchronicityDecisionMaker _synchronicityDecisionMaker; private readonly WellKnownTypes _wellKnownTypes; + private readonly IFunctionCycleTracker _functionCycleTracker; private readonly Func, ILocalFunctionResolutionBuilder> _localFunctionResolutionBuilderFactory; private readonly ICheckTypeProperties _checkTypeProperties; @@ -63,6 +64,8 @@ internal abstract partial class FunctionResolutionBuilder : IFunctionResolutionB private readonly IUserProvidedScopeElements _userProvidedScopeElements; + private readonly FunctionResolutionBuilderHandle _handle; + protected readonly IList LocalFunctions = new List(); protected abstract string Name { get; } @@ -82,24 +85,30 @@ internal FunctionResolutionBuilder( INamedTypeSymbol returnType, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters, IFunctionResolutionSynchronicityDecisionMaker synchronicityDecisionMaker, + object handleIdentity, // dependencies WellKnownTypes wellKnownTypes, IReferenceGeneratorFactory referenceGeneratorFactory, + IFunctionCycleTracker functionCycleTracker, Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) { OriginalReturnType = returnType; _rangeResolutionBaseBuilder = rangeResolutionBaseBuilder; _synchronicityDecisionMaker = synchronicityDecisionMaker; _wellKnownTypes = wellKnownTypes; + _functionCycleTracker = functionCycleTracker; _localFunctionResolutionBuilderFactory = localFunctionResolutionBuilderFactory; _checkTypeProperties = rangeResolutionBaseBuilder.CheckTypeProperties; _userProvidedScopeElements = rangeResolutionBaseBuilder.UserProvidedScopeElements; + _handle = new FunctionResolutionBuilderHandle( + handleIdentity, + $"{OriginalReturnType.FullName()}({string.Join(", ", currentParameters.Select(p => p.Resolution.TypeFullName))})"); RootReferenceGenerator = referenceGeneratorFactory.Create(); Parameters = currentParameters - .Select(p => new ParameterResolution(RootReferenceGenerator.Generate(p.Type), TypeFullName)) + .Select(p => new ParameterResolution(RootReferenceGenerator.Generate(p.Type), p.Resolution.TypeFullName)) .ToList(); Resolvable = new(CreateResolvable); @@ -565,6 +574,9 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup currentParameters), null), _ => SwitchImplementation(nextParameter) }; + + if (ret.Item1 is MultiSynchronicityFunctionCallResolution multi) + _functionCycleTracker.TrackFunctionCall(_handle, multi.FunctionResolutionBuilderHandle); if (ret.Item1 is ScopeRootResolution { ScopeRootFunction: IAwaitableResolution awaitableResolution }) _synchronicityDecisionMaker.Register(awaitableResolution); @@ -621,6 +633,9 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup _ => CreateConstructorResolution(nextParameter) }; + + if (ret.Item1 is MultiSynchronicityFunctionCallResolution multi) + _functionCycleTracker.TrackFunctionCall(_handle, multi.FunctionResolutionBuilderHandle); if (ret.Item1 is IAwaitableResolution awaitableResolution) _synchronicityDecisionMaker.Register(awaitableResolution); @@ -862,7 +877,8 @@ public MultiSynchronicityFunctionCallResolution BuildFunctionCall( Name, ownerReference, Parameters.Zip(currentParameters, (p, cp) => (p.Reference, cp.Resolution.Reference)).ToList()), - SynchronicityDecision); + SynchronicityDecision, + _handle); } public MethodGroupResolution BuildMethodGroup() => new (Name, TypeFullName, null); diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilderHandle.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilderHandle.cs new file mode 100644 index 00000000..9f718a4f --- /dev/null +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilderHandle.cs @@ -0,0 +1,5 @@ +namespace MrMeeseeks.DIE.ResolutionBuilding.Function; + +public record FunctionResolutionBuilderHandle( + object Identity, + string Description); \ No newline at end of file diff --git a/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs index 7b4edd2f..242375ec 100644 --- a/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs @@ -16,12 +16,22 @@ public LocalFunctionResolutionBuilder( IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> parameters, IFunctionResolutionSynchronicityDecisionMaker synchronicityDecisionMaker, - // dependencies WellKnownTypes wellKnownTypes, IReferenceGeneratorFactory referenceGeneratorFactory, + IFunctionCycleTracker functionCycleTracker, Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) - : base(rangeResolutionBaseBuilder, returnType, parameters, synchronicityDecisionMaker, wellKnownTypes, referenceGeneratorFactory, localFunctionResolutionBuilderFactory) + : base( + rangeResolutionBaseBuilder, + returnType, + parameters, + synchronicityDecisionMaker, + new object(), + + wellKnownTypes, + referenceGeneratorFactory, + functionCycleTracker, + localFunctionResolutionBuilderFactory) { _returnType = returnType; _parameters = parameters; diff --git a/Main/ResolutionBuilding/Function/RangedFunctionGroupResolutionBuilder.cs b/Main/ResolutionBuilding/Function/RangedFunctionGroupResolutionBuilder.cs index b096325e..bb8985b6 100644 --- a/Main/ResolutionBuilding/Function/RangedFunctionGroupResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/RangedFunctionGroupResolutionBuilder.cs @@ -20,6 +20,7 @@ private readonly Func< string, ForConstructorParameter, IFunctionResolutionSynchronicityDecisionMaker, + object, IRangedFunctionResolutionBuilder> _rangedFunctionResolutionBuilderFactory; private readonly string _reference; private readonly string _typeFullName; @@ -39,7 +40,7 @@ internal RangedFunctionGroupResolutionBuilder( // dependencies IReferenceGeneratorFactory referenceGeneratorFactory, - Func rangedFunctionResolutionBuilderFactory) + Func rangedFunctionResolutionBuilderFactory) { _rangeResolutionBaseBuilder = rangeResolutionBaseBuilder; _rangedFunctionResolutionBuilderFactory = rangedFunctionResolutionBuilderFactory; @@ -58,7 +59,12 @@ public IRangedFunctionResolutionBuilder GetInstanceFunction( var listedParameterTypes = string.Join(",", parameter.CurrentFuncParameters.Select(p => p.Item2.TypeFullName)); if (!_overloads.TryGetValue(listedParameterTypes, out var function)) { - function = _rangedFunctionResolutionBuilderFactory(_rangeResolutionBaseBuilder, _reference, parameter, synchronicityDecisionMaker.Value); + function = _rangedFunctionResolutionBuilderFactory( + _rangeResolutionBaseBuilder, + _reference, + parameter, + synchronicityDecisionMaker.Value, + this); _overloads[listedParameterTypes] = function; _functionQueue.Add(function); } diff --git a/Main/ResolutionBuilding/Function/RangedFunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/RangedFunctionResolutionBuilder.cs index 38765ab3..9cfc5030 100644 --- a/Main/ResolutionBuilding/Function/RangedFunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/RangedFunctionResolutionBuilder.cs @@ -14,13 +14,24 @@ public RangedFunctionResolutionBuilder( string reference, ForConstructorParameter forConstructorParameter, IFunctionResolutionSynchronicityDecisionMaker synchronicityDecisionMaker, - + object handleIdentity, // dependencies WellKnownTypes wellKnownTypes, IReferenceGeneratorFactory referenceGeneratorFactory, + IFunctionCycleTracker functionCycleTracker, Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) - : base(rangeResolutionBaseBuilder, forConstructorParameter.ImplementationType, forConstructorParameter.CurrentFuncParameters, synchronicityDecisionMaker, wellKnownTypes, referenceGeneratorFactory, localFunctionResolutionBuilderFactory) + : base( + rangeResolutionBaseBuilder, + forConstructorParameter.ImplementationType, + forConstructorParameter.CurrentFuncParameters, + synchronicityDecisionMaker, + handleIdentity, + + wellKnownTypes, + referenceGeneratorFactory, + functionCycleTracker, + localFunctionResolutionBuilderFactory) { _forConstructorParameter = forConstructorParameter; diff --git a/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs index eeaa6e70..5131ba98 100644 --- a/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs @@ -14,12 +14,22 @@ public ScopeRootCreateFunctionResolutionBuilder( SwitchImplementationParameter parameter, IFunctionResolutionSynchronicityDecisionMaker synchronicityDecisionMaker, - // dependencies WellKnownTypes wellKnownTypes, IReferenceGeneratorFactory referenceGeneratorFactory, + IFunctionCycleTracker functionCycleTracker, Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) - : base(rangeResolutionBaseBuilder, parameter.ReturnType, parameter.CurrentParameters, synchronicityDecisionMaker, wellKnownTypes, referenceGeneratorFactory, localFunctionResolutionBuilderFactory) + : base( + rangeResolutionBaseBuilder, + parameter.ReturnType, + parameter.CurrentParameters, + synchronicityDecisionMaker, + new object(), + + wellKnownTypes, + referenceGeneratorFactory, + functionCycleTracker, + localFunctionResolutionBuilderFactory) { _parameter = parameter; diff --git a/Main/ResolutionBuilding/ITransientScopeImplementationResolutionBuilder.cs b/Main/ResolutionBuilding/ITransientScopeImplementationResolutionBuilder.cs index ba4215ba..564c283e 100644 --- a/Main/ResolutionBuilding/ITransientScopeImplementationResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ITransientScopeImplementationResolutionBuilder.cs @@ -4,7 +4,7 @@ namespace MrMeeseeks.DIE.ResolutionBuilding; internal interface ITransientScopeImplementationResolutionBuilder { - void EnqueueRangedInstanceResolution( + MultiSynchronicityFunctionCallResolution EnqueueRangedInstanceResolution( ForConstructorParameter parameter, string label, string reference, diff --git a/Main/ResolutionBuilding/ResolutionDtos.cs b/Main/ResolutionBuilding/ResolutionDtos.cs index 1b1ee718..7e3bc599 100644 --- a/Main/ResolutionBuilding/ResolutionDtos.cs +++ b/Main/ResolutionBuilding/ResolutionDtos.cs @@ -1,3 +1,5 @@ +using MrMeeseeks.DIE.ResolutionBuilding.Function; + namespace MrMeeseeks.DIE.ResolutionBuilding; internal abstract record InterfaceExtension( @@ -80,4 +82,5 @@ internal record RangedInstanceResolutionsQueueItem( ForConstructorParameter Parameter, string Label, string Reference, - string Key); \ No newline at end of file + string Key, + FunctionResolutionBuilderHandle Handle); \ No newline at end of file diff --git a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs index 392d67ca..4d4605df 100644 --- a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs @@ -104,7 +104,7 @@ public ScopeRootResolution AddCreateResolveFunction( string transientInstanceScopeReference, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) { - var key = rootType.FullName(); + var key = $"{rootType.FullName()}{(currentParameters.Any() ? $"_{string.Join(";", currentParameters)}" : "")}"; if (!_scopeRootFunctionResolutions.TryGetValue( key, out var function)) diff --git a/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs b/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs index 3955821a..f3b5e824 100644 --- a/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs +++ b/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs @@ -20,8 +20,8 @@ internal class TransientScopeInterfaceResolutionBuilder : ITransientScopeInterfa private readonly IList _implementations = new List(); - private readonly IDictionary _rangedInstanceReferences = - new Dictionary(); + private readonly IDictionary _rangedInstanceReferences = + new Dictionary(); private readonly IDictionary _rangedInstanceReferenceResolutions = new Dictionary(); @@ -30,7 +30,7 @@ internal class TransientScopeInterfaceResolutionBuilder : ITransientScopeInterfa private readonly WellKnownTypes _wellKnownTypes; - private readonly Func _rangedFunctionGroupResolutionBuilderFactory; + private readonly IFunctionCycleTracker _functionCycleTracker; private readonly Func _synchronicityDecisionMakerFactory; private readonly string _name; @@ -40,11 +40,11 @@ internal class TransientScopeInterfaceResolutionBuilder : ITransientScopeInterfa public TransientScopeInterfaceResolutionBuilder( IReferenceGeneratorFactory referenceGeneratorFactory, WellKnownTypes wellKnownTypes, - Func rangedFunctionGroupResolutionBuilderFactory, + IFunctionCycleTracker functionCycleTracker, Func synchronicityDecisionMakerFactory) { _wellKnownTypes = wellKnownTypes; - _rangedFunctionGroupResolutionBuilderFactory = rangedFunctionGroupResolutionBuilderFactory; + _functionCycleTracker = functionCycleTracker; _synchronicityDecisionMakerFactory = synchronicityDecisionMakerFactory; _rootReferenceGenerator = referenceGeneratorFactory.Create(); @@ -56,12 +56,15 @@ public TransientScopeInterfaceResolutionBuilder( public void AddImplementation(ITransientScopeImplementationResolutionBuilder implementation) { - foreach (var (parameter, label, reference, key) in _pastQueuedItems) - implementation.EnqueueRangedInstanceResolution( + foreach (var (parameter, label, reference, key, handle) in _pastQueuedItems) + { + var multiSynchronicityFunctionCallResolution = implementation.EnqueueRangedInstanceResolution( parameter, label, reference, new (() => _synchronicityDecisionMakers[key])); + _functionCycleTracker.TrackFunctionCall(handle, multiSynchronicityFunctionCallResolution.FunctionResolutionBuilderHandle); + } _implementations.Add(implementation); } @@ -90,14 +93,18 @@ private MultiSynchronicityFunctionCallResolution CreateRangedInstanceReferenceRe _ => null }; var referenceKey = $"{implementationType.FullName()}{interfaceExtension?.KeySuffix() ?? ""}"; - if (!_rangedInstanceReferences.TryGetValue(referenceKey, out var reference)) + if (!_rangedInstanceReferences.TryGetValue(referenceKey, out var tuple)) { var decorationSuffix = interfaceExtension?.RangedNameSuffix() ?? ""; - reference = - _rootReferenceGenerator.Generate($"Get{label}Instance", implementationType, decorationSuffix); - _rangedInstanceReferences[referenceKey] = reference; + tuple = ( + _rootReferenceGenerator.Generate($"Get{label}Instance", implementationType, decorationSuffix), + new FunctionResolutionBuilderHandle(new object(), "asdf")); + + _rangedInstanceReferences[referenceKey] = tuple; } - + + var (reference, handle) = tuple; + var key = $"{referenceKey}:::{string.Join(":::", currentParameters.Select(p => p.Type.FullName()))}"; if (!_rangedInstanceReferenceResolutions.TryGetValue(key, out var interfaceDeclaration)) { @@ -105,7 +112,8 @@ private MultiSynchronicityFunctionCallResolution CreateRangedInstanceReferenceRe parameter, label, reference, - key); + key, + handle); _pastQueuedItems.Add(queueItem); @@ -113,11 +121,14 @@ private MultiSynchronicityFunctionCallResolution CreateRangedInstanceReferenceRe _synchronicityDecisionMakers[key] = synchronicityDecisionMaker; foreach (var implementation in _implementations) - implementation.EnqueueRangedInstanceResolution( + { + var multiSynchronicityFunctionCallResolution = implementation.EnqueueRangedInstanceResolution( queueItem.Parameter, queueItem.Label, queueItem.Reference, new (() => synchronicityDecisionMaker)); + _functionCycleTracker.TrackFunctionCall(handle, multiSynchronicityFunctionCallResolution.FunctionResolutionBuilderHandle); + } interfaceDeclaration = new InterfaceFunctionDeclarationResolution( reference, @@ -155,6 +166,7 @@ private MultiSynchronicityFunctionCallResolution CreateRangedInstanceReferenceRe owningObjectReference, interfaceDeclaration.Parameter.Zip(currentParameters, (p, cp) => (p.Reference, cp.Resolution.Reference)) .ToList()), - _synchronicityDecisionMakers[key].Decision); + _synchronicityDecisionMakers[key].Decision, + handle); } } \ No newline at end of file diff --git a/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs b/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs index 74838d0d..f84d0e1e 100644 --- a/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs @@ -98,7 +98,7 @@ public TransientScopeRootResolution AddCreateResolveFunction( string containerInstanceScopeReference, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) { - var key = rootType.FullName(); + var key = $"{rootType.FullName()}{(currentParameters.Any() ? $"_{string.Join(";", currentParameters)}" : "")}"; if (!_transientScopeRootFunctionResolutions.TryGetValue( key, out var function)) @@ -148,7 +148,7 @@ public TransientScopeResolution Build() => _containerParameterReference, Name); - public void EnqueueRangedInstanceResolution( + public MultiSynchronicityFunctionCallResolution EnqueueRangedInstanceResolution( ForConstructorParameter parameter, string label, string reference, diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index 1ff2d2a4..02354926 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -346,7 +346,8 @@ internal record MultiSynchronicityFunctionCallResolution( FunctionCallResolution Sync, FunctionCallResolution AsyncTask, FunctionCallResolution AsyncValueTask, - Lazy LazySynchronicityDecision) : Resolvable(Sync.Reference, ""), IAwaitableResolution, ITaskConsumableResolution + Lazy LazySynchronicityDecision, + FunctionResolutionBuilderHandle FunctionResolutionBuilderHandle) : Resolvable(Sync.Reference, ""), IAwaitableResolution, ITaskConsumableResolution { internal FunctionCallResolution SelectedFunctionCall => LazySynchronicityDecision.Value switch diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index 2ca906da..a8b16232 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -54,10 +54,12 @@ IContainerResolutionBuilder ResolutionTreeFactory(IContainerInfo ci) wellKnownTypesChoice, wellKnownTypesMiscellaneous)); + var functionCycleTracker = new FunctionCycleTracker(); + return new ContainerResolutionBuilder( ci, - new TransientScopeInterfaceResolutionBuilder(referenceGeneratorFactory, wellKnownTypes, RangedFunctionGroupResolutionBuilderFactory, FunctionResolutionSynchronicityDecisionMakerFactory), + new TransientScopeInterfaceResolutionBuilder(referenceGeneratorFactory, wellKnownTypes, functionCycleTracker, FunctionResolutionSynchronicityDecisionMakerFactory), referenceGeneratorFactory, new CheckTypeProperties(new CurrentlyConsideredTypes(containerTypesFromAttributesList, implementationTypeSetCache), wellKnownTypes), wellKnownTypes, @@ -65,7 +67,8 @@ IContainerResolutionBuilder ResolutionTreeFactory(IContainerInfo ci) ContainerCreateFunctionResolutionBuilderFactory, RangedFunctionGroupResolutionBuilderFactory, FunctionResolutionSynchronicityDecisionMakerFactory, - new UserProvidedScopeElements(ci.ContainerType)); + new UserProvidedScopeElements(ci.ContainerType), + functionCycleTracker); IScopeManager ScopeManagerFactory( IContainerResolutionBuilder containerResolutionBuilder, @@ -136,6 +139,7 @@ ILocalFunctionResolutionBuilder LocalFunctionResolutionBuilderFactory( wellKnownTypes, referenceGeneratorFactory, + functionCycleTracker, LocalFunctionResolutionBuilderFactory); IContainerCreateFunctionResolutionBuilder ContainerCreateFunctionResolutionBuilderFactory( @@ -147,6 +151,7 @@ IContainerCreateFunctionResolutionBuilder ContainerCreateFunctionResolutionBuild wellKnownTypes, referenceGeneratorFactory, + functionCycleTracker, LocalFunctionResolutionBuilderFactory); IScopeRootCreateFunctionResolutionBuilder ScopeRootCreateFunctionResolutionBuilderFactory( @@ -158,20 +163,24 @@ IScopeRootCreateFunctionResolutionBuilder ScopeRootCreateFunctionResolutionBuild wellKnownTypes, referenceGeneratorFactory, + functionCycleTracker, LocalFunctionResolutionBuilderFactory); IRangedFunctionResolutionBuilder RangedFunctionResolutionBuilderFactory( IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, string reference, ForConstructorParameter forConstructorParameter, - IFunctionResolutionSynchronicityDecisionMaker synchronicityDecisionMaker) => new RangedFunctionResolutionBuilder( + IFunctionResolutionSynchronicityDecisionMaker synchronicityDecisionMaker, + object handleIdentity) => new RangedFunctionResolutionBuilder( rangeResolutionBaseBuilder, reference, forConstructorParameter, synchronicityDecisionMaker, + handleIdentity, wellKnownTypes, referenceGeneratorFactory, + functionCycleTracker, LocalFunctionResolutionBuilderFactory); IRangedFunctionGroupResolutionBuilder RangedFunctionGroupResolutionBuilderFactory( diff --git a/Sample/Context.cs b/Sample/Context.cs index ff4b3b50..f00d4997 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -1,11 +1,16 @@ -using MrMeeseeks.DIE.Configuration.Attributes; -using MrMeeseeks.DIE.SampleChild; +using System; +using MrMeeseeks.DIE.Configuration.Attributes; +using MrMeeseeks.DIE.Sample; +namespace MrMeeseeks.DIE.Test.CycleDetection.Function.NoCycle.DirectRecursionScope; -namespace MrMeeseeks.DIE.Test.Implementation.Aggregation.AssemblyImplementationsAggregation; +internal class Dependency : IScopeInstance +{ + internal Dependency(Func inner) {} +} -[FilterAllImplementationsAggregation] -[AssemblyImplementationsAggregation(typeof(MrMeeseeks.DIE.SampleChild.AssemblyInfo))] -[ConstructorChoice(typeof(Parent.ClassToo))] -[CreateFunction(typeof(Parent.ClassToo), "Create")] -internal partial class Container {} \ No newline at end of file +[CreateFunction(typeof(Dependency), "Create")] +internal partial class Container +{ + +} \ No newline at end of file diff --git a/Test/CycleDetection/Function/Cycle/DirectRecursionContainer.cs b/Test/CycleDetection/Function/Cycle/DirectRecursionContainer.cs new file mode 100644 index 00000000..8ed06963 --- /dev/null +++ b/Test/CycleDetection/Function/Cycle/DirectRecursionContainer.cs @@ -0,0 +1,25 @@ +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CycleDetection.Function.Cycle.DirectRecursionContainer; + +internal class Dependency : IContainerInstance +{ + internal Dependency(Dependency inner) {} +} + +[CreateFunction(typeof(Dependency), "Create")] +internal partial class Container +{ + +} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + Assert.Equal(DieExceptionKind.FunctionCycle , container.ExceptionKind_0_0); + } +} \ No newline at end of file diff --git a/Test/CycleDetection/Function/Cycle/DirectRecursionScope.cs b/Test/CycleDetection/Function/Cycle/DirectRecursionScope.cs new file mode 100644 index 00000000..0e57f7d2 --- /dev/null +++ b/Test/CycleDetection/Function/Cycle/DirectRecursionScope.cs @@ -0,0 +1,25 @@ +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CycleDetection.Function.Cycle.DirectRecursionScope; + +internal class Dependency : IScopeInstance +{ + internal Dependency(Dependency inner) {} +} + +[CreateFunction(typeof(Dependency), "Create")] +internal partial class Container +{ + +} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + Assert.Equal(DieExceptionKind.FunctionCycle , container.ExceptionKind_0_0); + } +} \ No newline at end of file diff --git a/Test/CycleDetection/Function/Cycle/DirectRecursionTransientScope.cs b/Test/CycleDetection/Function/Cycle/DirectRecursionTransientScope.cs new file mode 100644 index 00000000..06e1f61a --- /dev/null +++ b/Test/CycleDetection/Function/Cycle/DirectRecursionTransientScope.cs @@ -0,0 +1,25 @@ +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CycleDetection.Function.Cycle.DirectRecursionTransientScope; + +internal class Dependency : ITransientScopeInstance +{ + internal Dependency(Dependency inner) {} +} + +[CreateFunction(typeof(Dependency), "Create")] +internal partial class Container +{ + +} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + Assert.Equal(DieExceptionKind.FunctionCycle , container.ExceptionKind_0_0); + } +} \ No newline at end of file diff --git a/Test/CycleDetection/Function/NoCycle/DirectRecursionContainerFunc.cs b/Test/CycleDetection/Function/NoCycle/DirectRecursionContainerFunc.cs new file mode 100644 index 00000000..af9fd027 --- /dev/null +++ b/Test/CycleDetection/Function/NoCycle/DirectRecursionContainerFunc.cs @@ -0,0 +1,27 @@ +using System; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CycleDetection.Function.NoCycle.DirectRecursionContainerFunc; + +internal class Dependency : IContainerInstance +{ + internal Dependency(Func inner) {} +} + +[CreateFunction(typeof(Dependency), "Create")] +internal partial class Container +{ + +} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var instance = container.Create(); + Assert.IsType(instance); + } +} \ No newline at end of file diff --git a/Test/CycleDetection/Function/NoCycle/DirectRecursionContainerLazy.cs b/Test/CycleDetection/Function/NoCycle/DirectRecursionContainerLazy.cs new file mode 100644 index 00000000..d3679f03 --- /dev/null +++ b/Test/CycleDetection/Function/NoCycle/DirectRecursionContainerLazy.cs @@ -0,0 +1,27 @@ +using System; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CycleDetection.Function.NoCycle.DirectRecursionContainerLazy; + +internal class Dependency : IContainerInstance +{ + internal Dependency(Lazy inner) {} +} + +[CreateFunction(typeof(Dependency), "Create")] +internal partial class Container +{ + +} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var instance = container.Create(); + Assert.IsType(instance); + } +} \ No newline at end of file diff --git a/Test/CycleDetection/Function/NoCycle/DirectRecursionScopeFunc.cs b/Test/CycleDetection/Function/NoCycle/DirectRecursionScopeFunc.cs new file mode 100644 index 00000000..31a87b01 --- /dev/null +++ b/Test/CycleDetection/Function/NoCycle/DirectRecursionScopeFunc.cs @@ -0,0 +1,27 @@ +using System; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CycleDetection.Function.NoCycle.DirectRecursionScopeFunc; + +internal class Dependency : IScopeInstance +{ + internal Dependency(Func inner) {} +} + +[CreateFunction(typeof(Dependency), "Create")] +internal partial class Container +{ + +} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var instance = container.Create(); + Assert.IsType(instance); + } +} \ No newline at end of file diff --git a/Test/CycleDetection/Function/NoCycle/DirectRecursionScopeLazy.cs b/Test/CycleDetection/Function/NoCycle/DirectRecursionScopeLazy.cs new file mode 100644 index 00000000..62be632e --- /dev/null +++ b/Test/CycleDetection/Function/NoCycle/DirectRecursionScopeLazy.cs @@ -0,0 +1,27 @@ +using System; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CycleDetection.Function.NoCycle.DirectRecursionScopeLazy; + +internal class Dependency : IScopeInstance +{ + internal Dependency(Lazy inner) {} +} + +[CreateFunction(typeof(Dependency), "Create")] +internal partial class Container +{ + +} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var instance = container.Create(); + Assert.IsType(instance); + } +} \ No newline at end of file diff --git a/Test/CycleDetection/Function/NoCycle/DirectRecursionTransientScopeFunc.cs b/Test/CycleDetection/Function/NoCycle/DirectRecursionTransientScopeFunc.cs new file mode 100644 index 00000000..e619c3c0 --- /dev/null +++ b/Test/CycleDetection/Function/NoCycle/DirectRecursionTransientScopeFunc.cs @@ -0,0 +1,27 @@ +using System; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CycleDetection.Function.NoCycle.DirectRecursionTransientScopeFunc; + +internal class Dependency : ITransientScopeInstance +{ + internal Dependency(Func inner) {} +} + +[CreateFunction(typeof(Dependency), "Create")] +internal partial class Container +{ + +} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var instance = container.Create(); + Assert.IsType(instance); + } +} \ No newline at end of file diff --git a/Test/CycleDetection/Function/NoCycle/DirectRecursionTransientScopeLazy.cs b/Test/CycleDetection/Function/NoCycle/DirectRecursionTransientScopeLazy.cs new file mode 100644 index 00000000..d27f8897 --- /dev/null +++ b/Test/CycleDetection/Function/NoCycle/DirectRecursionTransientScopeLazy.cs @@ -0,0 +1,27 @@ +using System; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CycleDetection.Function.NoCycle.DirectRecursionTransientScopeLazy; + +internal class Dependency : ITransientScopeInstance +{ + internal Dependency(Lazy inner) {} +} + +[CreateFunction(typeof(Dependency), "Create")] +internal partial class Container +{ + +} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + var instance = container.Create(); + Assert.IsType(instance); + } +} \ No newline at end of file diff --git a/Test/CycleDetection/Implementation.cs b/Test/CycleDetection/Implementation/Cycle/DirectRecursion.cs similarity index 84% rename from Test/CycleDetection/Implementation.cs rename to Test/CycleDetection/Implementation/Cycle/DirectRecursion.cs index fac8ba4e..a3f2ceb6 100644 --- a/Test/CycleDetection/Implementation.cs +++ b/Test/CycleDetection/Implementation/Cycle/DirectRecursion.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.CycleDetection.Implementation; +namespace MrMeeseeks.DIE.Test.CycleDetection.Implementation.Cycle.DirectRecursion; internal class Dependency { diff --git a/Test/CycleDetection/ImplementationProxied.cs b/Test/CycleDetection/Implementation/Cycle/ImplementationProxied.cs similarity index 84% rename from Test/CycleDetection/ImplementationProxied.cs rename to Test/CycleDetection/Implementation/Cycle/ImplementationProxied.cs index bd32bb1f..11257ea7 100644 --- a/Test/CycleDetection/ImplementationProxied.cs +++ b/Test/CycleDetection/Implementation/Cycle/ImplementationProxied.cs @@ -1,8 +1,7 @@ -using MrMeeseeks.DIE; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.CycleDetection.ImplementationProxied; +namespace MrMeeseeks.DIE.Test.CycleDetection.Implementation.Cycle.Proxied; internal class Proxy diff --git a/Test/CycleDetection/NoCycleInParallel.cs b/Test/CycleDetection/Implementation/NoCycle/NoCycleInParallel.cs similarity index 87% rename from Test/CycleDetection/NoCycleInParallel.cs rename to Test/CycleDetection/Implementation/NoCycle/NoCycleInParallel.cs index e8d6531f..6be2085e 100644 --- a/Test/CycleDetection/NoCycleInParallel.cs +++ b/Test/CycleDetection/Implementation/NoCycle/NoCycleInParallel.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.CycleDetection.NoCycleInParallel; +namespace MrMeeseeks.DIE.Test.CycleDetection.Implementation.InParallel; internal class Dependency { diff --git a/Test/Scoping/InScope.cs b/Test/Scoping/InScope.cs new file mode 100644 index 00000000..eaf2f105 --- /dev/null +++ b/Test/Scoping/InScope.cs @@ -0,0 +1,25 @@ +using System; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Scoping.SameScopeDifferentParameters; + +internal class ScopeRoot : IScopeRoot +{ +} + +[CreateFunction(typeof(Func), "Create0")] +[CreateFunction(typeof(Func), "Create1")] +internal partial class Container +{ + +} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + } +} \ No newline at end of file From 88f468a0ab9d40ad24582d34cf7256df92d86533 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sun, 29 May 2022 22:36:13 +0200 Subject: [PATCH 078/162] Moving local functions to scope classes and avoiding to double them --- Main/CodeBuilding/RangeCodeBaseBuilder.cs | 20 +++----- Main/Configuration/Attributes/Aggregation.cs | 1 + Main/Configuration/Attributes/Choice.cs | 1 + .../Configuration/Attributes/Miscellaneous.cs | 1 + Main/Configuration/CheckTypeProperties.cs | 1 - .../Configuration/CurrentlyConsideredTypes.cs | 2 - .../ContainerResolutionBuilder.cs | 32 +++++++------ ...ontainerCreateFunctionResolutionBuilder.cs | 16 +------ .../Function/FunctionResolutionBuilder.cs | 27 ++++------- .../LocalFunctionResolutionBuilder.cs | 16 +------ .../RangedFunctionGroupResolutionBuilder.cs | 1 - .../RangedFunctionResolutionBuilder.cs | 16 +------ ...copeRootCreateFunctionResolutionBuilder.cs | 16 +------ .../RangeResolutionBaseBuilder.cs | 46 ++++++++++++++++--- Main/ResolutionBuilding/ScopeManager.cs | 6 +-- .../ScopeResolutionBuilder.cs | 21 +++++++-- .../TransientScopeResolutionBuilder.cs | 21 +++++++-- Main/ResolutionTreeItem.cs | 20 ++++---- Main/SourceGenerator.cs | 19 ++++---- 19 files changed, 139 insertions(+), 144 deletions(-) diff --git a/Main/CodeBuilding/RangeCodeBaseBuilder.cs b/Main/CodeBuilding/RangeCodeBaseBuilder.cs index ad8083e6..e6d659eb 100644 --- a/Main/CodeBuilding/RangeCodeBaseBuilder.cs +++ b/Main/CodeBuilding/RangeCodeBaseBuilder.cs @@ -31,6 +31,8 @@ protected StringBuilder GenerateResolutionRange( stringBuilder = rangeResolution.RangedInstanceFunctionGroups.Aggregate(stringBuilder, GenerateRangedInstanceFunction); stringBuilder = rangeResolution.RootResolutions.Aggregate(stringBuilder, GenerateResolutionFunction); + + stringBuilder = rangeResolution.LocalFunctions.Aggregate(stringBuilder, GenerateResolutionFunction); return GenerateDisposalFunction( stringBuilder, @@ -157,9 +159,7 @@ private StringBuilder GenerateResolutionFunction( .AppendLine($"if (this.{_rangeResolution.DisposalHandling.DisposedPropertyReference}) throw new {WellKnownTypes.ObjectDisposedException}(\"\");"); stringBuilder = GenerateResolutionFunctionContent(stringBuilder, resolution.Resolvable) - .AppendLine($"return {resolution.Resolvable.Reference};"); - - stringBuilder = resolution.LocalFunctions.Aggregate(stringBuilder, GenerateResolutionFunction) + .AppendLine($"return {resolution.Resolvable.Reference};") .AppendLine($"}}"); return stringBuilder; @@ -168,20 +168,16 @@ private StringBuilder GenerateResolutionFunction( { var parameter = string.Join(",", resolution.Parameter.Select(r => $"{r.TypeFullName} {r.Reference}")); stringBuilder = stringBuilder - .AppendLine($"{(localFunctionResolution.SynchronicityDecision is SynchronicityDecision.AsyncTask or SynchronicityDecision.AsyncValueTask ? "async " : "")}{resolution.TypeFullName} {resolution.Reference}({parameter})") + .AppendLine($"private {(localFunctionResolution.SynchronicityDecision is SynchronicityDecision.AsyncTask or SynchronicityDecision.AsyncValueTask ? "async " : "")}{resolution.TypeFullName} {resolution.Reference}({parameter})") .AppendLine($"{{"); if (_containerResolution.DisposalType != DisposalType.None) stringBuilder = stringBuilder .AppendLine($"if (this.{_rangeResolution.DisposalHandling.DisposedPropertyReference}) throw new {WellKnownTypes.ObjectDisposedException}(\"\");"); stringBuilder = GenerateResolutionFunctionContent(stringBuilder, resolution.Resolvable) - .AppendLine($"return {resolution.Resolvable.Reference};"); - - stringBuilder = resolution.LocalFunctions.Aggregate(stringBuilder, GenerateResolutionFunction) + .AppendLine($"return {resolution.Resolvable.Reference};") .AppendLine($"}}"); - - return stringBuilder; } @@ -368,7 +364,7 @@ private StringBuilder GenerateResolutions( stringBuilder = stringBuilder .AppendLine($"{reference} = new {fullName}({resolvable.Reference});"); break; - case TaskFromWrappedValueTaskResolution(var resolvable, var reference, var fullName): + case TaskFromWrappedValueTaskResolution(var resolvable, var reference, _): stringBuilder = GenerateResolutions(stringBuilder, resolvable); stringBuilder = stringBuilder .AppendLine($"{reference} = {resolvable.Reference}.AsTask();"); @@ -595,9 +591,7 @@ private StringBuilder GenerateRangedInstanceFunction(StringBuilder stringBuilder .AppendLine($"{{") .AppendLine($"this.{rangedInstanceFunctionGroupResolution.LockReference}.Release();") .AppendLine($"}}") - .AppendLine($"return this.{rangedInstanceFunctionGroupResolution.FieldReference};"); - - stringBuilder = overload.LocalFunctions.Aggregate(stringBuilder, GenerateResolutionFunction) + .AppendLine($"return this.{rangedInstanceFunctionGroupResolution.FieldReference};") .AppendLine($"}}"); } diff --git a/Main/Configuration/Attributes/Aggregation.cs b/Main/Configuration/Attributes/Aggregation.cs index 21c94a45..2b108d88 100644 --- a/Main/Configuration/Attributes/Aggregation.cs +++ b/Main/Configuration/Attributes/Aggregation.cs @@ -1,3 +1,4 @@ +// ReSharper disable UnusedParameter.Local namespace MrMeeseeks.DIE.Configuration.Attributes; [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = false)] diff --git a/Main/Configuration/Attributes/Choice.cs b/Main/Configuration/Attributes/Choice.cs index f86beb7f..18212036 100644 --- a/Main/Configuration/Attributes/Choice.cs +++ b/Main/Configuration/Attributes/Choice.cs @@ -1,3 +1,4 @@ +// ReSharper disable UnusedParameter.Local namespace MrMeeseeks.DIE.Configuration.Attributes; [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] diff --git a/Main/Configuration/Attributes/Miscellaneous.cs b/Main/Configuration/Attributes/Miscellaneous.cs index 8ac0d57c..ee7faa6f 100644 --- a/Main/Configuration/Attributes/Miscellaneous.cs +++ b/Main/Configuration/Attributes/Miscellaneous.cs @@ -1,3 +1,4 @@ +// ReSharper disable UnusedParameter.Local namespace MrMeeseeks.DIE.Configuration.Attributes; [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] diff --git a/Main/Configuration/CheckTypeProperties.cs b/Main/Configuration/CheckTypeProperties.cs index 14652810..9e431fa7 100644 --- a/Main/Configuration/CheckTypeProperties.cs +++ b/Main/Configuration/CheckTypeProperties.cs @@ -66,7 +66,6 @@ public DisposalType ShouldDisposalBeManaged(INamedTypeSymbol implementationType) public ScopeLevel ShouldBeScopeRoot(INamedTypeSymbol implementationType) { - var unbound = implementationType.UnboundIfGeneric(); if (_currentlyConsideredTypes.TransientScopeRootTypes.Contains(implementationType.UnboundIfGeneric())) return ScopeLevel.TransientScope; if (_currentlyConsideredTypes.ScopeRootTypes.Contains(implementationType.UnboundIfGeneric())) diff --git a/Main/Configuration/CurrentlyConsideredTypes.cs b/Main/Configuration/CurrentlyConsideredTypes.cs index 3edb49db..7ddd14f0 100644 --- a/Main/Configuration/CurrentlyConsideredTypes.cs +++ b/Main/Configuration/CurrentlyConsideredTypes.cs @@ -229,7 +229,6 @@ public CurrentlyConsideredTypes( ImplementationMap); InterfaceToComposite = CompositeTypes - .OfType() .GroupBy(nts => { var namedTypeSymbol = nts.OriginalDefinition.AllInterfaces @@ -282,7 +281,6 @@ public CurrentlyConsideredTypes( ImplementationMap); InterfaceToDecorators = DecoratorTypes - .OfType() .GroupBy(nts => { var namedTypeSymbol = nts.OriginalDefinition.AllInterfaces diff --git a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs index 5c6b385c..244d7f92 100644 --- a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs @@ -16,7 +16,6 @@ MultiSynchronicityFunctionCallResolution CreateContainerInstanceReferenceResolut internal class ContainerResolutionBuilder : RangeResolutionBaseBuilder, IContainerResolutionBuilder, ITransientScopeImplementationResolutionBuilder { - private readonly IContainerInfo _containerInfo; private readonly ITransientScopeInterfaceResolutionBuilder _transientScopeInterfaceResolutionBuilder; private readonly WellKnownTypes _wellKnownTypes; private readonly Func _createFunctionResolutionBuilderFactory; @@ -39,8 +38,9 @@ internal ContainerResolutionBuilder( WellKnownTypes wellKnownTypes, Func scopeManagerFactory, Func createFunctionResolutionBuilderFactory, - Func rangedFunctionGroupResolutionBuilderFactory, - Func synchronicityDecisionMakerFactory, + Func rangedFunctionGroupResolutionBuilderFactory, + Func synchronicityDecisionMakerFactory, + Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory, IUserProvidedScopeElements userProvidedScopeElement, IFunctionCycleTracker functionCycleTracker) : base( @@ -50,9 +50,9 @@ internal ContainerResolutionBuilder( wellKnownTypes, referenceGeneratorFactory, rangedFunctionGroupResolutionBuilderFactory, - synchronicityDecisionMakerFactory) + synchronicityDecisionMakerFactory, + localFunctionResolutionBuilderFactory) { - _containerInfo = containerInfo; _transientScopeInterfaceResolutionBuilder = transientScopeInterfaceResolutionBuilder; _wellKnownTypes = wellKnownTypes; _createFunctionResolutionBuilderFactory = createFunctionResolutionBuilderFactory; @@ -119,6 +119,7 @@ public override void RegisterDisposalType(DisposalType disposalType) public bool HasWorkToDo => _rootResolutions.Any(r => r.CreateFunction.HasWorkToDo) || RangedInstanceReferenceResolutions.Values.Any(r => r.HasWorkToDo) + || LocalFunctions.Values.Any(r => r.HasWorkToDo) || _scopeManager.HasWorkToDo; public void DoWork() @@ -131,6 +132,7 @@ public void DoWork() } DoRangedInstancesWork(); + DoLocalFunctionsWork(); _scopeManager.DoWork(); } } @@ -147,7 +149,6 @@ public ContainerResolution Build() "private", privateFunctionResolution.Resolvable, privateFunctionResolution.Parameter, - privateFunctionResolution.LocalFunctions, privateFunctionResolution.SynchronicityDecision); rootFunctions.Add(privateRootResolutionFunction); @@ -169,7 +170,6 @@ public ContainerResolution Build() "public", call, privateRootResolutionFunction.Parameter, - Array.Empty(), SynchronicityDecision.Sync); rootFunctions.Add(publicSyncResolutionFunction); @@ -194,7 +194,6 @@ public ContainerResolution Build() wrappedTaskReference, boundTaskTypeFullName), privateRootResolutionFunction.Parameter, - Array.Empty(), SynchronicityDecision.Sync); rootFunctions.Add(publicTaskResolutionFunction); @@ -219,7 +218,6 @@ public ContainerResolution Build() wrappedValueTaskReference, boundValueTaskTypeFullName), privateRootResolutionFunction.Parameter, - Array.Empty(), SynchronicityDecision.Sync); rootFunctions.Add(publicValueTaskResolutionFunction); @@ -240,7 +238,6 @@ public ContainerResolution Build() "public", call, privateRootResolutionFunction.Parameter, - Array.Empty(), SynchronicityDecision.Sync); rootFunctions.Add(publicTaskResolutionFunction); @@ -265,7 +262,6 @@ public ContainerResolution Build() wrappedValueTaskReference, boundValueTaskTypeFullName), privateRootResolutionFunction.Parameter, - Array.Empty(), SynchronicityDecision.Sync); rootFunctions.Add(publicValueTaskResolutionFunction); @@ -294,7 +290,6 @@ public ContainerResolution Build() wrappedTaskReference, boundTaskTypeFullName), privateRootResolutionFunction.Parameter, - Array.Empty(), SynchronicityDecision.Sync); rootFunctions.Add(publicTaskResolutionFunction); @@ -311,17 +306,28 @@ public ContainerResolution Build() "public", valueCall, privateRootResolutionFunction.Parameter, - Array.Empty(), SynchronicityDecision.Sync); rootFunctions.Add(publicValueTaskResolutionFunction); } } + + var localFunctions = LocalFunctions + .Values + .Select(lf => lf.Build()) + .Select(f => new LocalFunctionResolution( + f.Reference, + f.TypeFullName, + f.Resolvable, + f.Parameter, + f.SynchronicityDecision)) + .ToList(); var (transientScopeResolutions, scopeResolutions) = _scopeManager.Build(); return new( rootFunctions, + localFunctions, BuildDisposalHandling(), RangedInstanceReferenceResolutions.Values.Select(b => b.Build()).ToList(), _transientScopeInterfaceResolutionBuilder.Build(), diff --git a/Main/ResolutionBuilding/Function/ContainerCreateFunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/ContainerCreateFunctionResolutionBuilder.cs index 896aa238..18e3192f 100644 --- a/Main/ResolutionBuilding/Function/ContainerCreateFunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/ContainerCreateFunctionResolutionBuilder.cs @@ -17,8 +17,7 @@ public ContainerCreateFunctionResolutionBuilder( // dependencies WellKnownTypes wellKnownTypes, IReferenceGeneratorFactory referenceGeneratorFactory, - IFunctionCycleTracker functionCycleTracker, - Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) + IFunctionCycleTracker functionCycleTracker) : base( rangeResolutionBaseBuilder, returnType, @@ -28,8 +27,7 @@ public ContainerCreateFunctionResolutionBuilder( wellKnownTypes, referenceGeneratorFactory, - functionCycleTracker, - localFunctionResolutionBuilderFactory) + functionCycleTracker) { _returnType = returnType; @@ -51,16 +49,6 @@ public override FunctionResolution Build() TypeFullName, Resolvable.Value, Array.Empty(), - LocalFunctions - .Select(lf => lf.Build()) - .Select(f => new LocalFunctionResolution( - f.Reference, - f.TypeFullName, - f.Resolvable, - f.Parameter, - f.LocalFunctions, - f.SynchronicityDecision)) - .ToList(), SynchronicityDecision.Value); } } \ No newline at end of file diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs index 348c1229..5a8b7c36 100644 --- a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs @@ -57,7 +57,6 @@ internal abstract partial class FunctionResolutionBuilder : IFunctionResolutionB private readonly IFunctionResolutionSynchronicityDecisionMaker _synchronicityDecisionMaker; private readonly WellKnownTypes _wellKnownTypes; private readonly IFunctionCycleTracker _functionCycleTracker; - private readonly Func, ILocalFunctionResolutionBuilder> _localFunctionResolutionBuilderFactory; private readonly ICheckTypeProperties _checkTypeProperties; protected readonly IReferenceGenerator RootReferenceGenerator; @@ -65,8 +64,6 @@ internal abstract partial class FunctionResolutionBuilder : IFunctionResolutionB private readonly IUserProvidedScopeElements _userProvidedScopeElements; private readonly FunctionResolutionBuilderHandle _handle; - - protected readonly IList LocalFunctions = new List(); protected abstract string Name { get; } protected string TypeFullName => ActualReturnType?.FullName() ?? OriginalReturnType.FullName(); @@ -91,15 +88,13 @@ internal FunctionResolutionBuilder( // dependencies WellKnownTypes wellKnownTypes, IReferenceGeneratorFactory referenceGeneratorFactory, - IFunctionCycleTracker functionCycleTracker, - Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) + IFunctionCycleTracker functionCycleTracker) { OriginalReturnType = returnType; _rangeResolutionBaseBuilder = rangeResolutionBaseBuilder; _synchronicityDecisionMaker = synchronicityDecisionMaker; _wellKnownTypes = wellKnownTypes; _functionCycleTracker = functionCycleTracker; - _localFunctionResolutionBuilderFactory = localFunctionResolutionBuilderFactory; _checkTypeProperties = rangeResolutionBaseBuilder.CheckTypeProperties; _userProvidedScopeElements = rangeResolutionBaseBuilder.UserProvidedScopeElements; _handle = new FunctionResolutionBuilderHandle( @@ -220,8 +215,9 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup null); } - var newLocalFunction = _localFunctionResolutionBuilderFactory(_rangeResolutionBaseBuilder, genericType, Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>()); - LocalFunctions.Add(newLocalFunction); + var newLocalFunction = _rangeResolutionBaseBuilder.CreateLocalFunctionResolution( + genericType, + Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>()); var constructorInjection = new LazyResolution( RootReferenceGenerator.Generate(namedTypeSymbol), @@ -249,8 +245,9 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup .Select(ts => (Type: ts, Resolution: new ParameterResolution(RootReferenceGenerator.Generate(ts), ts.FullName()))) .ToArray(); - var newLocalFunction = _localFunctionResolutionBuilderFactory(_rangeResolutionBaseBuilder, returnType, parameterTypes); - LocalFunctions.Add(newLocalFunction); + var newLocalFunction = _rangeResolutionBaseBuilder.CreateLocalFunctionResolution( + returnType, + parameterTypes); return ( new FuncResolution( @@ -883,21 +880,13 @@ public MultiSynchronicityFunctionCallResolution BuildFunctionCall( public MethodGroupResolution BuildMethodGroup() => new (Name, TypeFullName, null); - public bool HasWorkToDo => !Resolvable.IsValueCreated - || LocalFunctions.Any(lf => lf.HasWorkToDo); + public bool HasWorkToDo => !Resolvable.IsValueCreated; protected abstract Resolvable CreateResolvable(); public void DoWork() { var _ = Resolvable.Value; - while (LocalFunctions.Any(lf => lf.HasWorkToDo)) - { - foreach (var localFunction in LocalFunctions.ToList()) - { - localFunction.DoWork(); - } - } } public abstract FunctionResolution Build(); diff --git a/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs index 242375ec..73d55d87 100644 --- a/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs @@ -19,8 +19,7 @@ public LocalFunctionResolutionBuilder( // dependencies WellKnownTypes wellKnownTypes, IReferenceGeneratorFactory referenceGeneratorFactory, - IFunctionCycleTracker functionCycleTracker, - Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) + IFunctionCycleTracker functionCycleTracker) : base( rangeResolutionBaseBuilder, returnType, @@ -30,8 +29,7 @@ public LocalFunctionResolutionBuilder( wellKnownTypes, referenceGeneratorFactory, - functionCycleTracker, - localFunctionResolutionBuilderFactory) + functionCycleTracker) { _returnType = returnType; _parameters = parameters; @@ -51,16 +49,6 @@ public override FunctionResolution Build() TypeFullName, Resolvable.Value, _parameters.Select(t => t.Resolution).ToList(), - LocalFunctions - .Select(lf => lf.Build()) - .Select(f => new LocalFunctionResolution( - f.Reference, - f.TypeFullName, - f.Resolvable, - f.Parameter, - f.LocalFunctions, - f.SynchronicityDecision)) - .ToList(), SynchronicityDecision.Value); } } \ No newline at end of file diff --git a/Main/ResolutionBuilding/Function/RangedFunctionGroupResolutionBuilder.cs b/Main/ResolutionBuilding/Function/RangedFunctionGroupResolutionBuilder.cs index bb8985b6..70090c7c 100644 --- a/Main/ResolutionBuilding/Function/RangedFunctionGroupResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/RangedFunctionGroupResolutionBuilder.cs @@ -89,7 +89,6 @@ public RangedInstanceFunctionGroupResolution Build() => functionResolution.TypeFullName, functionResolution.Resolvable, functionResolution.Parameter, - functionResolution.LocalFunctions, functionResolution.SynchronicityDecision)) .ToList(), _fieldReference, diff --git a/Main/ResolutionBuilding/Function/RangedFunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/RangedFunctionResolutionBuilder.cs index 9cfc5030..2ab2cd84 100644 --- a/Main/ResolutionBuilding/Function/RangedFunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/RangedFunctionResolutionBuilder.cs @@ -19,8 +19,7 @@ public RangedFunctionResolutionBuilder( // dependencies WellKnownTypes wellKnownTypes, IReferenceGeneratorFactory referenceGeneratorFactory, - IFunctionCycleTracker functionCycleTracker, - Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) + IFunctionCycleTracker functionCycleTracker) : base( rangeResolutionBaseBuilder, forConstructorParameter.ImplementationType, @@ -30,8 +29,7 @@ public RangedFunctionResolutionBuilder( wellKnownTypes, referenceGeneratorFactory, - functionCycleTracker, - localFunctionResolutionBuilderFactory) + functionCycleTracker) { _forConstructorParameter = forConstructorParameter; @@ -52,16 +50,6 @@ public override FunctionResolution Build() TypeFullName, Resolvable.Value, _forConstructorParameter.CurrentFuncParameters.Select(t => t.Resolution).ToList(), - LocalFunctions - .Select(lf => lf.Build()) - .Select(f => new LocalFunctionResolution( - f.Reference, - f.TypeFullName, - f.Resolvable, - f.Parameter, - f.LocalFunctions, - f.SynchronicityDecision)) - .ToList(), SynchronicityDecision.Value); } } \ No newline at end of file diff --git a/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs index 5131ba98..81066c20 100644 --- a/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs @@ -17,8 +17,7 @@ public ScopeRootCreateFunctionResolutionBuilder( // dependencies WellKnownTypes wellKnownTypes, IReferenceGeneratorFactory referenceGeneratorFactory, - IFunctionCycleTracker functionCycleTracker, - Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) + IFunctionCycleTracker functionCycleTracker) : base( rangeResolutionBaseBuilder, parameter.ReturnType, @@ -28,8 +27,7 @@ public ScopeRootCreateFunctionResolutionBuilder( wellKnownTypes, referenceGeneratorFactory, - functionCycleTracker, - localFunctionResolutionBuilderFactory) + functionCycleTracker) { _parameter = parameter; @@ -50,16 +48,6 @@ public override FunctionResolution Build() TypeFullName, Resolvable.Value, Parameters, - LocalFunctions - .Select(lf => lf.Build()) - .Select(f => new LocalFunctionResolution( - f.Reference, - f.TypeFullName, - f.Resolvable, - f.Parameter, - f.LocalFunctions, - f.SynchronicityDecision)) - .ToList(), SynchronicityDecision.Value); } } \ No newline at end of file diff --git a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs index f2f59c34..5e25e4ca 100644 --- a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs +++ b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs @@ -28,6 +28,10 @@ ScopeRootResolution CreateScopeRootResolution( IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters); void RegisterDisposalType(DisposalType disposalType); + + IFunctionResolutionBuilder CreateLocalFunctionResolution( + INamedTypeSymbol type, + IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters); } internal abstract class RangeResolutionBaseBuilder : IRangeResolutionBaseBuilder @@ -35,13 +39,17 @@ internal abstract class RangeResolutionBaseBuilder : IRangeResolutionBaseBuilder public ICheckTypeProperties CheckTypeProperties { get; } public IUserProvidedScopeElements UserProvidedScopeElements { get; } - protected readonly WellKnownTypes WellKnownTypes; + private readonly WellKnownTypes _wellKnownTypes; private readonly Func _rangedFunctionGroupResolutionBuilderFactory; + private readonly Func, ILocalFunctionResolutionBuilder> _localFunctionResolutionBuilderFactory; private readonly Func _synchronicityDecisionMakerFactory; protected readonly IReferenceGenerator RootReferenceGenerator; protected readonly IDictionary RangedInstanceReferenceResolutions = new Dictionary(); + + protected readonly IDictionary LocalFunctions = new Dictionary(); + protected readonly string Name; protected RangeResolutionBaseBuilder( @@ -54,13 +62,15 @@ protected RangeResolutionBaseBuilder( WellKnownTypes wellKnownTypes, IReferenceGeneratorFactory referenceGeneratorFactory, Func rangedFunctionGroupResolutionBuilderFactory, - Func synchronicityDecisionMakerFactory) + Func synchronicityDecisionMakerFactory, + Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) { CheckTypeProperties = checkTypeProperties; UserProvidedScopeElements = userProvidedScopeElements; - WellKnownTypes = wellKnownTypes; + _wellKnownTypes = wellKnownTypes; _rangedFunctionGroupResolutionBuilderFactory = rangedFunctionGroupResolutionBuilderFactory; _synchronicityDecisionMakerFactory = synchronicityDecisionMakerFactory; + _localFunctionResolutionBuilderFactory = localFunctionResolutionBuilderFactory; RootReferenceGenerator = referenceGeneratorFactory.Create(); @@ -91,6 +101,17 @@ public abstract ScopeRootResolution CreateScopeRootResolution( IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters); public abstract void RegisterDisposalType(DisposalType disposalType); + public IFunctionResolutionBuilder CreateLocalFunctionResolution(INamedTypeSymbol type, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) + { + var key = $"{type.FullName()}:::{string.Join(":::", currentParameters.Select(p => p.Resolution.TypeFullName))}"; + if (!LocalFunctions.TryGetValue(key, out var localFunction)) + { + localFunction = _localFunctionResolutionBuilderFactory(this, type, currentParameters); + LocalFunctions[key] = localFunction; + } + + return localFunction; + } protected MultiSynchronicityFunctionCallResolution CreateRangedInstanceReferenceResolution( ForConstructorParameter parameter, @@ -130,13 +151,24 @@ protected void DoRangedInstancesWork() } } + protected void DoLocalFunctionsWork() + { + while (LocalFunctions.Values.Any(lf => lf.HasWorkToDo)) + { + foreach (var localFunction in LocalFunctions.Values.Where(lf => lf.HasWorkToDo).ToList()) + { + localFunction.DoWork(); + } + } + } + protected DisposalHandling BuildDisposalHandling() => new(new SyncDisposableCollectionResolution( - RootReferenceGenerator.Generate(WellKnownTypes.ConcurrentBagOfSyncDisposable), - WellKnownTypes.ConcurrentBagOfSyncDisposable.FullName()), + RootReferenceGenerator.Generate(_wellKnownTypes.ConcurrentBagOfSyncDisposable), + _wellKnownTypes.ConcurrentBagOfSyncDisposable.FullName()), new AsyncDisposableCollectionResolution( - RootReferenceGenerator.Generate(WellKnownTypes.ConcurrentBagOfAsyncDisposable), - WellKnownTypes.ConcurrentBagOfAsyncDisposable.FullName()), + RootReferenceGenerator.Generate(_wellKnownTypes.ConcurrentBagOfAsyncDisposable), + _wellKnownTypes.ConcurrentBagOfAsyncDisposable.FullName()), Name, RootReferenceGenerator.Generate("_disposed"), RootReferenceGenerator.Generate("disposed"), diff --git a/Main/ResolutionBuilding/ScopeManager.cs b/Main/ResolutionBuilding/ScopeManager.cs index d12c594e..e5af1bd3 100644 --- a/Main/ResolutionBuilding/ScopeManager.cs +++ b/Main/ResolutionBuilding/ScopeManager.cs @@ -17,7 +17,6 @@ internal interface IScopeManager internal class ScopeManager : IScopeManager { - private readonly IContainerInfo _containerInfo; private readonly IContainerResolutionBuilder _containerResolutionBuilder; private readonly ITransientScopeInterfaceResolutionBuilder _transientScopeInterfaceResolutionBuilder; private readonly ImmutableList _containerTypesFromAttributesList; @@ -75,7 +74,6 @@ public ScopeManager( IUserProvidedScopeElements emptyUserProvidedScopeElements, WellKnownTypesMiscellaneous wellKnownTypesMiscellaneous) { - _containerInfo = containerInfo; _containerResolutionBuilder = containerResolutionBuilder; _transientScopeInterfaceResolutionBuilder = transientScopeInterfaceResolutionBuilder; _containerTypesFromAttributesList = containerTypesFromAttributesList; @@ -87,7 +85,7 @@ public ScopeManager( _defaultScopeBuilder = new Lazy( () => { - var defaultScopeType = _containerInfo.ContainerType.GetTypeMembers(Constants.DefaultScopeName).FirstOrDefault(); + var defaultScopeType = containerInfo.ContainerType.GetTypeMembers(Constants.DefaultScopeName).FirstOrDefault(); var defaultScopeTypesFromAttributes = _scopeTypesFromAttributesFactory(defaultScopeType?.GetAttributes() ?? ImmutableArray.Empty); return _scopeResolutionBuilderFactory( Constants.DefaultScopeName, @@ -103,7 +101,7 @@ defaultScopeType is {} _defaultTransientScopeBuilder = new Lazy( () => { - var defaultTransientScopeType = _containerInfo.ContainerType.GetTypeMembers(Constants.DefaultTransientScopeName).FirstOrDefault(); + var defaultTransientScopeType = containerInfo.ContainerType.GetTypeMembers(Constants.DefaultTransientScopeName).FirstOrDefault(); var defaultTransientScopeTypesFromAttributes = _scopeTypesFromAttributesFactory(defaultTransientScopeType?.GetAttributes() ?? ImmutableArray.Empty); var ret = _transientScopeResolutionBuilderFactory( Constants.DefaultTransientScopeName, diff --git a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs index 4d4605df..ca490235 100644 --- a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs @@ -40,7 +40,8 @@ internal ScopeResolutionBuilder( IReferenceGeneratorFactory referenceGeneratorFactory, Func scopeRootCreateFunctionResolutionBuilderFactory, Func rangedFunctionGroupResolutionBuilderFactory, - Func synchronicityDecisionMakerFactory) + Func synchronicityDecisionMakerFactory, + Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) : base( name, checkTypeProperties, @@ -48,7 +49,8 @@ internal ScopeResolutionBuilder( wellKnownTypes, referenceGeneratorFactory, rangedFunctionGroupResolutionBuilderFactory, - synchronicityDecisionMakerFactory) + synchronicityDecisionMakerFactory, + localFunctionResolutionBuilderFactory) { _containerResolutionBuilder = containerResolutionBuilder; _transientScopeInterfaceResolutionBuilder = transientScopeInterfaceResolutionBuilder; @@ -95,7 +97,8 @@ public override ScopeRootResolution CreateScopeRootResolution( public bool HasWorkToDo => _scopeRootFunctionResolutions.Values.Any(f => f.HasWorkToDo) - || RangedInstanceReferenceResolutions.Values.Any(r => r.HasWorkToDo); + || RangedInstanceReferenceResolutions.Values.Any(r => r.HasWorkToDo) + || LocalFunctions.Values.Any(r => r.HasWorkToDo); public ScopeRootResolution AddCreateResolveFunction( SwitchImplementationParameter parameter, @@ -133,6 +136,7 @@ public void DoWork() } DoRangedInstancesWork(); + DoLocalFunctionsWork(); } } @@ -146,7 +150,16 @@ public ScopeResolution Build() => "internal", f.Resolvable, f.Parameter, - f.LocalFunctions, + f.SynchronicityDecision)) + .ToList(), + LocalFunctions + .Values + .Select(lf => lf.Build()) + .Select(f => new LocalFunctionResolution( + f.Reference, + f.TypeFullName, + f.Resolvable, + f.Parameter, f.SynchronicityDecision)) .ToList(), BuildDisposalHandling(), diff --git a/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs b/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs index f84d0e1e..8b804970 100644 --- a/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs @@ -37,7 +37,8 @@ internal TransientScopeResolutionBuilder( IReferenceGeneratorFactory referenceGeneratorFactory, Func scopeRootCreateFunctionResolutionBuilderFactory, Func rangedFunctionGroupResolutionBuilderFactory, - Func synchronicityDecisionMakerFactory) + Func synchronicityDecisionMakerFactory, + Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) : base( name, checkTypeProperties, @@ -45,7 +46,8 @@ internal TransientScopeResolutionBuilder( wellKnownTypes, referenceGeneratorFactory, rangedFunctionGroupResolutionBuilderFactory, - synchronicityDecisionMakerFactory) + synchronicityDecisionMakerFactory, + localFunctionResolutionBuilderFactory) { _containerResolutionBuilder = containerResolutionBuilder; _transientScopeInterfaceResolutionBuilder = transientScopeInterfaceResolutionBuilder; @@ -90,7 +92,8 @@ public override ScopeRootResolution CreateScopeRootResolution( public bool HasWorkToDo => _transientScopeRootFunctionResolutions.Values.Any(f => f.HasWorkToDo) - || RangedInstanceReferenceResolutions.Values.Any(r => r.HasWorkToDo); + || RangedInstanceReferenceResolutions.Values.Any(r => r.HasWorkToDo) + || LocalFunctions.Values.Any(r => r.HasWorkToDo); public TransientScopeRootResolution AddCreateResolveFunction( SwitchImplementationParameter parameter, @@ -126,6 +129,7 @@ public void DoWork() } DoRangedInstancesWork(); + DoLocalFunctionsWork(); } } @@ -139,7 +143,16 @@ public TransientScopeResolution Build() => "internal", f.Resolvable, f.Parameter, - f.LocalFunctions, + f.SynchronicityDecision)) + .ToList(), + LocalFunctions + .Values + .Select(lf => lf.Build()) + .Select(f => new LocalFunctionResolution( + f.Reference, + f.TypeFullName, + f.Resolvable, + f.Parameter, f.SynchronicityDecision)) .ToList(), BuildDisposalHandling(), diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index 02354926..e573437f 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -24,7 +24,6 @@ internal record FunctionResolution( string TypeFullName, Resolvable Resolvable, IReadOnlyList Parameter, - IReadOnlyList LocalFunctions, SynchronicityDecision SynchronicityDecision) : Resolvable(Reference, TypeFullName); internal record RootResolutionFunction( @@ -33,27 +32,24 @@ internal record RootResolutionFunction( string AccessModifier, Resolvable Resolvable, IReadOnlyList Parameter, - IReadOnlyList LocalFunctions, SynchronicityDecision SynchronicityDecision) - : FunctionResolution(Reference, TypeFullName, Resolvable, Parameter, LocalFunctions, SynchronicityDecision); + : FunctionResolution(Reference, TypeFullName, Resolvable, Parameter, SynchronicityDecision); internal record LocalFunctionResolution( string Reference, string TypeFullName, Resolvable Resolvable, IReadOnlyList Parameter, - IReadOnlyList LocalFunctions, SynchronicityDecision SynchronicityDecision) - : FunctionResolution(Reference, TypeFullName, Resolvable, Parameter, LocalFunctions, SynchronicityDecision); + : FunctionResolution(Reference, TypeFullName, Resolvable, Parameter, SynchronicityDecision); internal record RangedInstanceFunctionResolution( string Reference, string TypeFullName, Resolvable Resolvable, IReadOnlyList Parameter, - IReadOnlyList LocalFunctions, SynchronicityDecision SynchronicityDecision) - : FunctionResolution(Reference, TypeFullName, Resolvable, Parameter, LocalFunctions, SynchronicityDecision); + : FunctionResolution(Reference, TypeFullName, Resolvable, Parameter, SynchronicityDecision); internal record RangedInstanceFunctionGroupResolution( string TypeFullName, @@ -205,6 +201,7 @@ internal record AsyncDisposableCollectionResolution( internal abstract record RangeResolution( IReadOnlyList RootResolutions, + IReadOnlyList LocalFunctions, DisposalHandling DisposalHandling, IReadOnlyList RangedInstanceFunctionGroups, string ContainerReference) : ResolutionTreeItem; @@ -216,6 +213,7 @@ internal record TransientScopeInterfaceResolution( internal record ScopeResolution( IReadOnlyList RootResolutions, + IReadOnlyList LocalFunctions, DisposalHandling DisposalHandling, IReadOnlyList RangedInstanceFunctionGroups, string ContainerReference, @@ -223,19 +221,21 @@ internal record ScopeResolution( string TransientScopeReference, string TransientScopeParameterReference, string Name) - : RangeResolution(RootResolutions, DisposalHandling, RangedInstanceFunctionGroups, ContainerReference); + : RangeResolution(RootResolutions, LocalFunctions, DisposalHandling, RangedInstanceFunctionGroups, ContainerReference); internal record TransientScopeResolution( IReadOnlyList RootResolutions, + IReadOnlyList LocalFunctions, DisposalHandling DisposalHandling, IReadOnlyList RangedInstanceFunctionGroups, string ContainerReference, string ContainerParameterReference, string Name) - : RangeResolution(RootResolutions, DisposalHandling, RangedInstanceFunctionGroups, ContainerReference); + : RangeResolution(RootResolutions, LocalFunctions, DisposalHandling, RangedInstanceFunctionGroups, ContainerReference); internal record ContainerResolution( IReadOnlyList RootResolutions, + IReadOnlyList LocalFunctions, DisposalHandling DisposalHandling, IReadOnlyList RangedInstanceFunctionGroups, TransientScopeInterfaceResolution TransientScopeInterface, @@ -248,7 +248,7 @@ internal record ContainerResolution( NopDisposable NopDisposable, NopAsyncDisposable NopAsyncDisposable, SyncToAsyncDisposable SyncToAsyncDisposable) - : RangeResolution(RootResolutions, DisposalHandling, RangedInstanceFunctionGroups, "this"); + : RangeResolution(RootResolutions, LocalFunctions, DisposalHandling, RangedInstanceFunctionGroups, "this"); internal record NopDisposable( string ClassName, diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index a8b16232..8a64e5ef 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -67,6 +67,7 @@ IContainerResolutionBuilder ResolutionTreeFactory(IContainerInfo ci) ContainerCreateFunctionResolutionBuilderFactory, RangedFunctionGroupResolutionBuilderFactory, FunctionResolutionSynchronicityDecisionMakerFactory, + LocalFunctionResolutionBuilderFactory, new UserProvidedScopeElements(ci.ContainerType), functionCycleTracker); @@ -107,7 +108,8 @@ ITransientScopeResolutionBuilder TransientScopeResolutionBuilderFactory( referenceGeneratorFactory, ScopeRootCreateFunctionResolutionBuilderFactory, RangedFunctionGroupResolutionBuilderFactory, - FunctionResolutionSynchronicityDecisionMakerFactory); + FunctionResolutionSynchronicityDecisionMakerFactory, + LocalFunctionResolutionBuilderFactory); IScopeResolutionBuilder ScopeResolutionBuilderFactory( string name, IContainerResolutionBuilder containerBuilder, @@ -126,7 +128,8 @@ IScopeResolutionBuilder ScopeResolutionBuilderFactory( referenceGeneratorFactory, ScopeRootCreateFunctionResolutionBuilderFactory, RangedFunctionGroupResolutionBuilderFactory, - FunctionResolutionSynchronicityDecisionMakerFactory); + FunctionResolutionSynchronicityDecisionMakerFactory, + LocalFunctionResolutionBuilderFactory); ILocalFunctionResolutionBuilder LocalFunctionResolutionBuilderFactory( IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, @@ -139,8 +142,7 @@ ILocalFunctionResolutionBuilder LocalFunctionResolutionBuilderFactory( wellKnownTypes, referenceGeneratorFactory, - functionCycleTracker, - LocalFunctionResolutionBuilderFactory); + functionCycleTracker); IContainerCreateFunctionResolutionBuilder ContainerCreateFunctionResolutionBuilderFactory( IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, @@ -151,8 +153,7 @@ IContainerCreateFunctionResolutionBuilder ContainerCreateFunctionResolutionBuild wellKnownTypes, referenceGeneratorFactory, - functionCycleTracker, - LocalFunctionResolutionBuilderFactory); + functionCycleTracker); IScopeRootCreateFunctionResolutionBuilder ScopeRootCreateFunctionResolutionBuilderFactory( IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, @@ -163,8 +164,7 @@ IScopeRootCreateFunctionResolutionBuilder ScopeRootCreateFunctionResolutionBuild wellKnownTypes, referenceGeneratorFactory, - functionCycleTracker, - LocalFunctionResolutionBuilderFactory); + functionCycleTracker); IRangedFunctionResolutionBuilder RangedFunctionResolutionBuilderFactory( IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, @@ -180,8 +180,7 @@ IRangedFunctionResolutionBuilder RangedFunctionResolutionBuilderFactory( wellKnownTypes, referenceGeneratorFactory, - functionCycleTracker, - LocalFunctionResolutionBuilderFactory); + functionCycleTracker); IRangedFunctionGroupResolutionBuilder RangedFunctionGroupResolutionBuilderFactory( string label, From a8f0f359c3a5c5048e94b72e89a550837b465b01 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Tue, 31 May 2022 21:06:30 +0200 Subject: [PATCH 079/162] Always DisposeAsync --- Main/CodeBuilding/ContainerCodeBuilder.cs | 3 +- Main/CodeBuilding/RangeCodeBaseBuilder.cs | 158 ++++++++++-------- Main/CodeBuilding/ScopeCodeBuilder.cs | 3 +- .../CodeBuilding/TransientScopeCodeBuilder.cs | 3 +- Main/WellKnownTypesChoice.cs | 3 +- Main/WellKnownTypesMiscellaneous.cs | 3 +- .../Async/Awaited/AsyncScopeRootCallAsTask.cs | 2 +- .../Awaited/AsyncScopeRootCallAsValueTask.cs | 2 +- .../Awaited/AsyncScopeRootCallAwaited.cs | 2 +- .../ContainerInstanceFunctionAsTask.cs | 2 +- .../ContainerInstanceFunctionAsValueTask.cs | 2 +- .../Awaited/ScopeInstanceFunctionAsTask.cs | 2 +- .../ScopeInstanceFunctionAsValueTask.cs | 2 +- Test/Async/Awaited/TaskTypeInitializerTask.cs | 2 +- .../Awaited/TaskTypeInitializerValueTask.cs | 2 +- .../TransientScopeInstanceFunctionAsTask.cs | 2 +- ...ansientScopeInstanceFunctionAsValueTask.cs | 2 +- ...InstanceFunction_DifferentSynchronicity.cs | 2 +- .../ContainerInstanceFunctionAsTask.cs | 2 +- .../ContainerInstanceFunctionAsValueTask.cs | 2 +- Test/Async/Wrapped/DecorationChaining.cs | 2 +- Test/Async/Wrapped/Func.cs | 2 +- Test/Async/Wrapped/Lazy.cs | 3 +- .../Wrapped/ScopeInstanceFunctionAsTask.cs | 2 +- .../ScopeInstanceFunctionAsValueTask.cs | 2 +- Test/Async/Wrapped/SyncToTask.cs | 2 +- Test/Async/Wrapped/SyncToValueTask.cs | 2 +- Test/Async/Wrapped/TaskCollection.cs | 2 +- Test/Async/Wrapped/TaskComposition.cs | 2 +- Test/Async/Wrapped/TaskToTask.cs | 2 +- Test/Async/Wrapped/TaskToValueTask.cs | 2 +- .../TransientScopeInstanceFunctionAsTask.cs | 2 +- ...ceFunctionAsTask_DifferentSynchronicity.cs | 2 +- ...ansientScopeInstanceFunctionAsValueTask.cs | 2 +- ...ctionAsValueTask_DifferentSynchronicity.cs | 2 +- Test/Async/Wrapped/ValueTaskCollection.cs | 2 +- Test/Async/Wrapped/ValueTaskComposition.cs | 2 +- Test/Async/Wrapped/ValueTaskToTask.cs | 2 +- Test/Async/Wrapped/ValueTaskToValueTask.cs | 2 +- Test/Composite/Container.cs | 9 +- Test/Composite/Decorated.cs | 9 +- Test/Composite/MixedScoping.cs | 9 +- Test/Composite/Normal.cs | 9 +- Test/Composite/ScopeRoot.cs | 9 +- Test/ConstructorChoice/Parameterless.cs | 5 +- Test/ConstructorChoice/WithParameter.cs | 5 +- Test/CustomEmbedding/FactoryInContainercs.cs | 5 +- Test/CustomEmbedding/FactoryInScope.cs | 5 +- .../FactoryInTransientScope.cs | 5 +- .../FactoryWithParameterInContainercs.cs | 5 +- .../FactoryWithParameterInScope.cs | 5 +- .../FactoryWithParameterInTransientScope.cs | 5 +- Test/CustomEmbedding/FieldInContainercs.cs | 5 +- Test/CustomEmbedding/FieldInScope.cs | 5 +- Test/CustomEmbedding/FieldInTransientScope.cs | 5 +- Test/CustomEmbedding/PropertyInContainercs.cs | 5 +- Test/CustomEmbedding/PropertyInScope.cs | 5 +- .../PropertyInTransientScope.cs | 5 +- .../NoCycle/DirectRecursionContainerFunc.cs | 5 +- .../NoCycle/DirectRecursionContainerLazy.cs | 5 +- .../NoCycle/DirectRecursionScopeFunc.cs | 5 +- .../NoCycle/DirectRecursionScopeLazy.cs | 5 +- .../DirectRecursionTransientScopeFunc.cs | 5 +- .../DirectRecursionTransientScopeLazy.cs | 5 +- .../Implementation/Cycle/DirectRecursion.cs | 1 - .../NoCycle/NoCycleInParallel.cs | 6 +- Test/Decorator/ContainerInstance.cs | 5 +- Test/Decorator/List.cs | 5 +- Test/Decorator/Multi.cs | 5 +- Test/Decorator/Normal.cs | 5 +- .../ScopeDecoratorForContainerDependency.cs | 5 +- ...opeDecoratorForTransientScopeDependency.cs | 5 +- Test/Decorator/SequenceEdgeCase.cs | 7 +- Test/Disposal/Sync/InScopeInTransientScope.cs | 1 - .../Sync/InTransientScopeInTransientScope.cs | 1 - Test/Func/Double.cs | 6 +- Test/Func/Vanilla.cs | 5 +- Test/Generics/Choice/Double.cs | 7 +- Test/Generics/Choice/DoubleBothChosen.cs | 7 +- ...ubleBothChosenWithSingleOtherSubstitute.cs | 7 +- .../Choice/DoubleWithSingleOtherSubstitute.cs | 7 +- Test/Generics/Choice/Single.cs | 7 +- .../Choice/SingleWithSingleOtherSubstitute.cs | 7 +- .../Double.cs | 7 +- .../Single.cs | 7 +- Test/Generics/Configuration/Composite.cs | 5 +- .../Configuration/ConstructorChoice.cs | 5 +- .../Configuration/ContainerInstance.cs | 6 +- ...erInstanceWithDifferentGenericParameter.cs | 6 +- Test/Generics/Configuration/Decorator.cs | 5 +- .../InitializerImplementationAsync.cs | 2 +- .../InitializerImplementationAsyncValue.cs | 2 +- .../InitializerImplementationSync.cs | 5 +- .../InitializerInterfaceAsync.cs | 2 +- .../InitializerInterfaceAsyncValue.cs | 2 +- .../Configuration/InitializerInterfaceSync.cs | 5 +- .../InterfaceGenericComposite.cs | 5 +- .../InterfaceGenericDecorator.cs | 5 +- Test/Generics/Configuration/ScopeInstance.cs | 5 +- ...peInstanceWithDifferentGenericParameter.cs | 6 +- Test/Generics/Configuration/ScopeRoot.cs | 5 +- Test/Generics/Configuration/SyncTransient.cs | 5 +- .../SyncTransientWithJustTransient.cs | 5 +- .../Configuration/TransientScopeInstance.cs | 6 +- ...peInstanceWithDifferentGenericParameter.cs | 6 +- .../Configuration/TransientScopeRoot.cs | 5 +- Test/Generics/Implementation/Double.cs | 7 +- Test/Generics/Implementation/Single.cs | 7 +- Test/Generics/Interface/Double.cs | 7 +- Test/Generics/Interface/DoubleAndOneFixed.cs | 7 +- Test/Generics/Interface/DoubleAndSetToSame.cs | 7 +- Test/Generics/Interface/DoubleSwitched.cs | 7 +- Test/Generics/Interface/Single.cs | 7 +- ...eAndBaseImplementationDoubleButOneFixed.cs | 7 +- Test/Generics/SubstituteCollection/Double.cs | 5 +- .../DoubleBothSubstituted.cs | 5 +- .../DoubleBothSubstitutedWithChoice.cs | 5 +- .../SubstituteCollection/DoubleWithChoice.cs | 5 +- Test/Generics/SubstituteCollection/Single.cs | 9 +- .../SubstituteCollection/SingleWithChoice.cs | 9 +- .../SubstituteCollection/TripleInsanity.cs | 5 +- .../AssemblyImplementationsAggregation.cs | 5 +- .../Aggregation/ExternalType.cs | 5 +- .../Aggregation/FilterAllImplementations.cs | 5 +- .../Aggregation/InternalsVisibleTo.cs | 5 +- Test/Implementation/Choice/Collection.cs | 5 +- .../Choice/CollectionWithoutChoice.cs | 5 +- .../Choice/SingleInCollection.cs | 7 +- Test/Implementation/Choice/Vanilla.cs | 7 +- .../Choice/VanillaWithoutChoice.cs | 7 +- .../Choice/WithSingleInCollection.cs | 7 +- Test/InitProperty/Vanilla.cs | 5 +- Test/Lazy/Vanilla.cs | 5 +- .../NonOptional/MultipleImplementations.cs | 5 +- .../NonOptional/NoImplementation.cs | 5 +- .../Optional/MultipleImplementations.cs | 5 +- Test/Nullability/Optional/NoImplementation.cs | 5 +- Test/Record/CustomProperty.cs | 5 +- Test/Record/PrimaryConstr.cs | 5 +- Test/Record/Vanilla.cs | 5 +- Test/Scoping/InScope.cs | 5 +- .../ScopeSpecificAttributes/Decorator.cs | 21 +-- .../ScopeSpecificAttributes/Implementation.cs | 13 +- .../ImplementationCollection.cs | 13 +- .../TransientScopeInstance/InContainer.cs | 5 +- .../Scoping/TransientScopeInstance/InScope.cs | 5 +- .../TransientScopeInstance/InScopeInScope.cs | 5 +- .../InTransientScope.cs | 5 +- .../InTransientScopeWithScopes.cs | 5 +- Test/Struct/NoExplicitConstructor.cs | 5 +- Test/Struct/OneExplicitConstructor.cs | 5 +- Test/Struct/RecordNoExplicitConstructor.cs | 5 +- Test/Struct/RecordOneExplicitConstructor.cs | 5 +- Test/TypeInitializer/AsyncTask.cs | 2 +- Test/TypeInitializer/AsyncValueTask.cs | 2 +- Test/TypeInitializer/Sync.cs | 5 +- Test/ValueTuple/NonSyntaxVariant.cs | 5 +- Test/ValueTuple/NonSyntaxVariantSingleItem.cs | 5 +- Test/ValueTuple/SyntaxVariant.cs | 5 +- Test/ValueTuple/ValueTupleTests.cs | 5 +- 160 files changed, 513 insertions(+), 411 deletions(-) diff --git a/Main/CodeBuilding/ContainerCodeBuilder.cs b/Main/CodeBuilding/ContainerCodeBuilder.cs index 72ffbaa4..d3a608c4 100644 --- a/Main/CodeBuilding/ContainerCodeBuilder.cs +++ b/Main/CodeBuilding/ContainerCodeBuilder.cs @@ -58,9 +58,8 @@ public override StringBuilder Build(StringBuilder stringBuilder) { var disposableImplementation = _containerResolution.DisposalType switch { - DisposalType.Sync => $" : {WellKnownTypes.Disposable.FullName()}", DisposalType.Async => $" : {WellKnownTypes.AsyncDisposable.FullName()}", - _ => "" + _ => $" : {WellKnownTypes.AsyncDisposable.FullName()}, {WellKnownTypes.Disposable.FullName()}" }; stringBuilder = stringBuilder diff --git a/Main/CodeBuilding/RangeCodeBaseBuilder.cs b/Main/CodeBuilding/RangeCodeBaseBuilder.cs index e6d659eb..e73acf50 100644 --- a/Main/CodeBuilding/RangeCodeBaseBuilder.cs +++ b/Main/CodeBuilding/RangeCodeBaseBuilder.cs @@ -47,99 +47,109 @@ private StringBuilder GenerateDisposalFunction( StringBuilder stringBuilder, RangeResolution rangeResolution) { + if (_containerResolution.DisposalType == DisposalType.None) + { + return stringBuilder + .AppendLine("public void Dispose() {}") + .AppendLine($"public {WellKnownTypes.ValueTask.FullName()} DisposeAsync() => new {WellKnownTypes.ValueTask.FullName()}({WellKnownTypes.Task.FullName()}.CompletedTask);"); + } + + var returnType = _containerResolution.DisposalType switch + { + DisposalType.Async => $"async {WellKnownTypes.ValueTask.FullName()}", + _ => "void" + }; + + var asyncSuffix = _containerResolution.DisposalType switch + { + DisposalType.Async => "Async", + _ => "" + }; - if (_containerResolution.DisposalType != DisposalType.None) + var awaitPrefix = _containerResolution.DisposalType switch { - var returnType = _containerResolution.DisposalType switch - { - DisposalType.Async => $"async {WellKnownTypes.ValueTask.FullName()}", - _ => "void" - }; - - var asyncSuffix = _containerResolution.DisposalType switch - { - DisposalType.Async => "Async", - _ => "" - }; - - var awaitPrefix = _containerResolution.DisposalType switch - { - DisposalType.Async => "await ", - _ => "" - }; - - stringBuilder = GenerateDisposalFunction_TransientScopeDictionary(stringBuilder); + DisposalType.Async => "await ", + _ => "" + }; + + stringBuilder = GenerateDisposalFunction_TransientScopeDictionary(stringBuilder); - var disposalHandling = rangeResolution.DisposalHandling; - if (_containerResolution.DisposalType == DisposalType.Async) - { - stringBuilder = stringBuilder.AppendLine( - $"private {disposalHandling.AsyncDisposableCollection.TypeFullName} {disposalHandling.AsyncDisposableCollection.Reference} = new {disposalHandling.AsyncDisposableCollection.TypeFullName}();"); - } + var disposalHandling = rangeResolution.DisposalHandling; + if (_containerResolution.DisposalType == DisposalType.Async) + { + stringBuilder = stringBuilder.AppendLine( + $"private {disposalHandling.AsyncDisposableCollection.TypeFullName} {disposalHandling.AsyncDisposableCollection.Reference} = new {disposalHandling.AsyncDisposableCollection.TypeFullName}();"); + } - stringBuilder = stringBuilder - .AppendLine($"private {disposalHandling.SyncDisposableCollection.TypeFullName} {disposalHandling.SyncDisposableCollection.Reference} = new {disposalHandling.SyncDisposableCollection.TypeFullName}();") - .AppendLine($"private int {disposalHandling.DisposedFieldReference} = 0;") - .AppendLine($"private bool {disposalHandling.DisposedPropertyReference} => {disposalHandling.DisposedFieldReference} != 0;") - .AppendLine($"public {returnType} Dispose{asyncSuffix}()") - .AppendLine($"{{") - .AppendLine($"var {disposalHandling.DisposedLocalReference} = global::System.Threading.Interlocked.Exchange(ref this.{disposalHandling.DisposedFieldReference}, 1);") - .AppendLine($"if ({disposalHandling.DisposedLocalReference} != 0) return;"); + stringBuilder = stringBuilder + .AppendLine($"private {disposalHandling.SyncDisposableCollection.TypeFullName} {disposalHandling.SyncDisposableCollection.Reference} = new {disposalHandling.SyncDisposableCollection.TypeFullName}();") + .AppendLine($"private int {disposalHandling.DisposedFieldReference} = 0;") + .AppendLine($"private bool {disposalHandling.DisposedPropertyReference} => {disposalHandling.DisposedFieldReference} != 0;") + .AppendLine($"public {returnType} Dispose{asyncSuffix}()") + .AppendLine($"{{") + .AppendLine($"var {disposalHandling.DisposedLocalReference} = global::System.Threading.Interlocked.Exchange(ref this.{disposalHandling.DisposedFieldReference}, 1);") + .AppendLine($"if ({disposalHandling.DisposedLocalReference} != 0) return;"); - stringBuilder = rangeResolution.RangedInstanceFunctionGroups.Aggregate( - stringBuilder, - (current, containerInstanceResolution) => current.AppendLine($"{awaitPrefix}this.{containerInstanceResolution.LockReference}.Wait{asyncSuffix}();")); + stringBuilder = rangeResolution.RangedInstanceFunctionGroups.Aggregate( + stringBuilder, + (current, containerInstanceResolution) => current.AppendLine($"{awaitPrefix}this.{containerInstanceResolution.LockReference}.Wait{asyncSuffix}();")); - stringBuilder = stringBuilder - .AppendLine($"try") - .AppendLine($"{{"); + stringBuilder = stringBuilder + .AppendLine($"try") + .AppendLine($"{{"); - stringBuilder = GenerateDisposalFunction_TransientScopeDisposal(stringBuilder); + stringBuilder = GenerateDisposalFunction_TransientScopeDisposal(stringBuilder); - if (_containerResolution.DisposalType == DisposalType.Async) - { - stringBuilder = stringBuilder - .AppendLine( - $"foreach(var {disposalHandling.DisposableLocalReference} in {disposalHandling.AsyncDisposableCollection.Reference})") - .AppendLine($"{{") - .AppendLine($"try") - .AppendLine($"{{") - .AppendLine($"await {disposalHandling.DisposableLocalReference}.DisposeAsync();") - .AppendLine($"}}") - .AppendLine($"catch({WellKnownTypes.Exception.FullName()})") - .AppendLine($"{{") - .AppendLine( - $"// catch and ignore exceptions of individual disposals so the other disposals are triggered") - .AppendLine($"}}") - .AppendLine($"}}") - .AppendLine($"{disposalHandling.AsyncDisposableCollection.Reference}.Clear();"); - } - + if (_containerResolution.DisposalType == DisposalType.Async) + { stringBuilder = stringBuilder - .AppendLine($"foreach(var {disposalHandling.DisposableLocalReference} in {disposalHandling.SyncDisposableCollection.Reference})") + .AppendLine( + $"foreach(var {disposalHandling.DisposableLocalReference} in {disposalHandling.AsyncDisposableCollection.Reference})") .AppendLine($"{{") .AppendLine($"try") .AppendLine($"{{") - .AppendLine($"{disposalHandling.DisposableLocalReference}.Dispose();") + .AppendLine($"await {disposalHandling.DisposableLocalReference}.DisposeAsync();") .AppendLine($"}}") .AppendLine($"catch({WellKnownTypes.Exception.FullName()})") .AppendLine($"{{") - .AppendLine($"// catch and ignore exceptions of individual disposals so the other disposals are triggered") - .AppendLine($"}}") + .AppendLine( + $"// catch and ignore exceptions of individual disposals so the other disposals are triggered") .AppendLine($"}}") - .AppendLine($"{disposalHandling.SyncDisposableCollection.Reference}.Clear();") .AppendLine($"}}") - .AppendLine($"finally") - .AppendLine($"{{"); - - stringBuilder = rangeResolution.RangedInstanceFunctionGroups.Aggregate( - stringBuilder, - (current, containerInstanceResolution) => current.AppendLine($"this.{containerInstanceResolution.LockReference}.Release();")); + .AppendLine($"{disposalHandling.AsyncDisposableCollection.Reference}.Clear();"); + } + + stringBuilder = stringBuilder + .AppendLine($"foreach(var {disposalHandling.DisposableLocalReference} in {disposalHandling.SyncDisposableCollection.Reference})") + .AppendLine($"{{") + .AppendLine($"try") + .AppendLine($"{{") + .AppendLine($"{disposalHandling.DisposableLocalReference}.Dispose();") + .AppendLine($"}}") + .AppendLine($"catch({WellKnownTypes.Exception.FullName()})") + .AppendLine($"{{") + .AppendLine($"// catch and ignore exceptions of individual disposals so the other disposals are triggered") + .AppendLine($"}}") + .AppendLine($"}}") + .AppendLine($"{disposalHandling.SyncDisposableCollection.Reference}.Clear();") + .AppendLine($"}}") + .AppendLine($"finally") + .AppendLine($"{{"); + + stringBuilder = rangeResolution.RangedInstanceFunctionGroups.Aggregate( + stringBuilder, + (current, containerInstanceResolution) => current.AppendLine($"this.{containerInstanceResolution.LockReference}.Release();")); - return stringBuilder - .AppendLine($"}}") + stringBuilder = stringBuilder + .AppendLine($"}}") + .AppendLine($"}}"); + if (_containerResolution.DisposalType == DisposalType.Sync) + stringBuilder = stringBuilder + .AppendLine($"public {WellKnownTypes.ValueTask.FullName()} DisposeAsync()") + .AppendLine($"{{") + .AppendLine($"Dispose();") + .AppendLine($"return new {WellKnownTypes.ValueTask.FullName()}({WellKnownTypes.Task.FullName()}.CompletedTask);") .AppendLine($"}}"); - } return stringBuilder; } diff --git a/Main/CodeBuilding/ScopeCodeBuilder.cs b/Main/CodeBuilding/ScopeCodeBuilder.cs index 7b47ec53..c0f6c787 100644 --- a/Main/CodeBuilding/ScopeCodeBuilder.cs +++ b/Main/CodeBuilding/ScopeCodeBuilder.cs @@ -25,9 +25,8 @@ public override StringBuilder Build(StringBuilder stringBuilder) var disposableImplementation = _containerResolution.DisposalType switch { - DisposalType.Sync => $" : {WellKnownTypes.Disposable.FullName()}", DisposalType.Async => $" : {WellKnownTypes.AsyncDisposable.FullName()}", - _ => "" + _ => $" : {WellKnownTypes.AsyncDisposable.FullName()}, {WellKnownTypes.Disposable.FullName()}" }; stringBuilder = stringBuilder diff --git a/Main/CodeBuilding/TransientScopeCodeBuilder.cs b/Main/CodeBuilding/TransientScopeCodeBuilder.cs index 4d28bbef..2730567d 100644 --- a/Main/CodeBuilding/TransientScopeCodeBuilder.cs +++ b/Main/CodeBuilding/TransientScopeCodeBuilder.cs @@ -37,9 +37,8 @@ public override StringBuilder Build(StringBuilder stringBuilder) var disposableImplementation = _containerResolution.DisposalType switch { - DisposalType.Sync => $", {WellKnownTypes.Disposable.FullName()}", DisposalType.Async => $", {WellKnownTypes.AsyncDisposable.FullName()}", - _ => "" + _ => $", {WellKnownTypes.AsyncDisposable.FullName()}, {WellKnownTypes.Disposable.FullName()}" }; stringBuilder = stringBuilder diff --git a/Main/WellKnownTypesChoice.cs b/Main/WellKnownTypesChoice.cs index 5ccf73e6..a5c32b0f 100644 --- a/Main/WellKnownTypesChoice.cs +++ b/Main/WellKnownTypesChoice.cs @@ -1,5 +1,4 @@ -using MrMeeseeks.DIE.Configuration; -using MrMeeseeks.DIE.Configuration.Attributes; +using MrMeeseeks.DIE.Configuration.Attributes; namespace MrMeeseeks.DIE; diff --git a/Main/WellKnownTypesMiscellaneous.cs b/Main/WellKnownTypesMiscellaneous.cs index 93842204..fd46569f 100644 --- a/Main/WellKnownTypesMiscellaneous.cs +++ b/Main/WellKnownTypesMiscellaneous.cs @@ -1,5 +1,4 @@ -using MrMeeseeks.DIE.Configuration; -using MrMeeseeks.DIE.Configuration.Attributes; +using MrMeeseeks.DIE.Configuration.Attributes; namespace MrMeeseeks.DIE; diff --git a/Test/Async/Awaited/AsyncScopeRootCallAsTask.cs b/Test/Async/Awaited/AsyncScopeRootCallAsTask.cs index 1e905283..7d27a84d 100644 --- a/Test/Async/Awaited/AsyncScopeRootCallAsTask.cs +++ b/Test/Async/Awaited/AsyncScopeRootCallAsTask.cs @@ -35,7 +35,7 @@ public class Tests [Fact] public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var root = await container.Create().ConfigureAwait(false); Assert.True(root.Dep.IsInitialized); } diff --git a/Test/Async/Awaited/AsyncScopeRootCallAsValueTask.cs b/Test/Async/Awaited/AsyncScopeRootCallAsValueTask.cs index 74253960..0096a53f 100644 --- a/Test/Async/Awaited/AsyncScopeRootCallAsValueTask.cs +++ b/Test/Async/Awaited/AsyncScopeRootCallAsValueTask.cs @@ -35,7 +35,7 @@ public class Tests [Fact] public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var root = await container.Create().ConfigureAwait(false); Assert.True(root.Dep.IsInitialized); } diff --git a/Test/Async/Awaited/AsyncScopeRootCallAwaited.cs b/Test/Async/Awaited/AsyncScopeRootCallAwaited.cs index de20eb02..c01ad175 100644 --- a/Test/Async/Awaited/AsyncScopeRootCallAwaited.cs +++ b/Test/Async/Awaited/AsyncScopeRootCallAwaited.cs @@ -35,7 +35,7 @@ public class Tests [Fact] public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var root = await container.CreateValueAsync().ConfigureAwait(false); Assert.True(root.Dep.IsInitialized); } diff --git a/Test/Async/Awaited/ContainerInstanceFunctionAsTask.cs b/Test/Async/Awaited/ContainerInstanceFunctionAsTask.cs index 051ec2b8..5faf90ce 100644 --- a/Test/Async/Awaited/ContainerInstanceFunctionAsTask.cs +++ b/Test/Async/Awaited/ContainerInstanceFunctionAsTask.cs @@ -26,7 +26,7 @@ public class Tests [Fact] public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.CreateValueAsync(); Assert.True((await instance.ConfigureAwait(false)).IsInitialized); } diff --git a/Test/Async/Awaited/ContainerInstanceFunctionAsValueTask.cs b/Test/Async/Awaited/ContainerInstanceFunctionAsValueTask.cs index 2398397a..f788292b 100644 --- a/Test/Async/Awaited/ContainerInstanceFunctionAsValueTask.cs +++ b/Test/Async/Awaited/ContainerInstanceFunctionAsValueTask.cs @@ -26,7 +26,7 @@ public class Tests [Fact] public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.CreateValueAsync(); Assert.True((await instance.ConfigureAwait(false)).IsInitialized); } diff --git a/Test/Async/Awaited/ScopeInstanceFunctionAsTask.cs b/Test/Async/Awaited/ScopeInstanceFunctionAsTask.cs index 1fb5eae1..888eb2cc 100644 --- a/Test/Async/Awaited/ScopeInstanceFunctionAsTask.cs +++ b/Test/Async/Awaited/ScopeInstanceFunctionAsTask.cs @@ -26,7 +26,7 @@ public class Tests [Fact] public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.CreateValueAsync(); Assert.True((await instance.ConfigureAwait(false)).IsInitialized); } diff --git a/Test/Async/Awaited/ScopeInstanceFunctionAsValueTask.cs b/Test/Async/Awaited/ScopeInstanceFunctionAsValueTask.cs index 2dfbe5fa..b2af2bae 100644 --- a/Test/Async/Awaited/ScopeInstanceFunctionAsValueTask.cs +++ b/Test/Async/Awaited/ScopeInstanceFunctionAsValueTask.cs @@ -26,7 +26,7 @@ public class Tests [Fact] public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.CreateValueAsync(); Assert.True((await instance.ConfigureAwait(false)).IsInitialized); } diff --git a/Test/Async/Awaited/TaskTypeInitializerTask.cs b/Test/Async/Awaited/TaskTypeInitializerTask.cs index 8724eb13..b469ce98 100644 --- a/Test/Async/Awaited/TaskTypeInitializerTask.cs +++ b/Test/Async/Awaited/TaskTypeInitializerTask.cs @@ -26,7 +26,7 @@ public class Tests [Fact] public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = await container.CreateAsync().ConfigureAwait(false); Assert.True(instance.IsInitialized); } diff --git a/Test/Async/Awaited/TaskTypeInitializerValueTask.cs b/Test/Async/Awaited/TaskTypeInitializerValueTask.cs index c5f7c28c..73f06922 100644 --- a/Test/Async/Awaited/TaskTypeInitializerValueTask.cs +++ b/Test/Async/Awaited/TaskTypeInitializerValueTask.cs @@ -26,7 +26,7 @@ public class Tests [Fact] public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = await container.CreateAsync().ConfigureAwait(false); Assert.True(instance.IsInitialized); } diff --git a/Test/Async/Awaited/TransientScopeInstanceFunctionAsTask.cs b/Test/Async/Awaited/TransientScopeInstanceFunctionAsTask.cs index 2a8f07bb..3853f2c0 100644 --- a/Test/Async/Awaited/TransientScopeInstanceFunctionAsTask.cs +++ b/Test/Async/Awaited/TransientScopeInstanceFunctionAsTask.cs @@ -25,7 +25,7 @@ public class Tests [Fact] public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.CreateValueAsync(); Assert.True((await instance.ConfigureAwait(false)).IsInitialized); } diff --git a/Test/Async/Awaited/TransientScopeInstanceFunctionAsValueTask.cs b/Test/Async/Awaited/TransientScopeInstanceFunctionAsValueTask.cs index 95366f22..9af46780 100644 --- a/Test/Async/Awaited/TransientScopeInstanceFunctionAsValueTask.cs +++ b/Test/Async/Awaited/TransientScopeInstanceFunctionAsValueTask.cs @@ -25,7 +25,7 @@ public class Tests [Fact] public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.CreateValueAsync(); Assert.True((await instance.ConfigureAwait(false)).IsInitialized); } diff --git a/Test/Async/Awaited/TransientScopeInstanceFunction_DifferentSynchronicity.cs b/Test/Async/Awaited/TransientScopeInstanceFunction_DifferentSynchronicity.cs index 3b14c8e1..7f760317 100644 --- a/Test/Async/Awaited/TransientScopeInstanceFunction_DifferentSynchronicity.cs +++ b/Test/Async/Awaited/TransientScopeInstanceFunction_DifferentSynchronicity.cs @@ -74,7 +74,7 @@ public class Tests [Fact] public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance0 = container.Create0ValueAsync(); var _ = container.Create1ValueAsync(); Assert.True((((await instance0.ConfigureAwait(false)).Dependency).Inner as DependencyA)?.IsInitialized); diff --git a/Test/Async/Wrapped/ContainerInstanceFunctionAsTask.cs b/Test/Async/Wrapped/ContainerInstanceFunctionAsTask.cs index 202f11b2..ae1bb670 100644 --- a/Test/Async/Wrapped/ContainerInstanceFunctionAsTask.cs +++ b/Test/Async/Wrapped/ContainerInstanceFunctionAsTask.cs @@ -26,7 +26,7 @@ public class Tests [Fact] public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create(); Assert.True((await instance.ConfigureAwait(false)).IsInitialized); } diff --git a/Test/Async/Wrapped/ContainerInstanceFunctionAsValueTask.cs b/Test/Async/Wrapped/ContainerInstanceFunctionAsValueTask.cs index 116c143c..fee85c60 100644 --- a/Test/Async/Wrapped/ContainerInstanceFunctionAsValueTask.cs +++ b/Test/Async/Wrapped/ContainerInstanceFunctionAsValueTask.cs @@ -26,7 +26,7 @@ public class Tests [Fact] public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create(); Assert.True((await instance.ConfigureAwait(false)).IsInitialized); } diff --git a/Test/Async/Wrapped/DecorationChaining.cs b/Test/Async/Wrapped/DecorationChaining.cs index 40d7eaae..fd5a9241 100644 --- a/Test/Async/Wrapped/DecorationChaining.cs +++ b/Test/Async/Wrapped/DecorationChaining.cs @@ -58,7 +58,7 @@ public class Tests [Fact] public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = await container.Create().ConfigureAwait(false); Assert.True(instance.IsInitialized); } diff --git a/Test/Async/Wrapped/Func.cs b/Test/Async/Wrapped/Func.cs index d5f300ea..300189e7 100644 --- a/Test/Async/Wrapped/Func.cs +++ b/Test/Async/Wrapped/Func.cs @@ -27,7 +27,7 @@ public class Tests [Fact] public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create(); Assert.True((await instance().ConfigureAwait(false)).IsInitialized); } diff --git a/Test/Async/Wrapped/Lazy.cs b/Test/Async/Wrapped/Lazy.cs index 824b23d4..991dabb2 100644 --- a/Test/Async/Wrapped/Lazy.cs +++ b/Test/Async/Wrapped/Lazy.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -28,7 +27,7 @@ public class Tests [Fact] public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create(); Assert.True((await instance.Value.ConfigureAwait(false)).IsInitialized); } diff --git a/Test/Async/Wrapped/ScopeInstanceFunctionAsTask.cs b/Test/Async/Wrapped/ScopeInstanceFunctionAsTask.cs index 7edd277c..d38d2c40 100644 --- a/Test/Async/Wrapped/ScopeInstanceFunctionAsTask.cs +++ b/Test/Async/Wrapped/ScopeInstanceFunctionAsTask.cs @@ -26,7 +26,7 @@ public class Tests [Fact] public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create(); Assert.True((await instance.ConfigureAwait(false)).IsInitialized); } diff --git a/Test/Async/Wrapped/ScopeInstanceFunctionAsValueTask.cs b/Test/Async/Wrapped/ScopeInstanceFunctionAsValueTask.cs index 5602d179..3f45836c 100644 --- a/Test/Async/Wrapped/ScopeInstanceFunctionAsValueTask.cs +++ b/Test/Async/Wrapped/ScopeInstanceFunctionAsValueTask.cs @@ -26,7 +26,7 @@ public class Tests [Fact] public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create(); Assert.True((await instance.ConfigureAwait(false)).IsInitialized); } diff --git a/Test/Async/Wrapped/SyncToTask.cs b/Test/Async/Wrapped/SyncToTask.cs index 1f9a3717..63c2d239 100644 --- a/Test/Async/Wrapped/SyncToTask.cs +++ b/Test/Async/Wrapped/SyncToTask.cs @@ -24,7 +24,7 @@ public class Tests [Fact] public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = await container.Create().ConfigureAwait(false); Assert.True(instance.IsInitialized); } diff --git a/Test/Async/Wrapped/SyncToValueTask.cs b/Test/Async/Wrapped/SyncToValueTask.cs index 1148db60..3facc58a 100644 --- a/Test/Async/Wrapped/SyncToValueTask.cs +++ b/Test/Async/Wrapped/SyncToValueTask.cs @@ -24,7 +24,7 @@ public class Tests [Fact] public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = await container.Create().ConfigureAwait(false); Assert.True(instance.IsInitialized); } diff --git a/Test/Async/Wrapped/TaskCollection.cs b/Test/Async/Wrapped/TaskCollection.cs index 4ab0f251..12fa1330 100644 --- a/Test/Async/Wrapped/TaskCollection.cs +++ b/Test/Async/Wrapped/TaskCollection.cs @@ -57,7 +57,7 @@ public class Tests [Fact] public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create(); Assert.Equal(4, instance.Count); await Task.WhenAll(instance).ConfigureAwait(false); diff --git a/Test/Async/Wrapped/TaskComposition.cs b/Test/Async/Wrapped/TaskComposition.cs index ecce3c9d..57c241f5 100644 --- a/Test/Async/Wrapped/TaskComposition.cs +++ b/Test/Async/Wrapped/TaskComposition.cs @@ -76,7 +76,7 @@ public class Tests [Fact] public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = await container.Create().ConfigureAwait(false); Assert.IsType(instance); Assert.Equal(4, ((Composite) instance).Count); diff --git a/Test/Async/Wrapped/TaskToTask.cs b/Test/Async/Wrapped/TaskToTask.cs index 6ae97c79..bd62d661 100644 --- a/Test/Async/Wrapped/TaskToTask.cs +++ b/Test/Async/Wrapped/TaskToTask.cs @@ -25,7 +25,7 @@ public class Tests [Fact] public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = await container.Create().ConfigureAwait(false); Assert.True(instance.IsInitialized); } diff --git a/Test/Async/Wrapped/TaskToValueTask.cs b/Test/Async/Wrapped/TaskToValueTask.cs index a3eee09e..6d32956a 100644 --- a/Test/Async/Wrapped/TaskToValueTask.cs +++ b/Test/Async/Wrapped/TaskToValueTask.cs @@ -26,7 +26,7 @@ public class Tests [Fact] public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = await container.Create().ConfigureAwait(false); Assert.True(instance.IsInitialized); } diff --git a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask.cs b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask.cs index 10638961..70ed3921 100644 --- a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask.cs +++ b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask.cs @@ -25,7 +25,7 @@ public class Tests [Fact] public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create(); Assert.True((await instance.ConfigureAwait(false)).IsInitialized); } diff --git a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask_DifferentSynchronicity.cs b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask_DifferentSynchronicity.cs index 59acf3f7..68ee7bb0 100644 --- a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask_DifferentSynchronicity.cs +++ b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask_DifferentSynchronicity.cs @@ -74,7 +74,7 @@ public class Tests [Fact] public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance0 = container.Create0(); var _ = container.Create1(); Assert.True(((await instance0.Dependency.ConfigureAwait(false)).Inner as DependencyA)?.IsInitialized); diff --git a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask.cs b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask.cs index 80df43ab..5662020d 100644 --- a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask.cs +++ b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask.cs @@ -25,7 +25,7 @@ public class Tests [Fact] public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create(); Assert.True((await instance.ConfigureAwait(false)).IsInitialized); } diff --git a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask_DifferentSynchronicity.cs b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask_DifferentSynchronicity.cs index bef4ada1..c43cdac1 100644 --- a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask_DifferentSynchronicity.cs +++ b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask_DifferentSynchronicity.cs @@ -74,7 +74,7 @@ public class Tests [Fact] public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance0 = container.Create0(); var _ = container.Create1(); Assert.True(((await instance0.Dependency.ConfigureAwait(false)).Inner as DependencyA)?.IsInitialized); diff --git a/Test/Async/Wrapped/ValueTaskCollection.cs b/Test/Async/Wrapped/ValueTaskCollection.cs index ccd776d0..deee8b90 100644 --- a/Test/Async/Wrapped/ValueTaskCollection.cs +++ b/Test/Async/Wrapped/ValueTaskCollection.cs @@ -57,7 +57,7 @@ public class Tests [Fact] public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create(); Assert.Equal(4, instance.Count); foreach (var task in instance) diff --git a/Test/Async/Wrapped/ValueTaskComposition.cs b/Test/Async/Wrapped/ValueTaskComposition.cs index 25248bd0..52b4bac5 100644 --- a/Test/Async/Wrapped/ValueTaskComposition.cs +++ b/Test/Async/Wrapped/ValueTaskComposition.cs @@ -77,7 +77,7 @@ public class Tests [Fact] public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = await container.Create().ConfigureAwait(false); Assert.IsType(instance); Assert.Equal(4, ((Composite) instance).Count); diff --git a/Test/Async/Wrapped/ValueTaskToTask.cs b/Test/Async/Wrapped/ValueTaskToTask.cs index 99f4480e..259fd986 100644 --- a/Test/Async/Wrapped/ValueTaskToTask.cs +++ b/Test/Async/Wrapped/ValueTaskToTask.cs @@ -26,7 +26,7 @@ public class Tests [Fact] public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = await container.Create().ConfigureAwait(false); Assert.True(instance.IsInitialized); } diff --git a/Test/Async/Wrapped/ValueTaskToValueTask.cs b/Test/Async/Wrapped/ValueTaskToValueTask.cs index ebb0bb0b..79e53cf5 100644 --- a/Test/Async/Wrapped/ValueTaskToValueTask.cs +++ b/Test/Async/Wrapped/ValueTaskToValueTask.cs @@ -26,7 +26,7 @@ public class Tests [Fact] public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = await container.Create().ConfigureAwait(false); Assert.True(instance.IsInitialized); } diff --git a/Test/Composite/Container.cs b/Test/Composite/Container.cs index f6cdcc6c..517bb427 100644 --- a/Test/Composite/Container.cs +++ b/Test/Composite/Container.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -37,9 +38,9 @@ internal partial class Container public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var composite = container.CreateDep(); foreach (var compositeComposite in composite.Composites) { @@ -52,9 +53,9 @@ public void Test() } [Fact] - public void TestList() + public async ValueTask TestList() { - var container = new Container(); + await using var container = new Container(); var composites = container.CreateCollection(); foreach (var compositeComposite in composites) { diff --git a/Test/Composite/Decorated.cs b/Test/Composite/Decorated.cs index 1fa0aae8..b5c8279f 100644 --- a/Test/Composite/Decorated.cs +++ b/Test/Composite/Decorated.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -63,9 +64,9 @@ internal partial class Container public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var composite = container.CreateDep(); Assert.IsType(composite); Assert.IsType(composite.Decorated); @@ -80,9 +81,9 @@ public void Test() } [Fact] - public void TestList() + public async ValueTask TestList() { - var container = new Container(); + await using var container = new Container(); var composites = container.CreateCollection(); foreach (var compositeComposite in composites) { diff --git a/Test/Composite/MixedScoping.cs b/Test/Composite/MixedScoping.cs index 0ea35b2b..2517804f 100644 --- a/Test/Composite/MixedScoping.cs +++ b/Test/Composite/MixedScoping.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -37,9 +38,9 @@ internal partial class Container public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var composite = container.CreateDep(); foreach (var compositeComposite in composite.Composites) { @@ -52,9 +53,9 @@ public void Test() } [Fact] - public void TestList() + public async ValueTask TestList() { - var container = new Container(); + await using var container = new Container(); var composites = container.CreateCollection(); foreach (var compositeComposite in composites) { diff --git a/Test/Composite/Normal.cs b/Test/Composite/Normal.cs index 2eb5893d..673d6339 100644 --- a/Test/Composite/Normal.cs +++ b/Test/Composite/Normal.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -37,9 +38,9 @@ internal partial class Container public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var composite = container.CreateDep(); foreach (var compositeComposite in composite.Composites) { @@ -50,9 +51,9 @@ public void Test() } [Fact] - public void TestList() + public async ValueTask TestList() { - var container = new Container(); + await using var container = new Container(); var composites = container.CreateCollection(); foreach (var compositeComposite in composites) { diff --git a/Test/Composite/ScopeRoot.cs b/Test/Composite/ScopeRoot.cs index 3cae8660..95023e4c 100644 --- a/Test/Composite/ScopeRoot.cs +++ b/Test/Composite/ScopeRoot.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -52,9 +53,9 @@ internal partial class Container public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var composite = container.CreateDep(); foreach (var compositeComposite in composite.Composites) { @@ -67,9 +68,9 @@ public void Test() } [Fact] - public void TestList() + public async ValueTask TestList() { - var container = new Container(); + await using var container = new Container(); var composites = container.CreateCollection(); foreach (var compositeComposite in composites) { diff --git a/Test/ConstructorChoice/Parameterless.cs b/Test/ConstructorChoice/Parameterless.cs index 0d11e31d..1077f734 100644 --- a/Test/ConstructorChoice/Parameterless.cs +++ b/Test/ConstructorChoice/Parameterless.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -15,9 +16,9 @@ internal partial class Container public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var dateTime = container.Create(); Assert.Equal(DateTime.MinValue, dateTime); } diff --git a/Test/ConstructorChoice/WithParameter.cs b/Test/ConstructorChoice/WithParameter.cs index 1e89235e..9be2e6a5 100644 --- a/Test/ConstructorChoice/WithParameter.cs +++ b/Test/ConstructorChoice/WithParameter.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -16,9 +17,9 @@ internal partial class Container public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var fileInfo = container.Create()("C:\\Yeah.txt"); Assert.Equal("C:\\Yeah.txt", fileInfo.FullName); } diff --git a/Test/CustomEmbedding/FactoryInContainercs.cs b/Test/CustomEmbedding/FactoryInContainercs.cs index 60ed0fcf..42c62fa9 100644 --- a/Test/CustomEmbedding/FactoryInContainercs.cs +++ b/Test/CustomEmbedding/FactoryInContainercs.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -20,9 +21,9 @@ public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var wrapper = container.Create(); Assert.Equal("Yeah", wrapper.Property); } diff --git a/Test/CustomEmbedding/FactoryInScope.cs b/Test/CustomEmbedding/FactoryInScope.cs index 10ecd92a..8a1b2e8a 100644 --- a/Test/CustomEmbedding/FactoryInScope.cs +++ b/Test/CustomEmbedding/FactoryInScope.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -23,9 +24,9 @@ public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var scopeRoot = container.Create(); Assert.Equal("Yeah", scopeRoot.Property); } diff --git a/Test/CustomEmbedding/FactoryInTransientScope.cs b/Test/CustomEmbedding/FactoryInTransientScope.cs index 895765ba..a11c8dfe 100644 --- a/Test/CustomEmbedding/FactoryInTransientScope.cs +++ b/Test/CustomEmbedding/FactoryInTransientScope.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -23,9 +24,9 @@ public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var transientScopeRoot = container.Create(); Assert.Equal("Yeah", transientScopeRoot.Property); } diff --git a/Test/CustomEmbedding/FactoryWithParameterInContainercs.cs b/Test/CustomEmbedding/FactoryWithParameterInContainercs.cs index 6971de6d..ec957521 100644 --- a/Test/CustomEmbedding/FactoryWithParameterInContainercs.cs +++ b/Test/CustomEmbedding/FactoryWithParameterInContainercs.cs @@ -1,4 +1,5 @@ using System.IO; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -15,9 +16,9 @@ internal partial class Container public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var fileInfo = container.Create(); Assert.Equal("C:\\Yeah.txt", fileInfo.FullName); } diff --git a/Test/CustomEmbedding/FactoryWithParameterInScope.cs b/Test/CustomEmbedding/FactoryWithParameterInScope.cs index b26cb5d9..e074d7bd 100644 --- a/Test/CustomEmbedding/FactoryWithParameterInScope.cs +++ b/Test/CustomEmbedding/FactoryWithParameterInScope.cs @@ -1,4 +1,5 @@ using System.IO; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -24,9 +25,9 @@ partial class DIE_DefaultScope public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var scopeRoot = container.Create(); Assert.Equal("C:\\Yeah.txt", scopeRoot.Property.FullName); } diff --git a/Test/CustomEmbedding/FactoryWithParameterInTransientScope.cs b/Test/CustomEmbedding/FactoryWithParameterInTransientScope.cs index 6c895e34..c6cbfc95 100644 --- a/Test/CustomEmbedding/FactoryWithParameterInTransientScope.cs +++ b/Test/CustomEmbedding/FactoryWithParameterInTransientScope.cs @@ -1,4 +1,5 @@ using System.IO; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -24,9 +25,9 @@ partial class DIE_DefaultTransientScope public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var transientScopeRoot = container.Create(); Assert.Equal("C:\\Yeah.txt", transientScopeRoot.Property.FullName); } diff --git a/Test/CustomEmbedding/FieldInContainercs.cs b/Test/CustomEmbedding/FieldInContainercs.cs index 31434164..a462cb1b 100644 --- a/Test/CustomEmbedding/FieldInContainercs.cs +++ b/Test/CustomEmbedding/FieldInContainercs.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -20,9 +21,9 @@ public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var wrapper = container.Create(); Assert.Equal("Yeah", wrapper.Property); } diff --git a/Test/CustomEmbedding/FieldInScope.cs b/Test/CustomEmbedding/FieldInScope.cs index bcf98799..5a9226de 100644 --- a/Test/CustomEmbedding/FieldInScope.cs +++ b/Test/CustomEmbedding/FieldInScope.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -23,9 +24,9 @@ public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var scopeRoot = container.Create(); Assert.Equal("Yeah", scopeRoot.Property); } diff --git a/Test/CustomEmbedding/FieldInTransientScope.cs b/Test/CustomEmbedding/FieldInTransientScope.cs index fc1fe5c1..534dc50b 100644 --- a/Test/CustomEmbedding/FieldInTransientScope.cs +++ b/Test/CustomEmbedding/FieldInTransientScope.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -23,9 +24,9 @@ public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var transientScopeRoot = container.Create(); Assert.Equal("Yeah", transientScopeRoot.Property); } diff --git a/Test/CustomEmbedding/PropertyInContainercs.cs b/Test/CustomEmbedding/PropertyInContainercs.cs index f6566267..e3137e6e 100644 --- a/Test/CustomEmbedding/PropertyInContainercs.cs +++ b/Test/CustomEmbedding/PropertyInContainercs.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -20,9 +21,9 @@ public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var wrapper = container.Create(); Assert.Equal("Yeah", wrapper.Property); } diff --git a/Test/CustomEmbedding/PropertyInScope.cs b/Test/CustomEmbedding/PropertyInScope.cs index 2ed0e128..1ef956cc 100644 --- a/Test/CustomEmbedding/PropertyInScope.cs +++ b/Test/CustomEmbedding/PropertyInScope.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -23,9 +24,9 @@ public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var scopeRoot = container.Create(); Assert.Equal("Yeah", scopeRoot.Property); } diff --git a/Test/CustomEmbedding/PropertyInTransientScope.cs b/Test/CustomEmbedding/PropertyInTransientScope.cs index bbea6a74..dac4e611 100644 --- a/Test/CustomEmbedding/PropertyInTransientScope.cs +++ b/Test/CustomEmbedding/PropertyInTransientScope.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -23,9 +24,9 @@ public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var transientScopeRoot = container.Create(); Assert.Equal("Yeah", transientScopeRoot.Property); } diff --git a/Test/CycleDetection/Function/NoCycle/DirectRecursionContainerFunc.cs b/Test/CycleDetection/Function/NoCycle/DirectRecursionContainerFunc.cs index af9fd027..0f1301a2 100644 --- a/Test/CycleDetection/Function/NoCycle/DirectRecursionContainerFunc.cs +++ b/Test/CycleDetection/Function/NoCycle/DirectRecursionContainerFunc.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -18,9 +19,9 @@ internal partial class Container public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create(); Assert.IsType(instance); } diff --git a/Test/CycleDetection/Function/NoCycle/DirectRecursionContainerLazy.cs b/Test/CycleDetection/Function/NoCycle/DirectRecursionContainerLazy.cs index d3679f03..e57f16e5 100644 --- a/Test/CycleDetection/Function/NoCycle/DirectRecursionContainerLazy.cs +++ b/Test/CycleDetection/Function/NoCycle/DirectRecursionContainerLazy.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -18,9 +19,9 @@ internal partial class Container public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create(); Assert.IsType(instance); } diff --git a/Test/CycleDetection/Function/NoCycle/DirectRecursionScopeFunc.cs b/Test/CycleDetection/Function/NoCycle/DirectRecursionScopeFunc.cs index 31a87b01..c831d0d8 100644 --- a/Test/CycleDetection/Function/NoCycle/DirectRecursionScopeFunc.cs +++ b/Test/CycleDetection/Function/NoCycle/DirectRecursionScopeFunc.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -18,9 +19,9 @@ internal partial class Container public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create(); Assert.IsType(instance); } diff --git a/Test/CycleDetection/Function/NoCycle/DirectRecursionScopeLazy.cs b/Test/CycleDetection/Function/NoCycle/DirectRecursionScopeLazy.cs index 62be632e..18c6a66c 100644 --- a/Test/CycleDetection/Function/NoCycle/DirectRecursionScopeLazy.cs +++ b/Test/CycleDetection/Function/NoCycle/DirectRecursionScopeLazy.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -18,9 +19,9 @@ internal partial class Container public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create(); Assert.IsType(instance); } diff --git a/Test/CycleDetection/Function/NoCycle/DirectRecursionTransientScopeFunc.cs b/Test/CycleDetection/Function/NoCycle/DirectRecursionTransientScopeFunc.cs index e619c3c0..fbe9fd58 100644 --- a/Test/CycleDetection/Function/NoCycle/DirectRecursionTransientScopeFunc.cs +++ b/Test/CycleDetection/Function/NoCycle/DirectRecursionTransientScopeFunc.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -18,9 +19,9 @@ internal partial class Container public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create(); Assert.IsType(instance); } diff --git a/Test/CycleDetection/Function/NoCycle/DirectRecursionTransientScopeLazy.cs b/Test/CycleDetection/Function/NoCycle/DirectRecursionTransientScopeLazy.cs index d27f8897..8b61b2cb 100644 --- a/Test/CycleDetection/Function/NoCycle/DirectRecursionTransientScopeLazy.cs +++ b/Test/CycleDetection/Function/NoCycle/DirectRecursionTransientScopeLazy.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -18,9 +19,9 @@ internal partial class Container public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create(); Assert.IsType(instance); } diff --git a/Test/CycleDetection/Implementation/Cycle/DirectRecursion.cs b/Test/CycleDetection/Implementation/Cycle/DirectRecursion.cs index a3f2ceb6..0ee25ce7 100644 --- a/Test/CycleDetection/Implementation/Cycle/DirectRecursion.cs +++ b/Test/CycleDetection/Implementation/Cycle/DirectRecursion.cs @@ -1,4 +1,3 @@ -using MrMeeseeks.DIE; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; diff --git a/Test/CycleDetection/Implementation/NoCycle/NoCycleInParallel.cs b/Test/CycleDetection/Implementation/NoCycle/NoCycleInParallel.cs index 6be2085e..c72c8dea 100644 --- a/Test/CycleDetection/Implementation/NoCycle/NoCycleInParallel.cs +++ b/Test/CycleDetection/Implementation/NoCycle/NoCycleInParallel.cs @@ -1,4 +1,4 @@ -using MrMeeseeks.DIE; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -27,9 +27,9 @@ internal partial class Container public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var parent = container.Create(); Assert.IsType(parent); } diff --git a/Test/Decorator/ContainerInstance.cs b/Test/Decorator/ContainerInstance.cs index 6b3951b7..8d730787 100644 --- a/Test/Decorator/ContainerInstance.cs +++ b/Test/Decorator/ContainerInstance.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -30,9 +31,9 @@ internal partial class Container public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var decorated = container.Create(); Assert.NotEqual(decorated, decorated.Decorated); Assert.IsType(decorated); diff --git a/Test/Decorator/List.cs b/Test/Decorator/List.cs index f6261007..e73198eb 100644 --- a/Test/Decorator/List.cs +++ b/Test/Decorator/List.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -36,9 +37,9 @@ internal partial class Container public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var decorated = container.Create(); var decoratedOfA = decorated[0]; var decoratedOfB = decorated[1]; diff --git a/Test/Decorator/Multi.cs b/Test/Decorator/Multi.cs index 00e82253..c189887e 100644 --- a/Test/Decorator/Multi.cs +++ b/Test/Decorator/Multi.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -39,9 +40,9 @@ internal partial class Container public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var decorated = container.Create(); var decoratedB = decorated; var decoratedA = decorated.Decorated; diff --git a/Test/Decorator/Normal.cs b/Test/Decorator/Normal.cs index f143eca3..ff238e4c 100644 --- a/Test/Decorator/Normal.cs +++ b/Test/Decorator/Normal.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -30,9 +31,9 @@ internal partial class Container public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var decorated = container.Create(); Assert.NotEqual(decorated, decorated.Decorated); Assert.IsType(decorated); diff --git a/Test/Decorator/ScopeDecoratorForContainerDependency.cs b/Test/Decorator/ScopeDecoratorForContainerDependency.cs index 4e7b7656..8bd1ce83 100644 --- a/Test/Decorator/ScopeDecoratorForContainerDependency.cs +++ b/Test/Decorator/ScopeDecoratorForContainerDependency.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -40,9 +41,9 @@ internal partial class Container public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var scopeRoot0 = container.Create(); var decorator0 = scopeRoot0.Decorated; diff --git a/Test/Decorator/ScopeDecoratorForTransientScopeDependency.cs b/Test/Decorator/ScopeDecoratorForTransientScopeDependency.cs index 674b24e3..03a97318 100644 --- a/Test/Decorator/ScopeDecoratorForTransientScopeDependency.cs +++ b/Test/Decorator/ScopeDecoratorForTransientScopeDependency.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -40,9 +41,9 @@ internal partial class Container public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var scopeRoot0 = container.Create(); var decorator0 = scopeRoot0.Decorated; diff --git a/Test/Decorator/SequenceEdgeCase.cs b/Test/Decorator/SequenceEdgeCase.cs index 9df55b2e..b686748a 100644 --- a/Test/Decorator/SequenceEdgeCase.cs +++ b/Test/Decorator/SequenceEdgeCase.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -65,9 +66,9 @@ private partial class DIE_Scope_1 public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container0Then1 = new Container(); + await using var container0Then1 = new Container(); var _0Then1_0_2 = container0Then1.Create0().Decorated; var _0Then1_0_1 = _0Then1_0_2.Decorated; @@ -91,7 +92,7 @@ public void Test() Assert.Same(_0Then1_1_0, _0Then1_SanityCheck); - var container1Then0 = new Container(); + await using var container1Then0 = new Container(); var _1Then0_1_1 = container1Then0.Create1().Decorated; var _1Then0_1_0 = _1Then0_1_1.Decorated; diff --git a/Test/Disposal/Sync/InScopeInTransientScope.cs b/Test/Disposal/Sync/InScopeInTransientScope.cs index 7abb9ef4..b03f0cc6 100644 --- a/Test/Disposal/Sync/InScopeInTransientScope.cs +++ b/Test/Disposal/Sync/InScopeInTransientScope.cs @@ -1,5 +1,4 @@ using System; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; diff --git a/Test/Disposal/Sync/InTransientScopeInTransientScope.cs b/Test/Disposal/Sync/InTransientScopeInTransientScope.cs index d164cafb..0f9f2d65 100644 --- a/Test/Disposal/Sync/InTransientScopeInTransientScope.cs +++ b/Test/Disposal/Sync/InTransientScopeInTransientScope.cs @@ -1,5 +1,4 @@ using System; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; diff --git a/Test/Func/Double.cs b/Test/Func/Double.cs index 11d2b74e..76baf97c 100644 --- a/Test/Func/Double.cs +++ b/Test/Func/Double.cs @@ -1,5 +1,5 @@ using System; -using System.Collections.Generic; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -25,9 +25,9 @@ internal partial class Container public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var parent = container.Create(); Assert.IsType(parent); } diff --git a/Test/Func/Vanilla.cs b/Test/Func/Vanilla.cs index 17cb0605..11945871 100644 --- a/Test/Func/Vanilla.cs +++ b/Test/Func/Vanilla.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -15,9 +16,9 @@ internal partial class Container public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var _ = container.Create()(DateTime.Now, new List()); } } diff --git a/Test/Generics/Choice/Double.cs b/Test/Generics/Choice/Double.cs index 17b87d14..c985de7c 100644 --- a/Test/Generics/Choice/Double.cs +++ b/Test/Generics/Choice/Double.cs @@ -1,4 +1,5 @@ -using MrMeeseeks.DIE.Configuration.Attributes; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Choice.Double; @@ -14,9 +15,9 @@ internal partial class Container {} public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create(); Assert.IsType>(instance); } diff --git a/Test/Generics/Choice/DoubleBothChosen.cs b/Test/Generics/Choice/DoubleBothChosen.cs index 044e71f8..94c19e61 100644 --- a/Test/Generics/Choice/DoubleBothChosen.cs +++ b/Test/Generics/Choice/DoubleBothChosen.cs @@ -1,4 +1,5 @@ -using MrMeeseeks.DIE.Configuration.Attributes; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Choice.DoubleBothChosen; @@ -15,9 +16,9 @@ internal partial class Container {} public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create(); Assert.IsType>(instance); } diff --git a/Test/Generics/Choice/DoubleBothChosenWithSingleOtherSubstitute.cs b/Test/Generics/Choice/DoubleBothChosenWithSingleOtherSubstitute.cs index aae135cb..82578973 100644 --- a/Test/Generics/Choice/DoubleBothChosenWithSingleOtherSubstitute.cs +++ b/Test/Generics/Choice/DoubleBothChosenWithSingleOtherSubstitute.cs @@ -1,4 +1,5 @@ -using MrMeeseeks.DIE.Configuration.Attributes; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Choice.DoubleBothChosenWithSingleOtherSubstitute; @@ -17,9 +18,9 @@ internal partial class Container {} public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create(); Assert.IsType>(instance); } diff --git a/Test/Generics/Choice/DoubleWithSingleOtherSubstitute.cs b/Test/Generics/Choice/DoubleWithSingleOtherSubstitute.cs index a12100a4..344b7d7f 100644 --- a/Test/Generics/Choice/DoubleWithSingleOtherSubstitute.cs +++ b/Test/Generics/Choice/DoubleWithSingleOtherSubstitute.cs @@ -1,4 +1,5 @@ -using MrMeeseeks.DIE.Configuration.Attributes; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Choice.DoubleWithSingleOtherSubstitute; @@ -15,9 +16,9 @@ internal partial class Container {} public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create(); Assert.IsType>(instance); } diff --git a/Test/Generics/Choice/Single.cs b/Test/Generics/Choice/Single.cs index 45ca8036..618a7f2e 100644 --- a/Test/Generics/Choice/Single.cs +++ b/Test/Generics/Choice/Single.cs @@ -1,4 +1,5 @@ -using MrMeeseeks.DIE.Configuration.Attributes; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Choice.Single; @@ -14,9 +15,9 @@ internal partial class Container {} public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create(); Assert.IsType>(instance); } diff --git a/Test/Generics/Choice/SingleWithSingleOtherSubstitute.cs b/Test/Generics/Choice/SingleWithSingleOtherSubstitute.cs index d16479d5..4f518b4a 100644 --- a/Test/Generics/Choice/SingleWithSingleOtherSubstitute.cs +++ b/Test/Generics/Choice/SingleWithSingleOtherSubstitute.cs @@ -1,4 +1,5 @@ -using MrMeeseeks.DIE.Configuration.Attributes; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Choice.SingleWithSingleOtherSubstitute; @@ -15,9 +16,9 @@ internal partial class Container {} public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create(); Assert.IsType>(instance); } diff --git a/Test/Generics/ChoiceIndirectlyBySingleSubstitute/Double.cs b/Test/Generics/ChoiceIndirectlyBySingleSubstitute/Double.cs index 4d1c94c4..2be7e21c 100644 --- a/Test/Generics/ChoiceIndirectlyBySingleSubstitute/Double.cs +++ b/Test/Generics/ChoiceIndirectlyBySingleSubstitute/Double.cs @@ -1,4 +1,5 @@ -using MrMeeseeks.DIE.Configuration.Attributes; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.ChoiceIndirectlyBySingleSubstitute.Double; @@ -14,9 +15,9 @@ internal partial class Container {} public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create(); Assert.IsType>(instance); } diff --git a/Test/Generics/ChoiceIndirectlyBySingleSubstitute/Single.cs b/Test/Generics/ChoiceIndirectlyBySingleSubstitute/Single.cs index f3d74def..63e8ce9e 100644 --- a/Test/Generics/ChoiceIndirectlyBySingleSubstitute/Single.cs +++ b/Test/Generics/ChoiceIndirectlyBySingleSubstitute/Single.cs @@ -1,4 +1,5 @@ -using MrMeeseeks.DIE.Configuration.Attributes; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.ChoiceIndirectlyBySingleSubstitute.Single; @@ -14,9 +15,9 @@ internal partial class Container {} public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create(); Assert.IsType>(instance); } diff --git a/Test/Generics/Configuration/Composite.cs b/Test/Generics/Configuration/Composite.cs index 7fd9ea5c..98f606ad 100644 --- a/Test/Generics/Configuration/Composite.cs +++ b/Test/Generics/Configuration/Composite.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -38,9 +39,9 @@ internal partial class Container public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var composite = container.Create(); Assert.IsType>(composite); } diff --git a/Test/Generics/Configuration/ConstructorChoice.cs b/Test/Generics/Configuration/ConstructorChoice.cs index 91c92c2b..19e7d360 100644 --- a/Test/Generics/Configuration/ConstructorChoice.cs +++ b/Test/Generics/Configuration/ConstructorChoice.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -25,9 +26,9 @@ internal partial class Container {} public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create(); Assert.IsType(instance.Dependency); } diff --git a/Test/Generics/Configuration/ContainerInstance.cs b/Test/Generics/Configuration/ContainerInstance.cs index 77ed6b20..f35fa68c 100644 --- a/Test/Generics/Configuration/ContainerInstance.cs +++ b/Test/Generics/Configuration/ContainerInstance.cs @@ -1,4 +1,4 @@ -using System; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -12,9 +12,9 @@ internal partial class Container {} public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance0 = container.Create(); var instance1 = container.Create(); Assert.Same(instance0, instance1); diff --git a/Test/Generics/Configuration/ContainerInstanceWithDifferentGenericParameter.cs b/Test/Generics/Configuration/ContainerInstanceWithDifferentGenericParameter.cs index 32d404f1..6634cbbc 100644 --- a/Test/Generics/Configuration/ContainerInstanceWithDifferentGenericParameter.cs +++ b/Test/Generics/Configuration/ContainerInstanceWithDifferentGenericParameter.cs @@ -1,4 +1,4 @@ -using System; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -13,9 +13,9 @@ internal partial class Container {} public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance0 = container.Create(); var instance1 = container.CreateString(); Assert.NotSame(instance0, instance1); diff --git a/Test/Generics/Configuration/Decorator.cs b/Test/Generics/Configuration/Decorator.cs index 5e958fa2..c8a85395 100644 --- a/Test/Generics/Configuration/Decorator.cs +++ b/Test/Generics/Configuration/Decorator.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -43,9 +44,9 @@ internal partial class Container public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var decorator = container.Create(); Assert.IsType>(decorator); Assert.IsType>(decorator.Decorated); diff --git a/Test/Generics/Configuration/InitializerImplementationAsync.cs b/Test/Generics/Configuration/InitializerImplementationAsync.cs index ba21ddd2..d9e697bb 100644 --- a/Test/Generics/Configuration/InitializerImplementationAsync.cs +++ b/Test/Generics/Configuration/InitializerImplementationAsync.cs @@ -27,7 +27,7 @@ public class Tests [Fact] public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = await container.CreateValueAsync().ConfigureAwait(false); Assert.True(instance.IsInitialized); } diff --git a/Test/Generics/Configuration/InitializerImplementationAsyncValue.cs b/Test/Generics/Configuration/InitializerImplementationAsyncValue.cs index b991fdbf..34a55956 100644 --- a/Test/Generics/Configuration/InitializerImplementationAsyncValue.cs +++ b/Test/Generics/Configuration/InitializerImplementationAsyncValue.cs @@ -27,7 +27,7 @@ public class Tests [Fact] public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = await container.CreateValueAsync().ConfigureAwait(false); Assert.True(instance.IsInitialized); } diff --git a/Test/Generics/Configuration/InitializerImplementationSync.cs b/Test/Generics/Configuration/InitializerImplementationSync.cs index 280242a5..6efbf80e 100644 --- a/Test/Generics/Configuration/InitializerImplementationSync.cs +++ b/Test/Generics/Configuration/InitializerImplementationSync.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -23,9 +24,9 @@ internal partial class Container public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create(); Assert.True(instance.IsInitialized); } diff --git a/Test/Generics/Configuration/InitializerInterfaceAsync.cs b/Test/Generics/Configuration/InitializerInterfaceAsync.cs index 7d4d8107..b011fde5 100644 --- a/Test/Generics/Configuration/InitializerInterfaceAsync.cs +++ b/Test/Generics/Configuration/InitializerInterfaceAsync.cs @@ -26,7 +26,7 @@ public class Tests [Fact] public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = await container.CreateValueAsync().ConfigureAwait(false); Assert.True(instance.IsInitialized); } diff --git a/Test/Generics/Configuration/InitializerInterfaceAsyncValue.cs b/Test/Generics/Configuration/InitializerInterfaceAsyncValue.cs index 439e86ce..48948ae1 100644 --- a/Test/Generics/Configuration/InitializerInterfaceAsyncValue.cs +++ b/Test/Generics/Configuration/InitializerInterfaceAsyncValue.cs @@ -26,7 +26,7 @@ public class Tests [Fact] public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = await container.CreateValueAsync().ConfigureAwait(false); Assert.True(instance.IsInitialized); } diff --git a/Test/Generics/Configuration/InitializerInterfaceSync.cs b/Test/Generics/Configuration/InitializerInterfaceSync.cs index ac49c0a5..93c8f99a 100644 --- a/Test/Generics/Configuration/InitializerInterfaceSync.cs +++ b/Test/Generics/Configuration/InitializerInterfaceSync.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -22,9 +23,9 @@ internal partial class Container public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create(); Assert.True(instance.IsInitialized); } diff --git a/Test/Generics/Configuration/InterfaceGenericComposite.cs b/Test/Generics/Configuration/InterfaceGenericComposite.cs index 87bd7067..8bf041c0 100644 --- a/Test/Generics/Configuration/InterfaceGenericComposite.cs +++ b/Test/Generics/Configuration/InterfaceGenericComposite.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -38,9 +39,9 @@ internal partial class Container public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var composite = container.Create(); Assert.IsType>(composite); } diff --git a/Test/Generics/Configuration/InterfaceGenericDecorator.cs b/Test/Generics/Configuration/InterfaceGenericDecorator.cs index 8c0c9532..648676af 100644 --- a/Test/Generics/Configuration/InterfaceGenericDecorator.cs +++ b/Test/Generics/Configuration/InterfaceGenericDecorator.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -43,9 +44,9 @@ internal partial class Container public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var decorator = container.Create(); Assert.IsType>(decorator); Assert.IsType>(decorator.Decorated); diff --git a/Test/Generics/Configuration/ScopeInstance.cs b/Test/Generics/Configuration/ScopeInstance.cs index 0aa42923..39528f83 100644 --- a/Test/Generics/Configuration/ScopeInstance.cs +++ b/Test/Generics/Configuration/ScopeInstance.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -25,9 +26,9 @@ internal partial class Container {} public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var scopeRoot = container.Create(); Assert.Same(scopeRoot.Dependency0, scopeRoot.Dependency1); } diff --git a/Test/Generics/Configuration/ScopeInstanceWithDifferentGenericParameter.cs b/Test/Generics/Configuration/ScopeInstanceWithDifferentGenericParameter.cs index 9359ba94..cef87288 100644 --- a/Test/Generics/Configuration/ScopeInstanceWithDifferentGenericParameter.cs +++ b/Test/Generics/Configuration/ScopeInstanceWithDifferentGenericParameter.cs @@ -1,4 +1,4 @@ -using System; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -26,9 +26,9 @@ internal partial class Container {} public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var scopeRoot = container.Create(); Assert.NotSame(scopeRoot.Dependency0, scopeRoot.Dependency1); } diff --git a/Test/Generics/Configuration/ScopeRoot.cs b/Test/Generics/Configuration/ScopeRoot.cs index cae8e006..e035e295 100644 --- a/Test/Generics/Configuration/ScopeRoot.cs +++ b/Test/Generics/Configuration/ScopeRoot.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -32,9 +33,9 @@ internal partial class Container {} public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var root = container.Create(); Assert.NotSame(root.ScopeInstance, root.ScopeRoot.ScopeInstance); } diff --git a/Test/Generics/Configuration/SyncTransient.cs b/Test/Generics/Configuration/SyncTransient.cs index 3294cc11..8ca8d51d 100644 --- a/Test/Generics/Configuration/SyncTransient.cs +++ b/Test/Generics/Configuration/SyncTransient.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -24,9 +25,9 @@ internal partial class Container {} public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - using var container = new Container(); + await using var container = new Container(); using var instance = container.Create(); Assert.False(instance.IsDisposed); container.Dispose(); diff --git a/Test/Generics/Configuration/SyncTransientWithJustTransient.cs b/Test/Generics/Configuration/SyncTransientWithJustTransient.cs index befd2cc8..cc269045 100644 --- a/Test/Generics/Configuration/SyncTransientWithJustTransient.cs +++ b/Test/Generics/Configuration/SyncTransientWithJustTransient.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -24,9 +25,9 @@ internal partial class Container {} public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - using var container = new Container(); + await using var container = new Container(); using var instance = container.Create(); Assert.False(instance.IsDisposed); container.Dispose(); diff --git a/Test/Generics/Configuration/TransientScopeInstance.cs b/Test/Generics/Configuration/TransientScopeInstance.cs index b597dd4f..aca4d0ff 100644 --- a/Test/Generics/Configuration/TransientScopeInstance.cs +++ b/Test/Generics/Configuration/TransientScopeInstance.cs @@ -1,4 +1,4 @@ -using System; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -26,9 +26,9 @@ internal partial class Container {} public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var transientScopeRoot = container.Create(); Assert.Same(transientScopeRoot.Dependency0, transientScopeRoot.Dependency1); } diff --git a/Test/Generics/Configuration/TransientScopeInstanceWithDifferentGenericParameter.cs b/Test/Generics/Configuration/TransientScopeInstanceWithDifferentGenericParameter.cs index 844a45ae..3ef0da97 100644 --- a/Test/Generics/Configuration/TransientScopeInstanceWithDifferentGenericParameter.cs +++ b/Test/Generics/Configuration/TransientScopeInstanceWithDifferentGenericParameter.cs @@ -1,4 +1,4 @@ -using System; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -26,9 +26,9 @@ internal partial class Container {} public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var transientScopeRoot = container.Create(); Assert.NotSame(transientScopeRoot.Dependency0, transientScopeRoot.Dependency1); } diff --git a/Test/Generics/Configuration/TransientScopeRoot.cs b/Test/Generics/Configuration/TransientScopeRoot.cs index 5beea17b..49ee9dbc 100644 --- a/Test/Generics/Configuration/TransientScopeRoot.cs +++ b/Test/Generics/Configuration/TransientScopeRoot.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -32,9 +33,9 @@ internal partial class Container {} public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var root = container.Create(); Assert.NotSame(root.ScopeInstance, root.TransientScopeRoot.ScopeInstance); } diff --git a/Test/Generics/Implementation/Double.cs b/Test/Generics/Implementation/Double.cs index adbe96d4..ffd29de7 100644 --- a/Test/Generics/Implementation/Double.cs +++ b/Test/Generics/Implementation/Double.cs @@ -1,4 +1,5 @@ -using MrMeeseeks.DIE.Configuration.Attributes; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Implementation.Double; @@ -11,9 +12,9 @@ internal partial class Container {} public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create(); Assert.IsType>(instance); } diff --git a/Test/Generics/Implementation/Single.cs b/Test/Generics/Implementation/Single.cs index 9af95f0b..718d90fb 100644 --- a/Test/Generics/Implementation/Single.cs +++ b/Test/Generics/Implementation/Single.cs @@ -1,4 +1,5 @@ -using MrMeeseeks.DIE.Configuration.Attributes; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Implementation.Single; @@ -11,9 +12,9 @@ internal partial class Container {} public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create(); Assert.IsType>(instance); } diff --git a/Test/Generics/Interface/Double.cs b/Test/Generics/Interface/Double.cs index 2086ea1c..3b539a54 100644 --- a/Test/Generics/Interface/Double.cs +++ b/Test/Generics/Interface/Double.cs @@ -1,4 +1,5 @@ -using MrMeeseeks.DIE.Configuration.Attributes; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Interface.Double; @@ -13,9 +14,9 @@ internal partial class Container {} public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create(); Assert.IsType>(instance); } diff --git a/Test/Generics/Interface/DoubleAndOneFixed.cs b/Test/Generics/Interface/DoubleAndOneFixed.cs index a87a73f9..af69f76a 100644 --- a/Test/Generics/Interface/DoubleAndOneFixed.cs +++ b/Test/Generics/Interface/DoubleAndOneFixed.cs @@ -1,4 +1,5 @@ -using MrMeeseeks.DIE.Configuration.Attributes; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Interface.DoubleAndOneFixed; @@ -13,9 +14,9 @@ internal partial class Container {} public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create(); Assert.IsType>(instance); } diff --git a/Test/Generics/Interface/DoubleAndSetToSame.cs b/Test/Generics/Interface/DoubleAndSetToSame.cs index 38774160..67b6b1eb 100644 --- a/Test/Generics/Interface/DoubleAndSetToSame.cs +++ b/Test/Generics/Interface/DoubleAndSetToSame.cs @@ -1,4 +1,5 @@ -using MrMeeseeks.DIE.Configuration.Attributes; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Interface.DoubleAndSetToSame; @@ -13,9 +14,9 @@ internal partial class Container {} public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create(); Assert.IsType>(instance); } diff --git a/Test/Generics/Interface/DoubleSwitched.cs b/Test/Generics/Interface/DoubleSwitched.cs index 47aa5037..012b2006 100644 --- a/Test/Generics/Interface/DoubleSwitched.cs +++ b/Test/Generics/Interface/DoubleSwitched.cs @@ -1,4 +1,5 @@ -using MrMeeseeks.DIE.Configuration.Attributes; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Interface.DoubleSwitched; @@ -13,9 +14,9 @@ internal partial class Container {} public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create(); Assert.IsType>(instance); } diff --git a/Test/Generics/Interface/Single.cs b/Test/Generics/Interface/Single.cs index 79bf18da..79a99b88 100644 --- a/Test/Generics/Interface/Single.cs +++ b/Test/Generics/Interface/Single.cs @@ -1,4 +1,5 @@ -using MrMeeseeks.DIE.Configuration.Attributes; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Interface.Single; @@ -13,9 +14,9 @@ internal partial class Container {} public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create(); Assert.IsType>(instance); } diff --git a/Test/Generics/Interface/SingleAndBaseImplementationDoubleButOneFixed.cs b/Test/Generics/Interface/SingleAndBaseImplementationDoubleButOneFixed.cs index 2f08919e..94570425 100644 --- a/Test/Generics/Interface/SingleAndBaseImplementationDoubleButOneFixed.cs +++ b/Test/Generics/Interface/SingleAndBaseImplementationDoubleButOneFixed.cs @@ -1,4 +1,5 @@ -using MrMeeseeks.DIE.Configuration.Attributes; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Interface.SingleAndBaseImplementationDoubleButOneFixed; @@ -15,9 +16,9 @@ internal partial class Container {} public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create(); Assert.IsType>(instance); } diff --git a/Test/Generics/SubstituteCollection/Double.cs b/Test/Generics/SubstituteCollection/Double.cs index 59063804..4134178a 100644 --- a/Test/Generics/SubstituteCollection/Double.cs +++ b/Test/Generics/SubstituteCollection/Double.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -15,9 +16,9 @@ internal partial class Container {} public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var list = container.Create(); Assert.Equal(2, list.Count); Assert.Contains(list, i => i.GetType() == typeof(Class)); diff --git a/Test/Generics/SubstituteCollection/DoubleBothSubstituted.cs b/Test/Generics/SubstituteCollection/DoubleBothSubstituted.cs index 92bebeff..132cb456 100644 --- a/Test/Generics/SubstituteCollection/DoubleBothSubstituted.cs +++ b/Test/Generics/SubstituteCollection/DoubleBothSubstituted.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -16,9 +17,9 @@ internal partial class Container {} public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var list = container.Create(); Assert.Equal(4, list.Count); Assert.Contains(list, i => i.GetType() == typeof(Class)); diff --git a/Test/Generics/SubstituteCollection/DoubleBothSubstitutedWithChoice.cs b/Test/Generics/SubstituteCollection/DoubleBothSubstitutedWithChoice.cs index b9ee3e85..fe44ffd8 100644 --- a/Test/Generics/SubstituteCollection/DoubleBothSubstitutedWithChoice.cs +++ b/Test/Generics/SubstituteCollection/DoubleBothSubstitutedWithChoice.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -18,9 +19,9 @@ internal partial class Container {} public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var list = container.Create(); Assert.Equal(4, list.Count); Assert.Contains(list, i => i.GetType() == typeof(Class)); diff --git a/Test/Generics/SubstituteCollection/DoubleWithChoice.cs b/Test/Generics/SubstituteCollection/DoubleWithChoice.cs index 4932c774..d2555968 100644 --- a/Test/Generics/SubstituteCollection/DoubleWithChoice.cs +++ b/Test/Generics/SubstituteCollection/DoubleWithChoice.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -16,9 +17,9 @@ internal partial class Container {} public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var list = container.Create(); Assert.Equal(2, list.Count); Assert.Contains(list, i => i.GetType() == typeof(Class)); diff --git a/Test/Generics/SubstituteCollection/Single.cs b/Test/Generics/SubstituteCollection/Single.cs index 225955ed..93e77a24 100644 --- a/Test/Generics/SubstituteCollection/Single.cs +++ b/Test/Generics/SubstituteCollection/Single.cs @@ -1,6 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Linq; +using System.Collections.Generic; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -17,9 +16,9 @@ internal partial class Container {} public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var list = container.Create(); Assert.Equal(2, list.Count); Assert.Contains(list, i => i.GetType() == typeof(Class)); diff --git a/Test/Generics/SubstituteCollection/SingleWithChoice.cs b/Test/Generics/SubstituteCollection/SingleWithChoice.cs index f5f809f3..eeb007c2 100644 --- a/Test/Generics/SubstituteCollection/SingleWithChoice.cs +++ b/Test/Generics/SubstituteCollection/SingleWithChoice.cs @@ -1,6 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Linq; +using System.Collections.Generic; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -18,9 +17,9 @@ internal partial class Container {} public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var list = container.Create(); Assert.Equal(2, list.Count); Assert.Contains(list, i => i.GetType() == typeof(Class)); diff --git a/Test/Generics/SubstituteCollection/TripleInsanity.cs b/Test/Generics/SubstituteCollection/TripleInsanity.cs index adfc8b6e..6a1ca200 100644 --- a/Test/Generics/SubstituteCollection/TripleInsanity.cs +++ b/Test/Generics/SubstituteCollection/TripleInsanity.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -17,9 +18,9 @@ internal partial class Container {} public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var list = container.Create(); Assert.Equal(125, list.Count); } diff --git a/Test/Implementation/Aggregation/AssemblyImplementationsAggregation.cs b/Test/Implementation/Aggregation/AssemblyImplementationsAggregation.cs index b55c4992..c61a1bb8 100644 --- a/Test/Implementation/Aggregation/AssemblyImplementationsAggregation.cs +++ b/Test/Implementation/Aggregation/AssemblyImplementationsAggregation.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using MrMeeseeks.DIE.TestNotInternalsVisibleToChild.Public; using Xunit; @@ -13,9 +14,9 @@ internal partial class Container {} public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create(); Assert.IsType(instance); } diff --git a/Test/Implementation/Aggregation/ExternalType.cs b/Test/Implementation/Aggregation/ExternalType.cs index 954c7d20..02ae1ab1 100644 --- a/Test/Implementation/Aggregation/ExternalType.cs +++ b/Test/Implementation/Aggregation/ExternalType.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -17,9 +18,9 @@ internal partial class Container public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var path = @"C:\HelloWorld.txt"; var fileInfo = container.Create()(path); Assert.NotNull(fileInfo); diff --git a/Test/Implementation/Aggregation/FilterAllImplementations.cs b/Test/Implementation/Aggregation/FilterAllImplementations.cs index d1aec496..2590356a 100644 --- a/Test/Implementation/Aggregation/FilterAllImplementations.cs +++ b/Test/Implementation/Aggregation/FilterAllImplementations.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -17,9 +18,9 @@ internal partial class Container {} public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create(); Assert.IsType(instance); } diff --git a/Test/Implementation/Aggregation/InternalsVisibleTo.cs b/Test/Implementation/Aggregation/InternalsVisibleTo.cs index ba7797b1..9db9c4d9 100644 --- a/Test/Implementation/Aggregation/InternalsVisibleTo.cs +++ b/Test/Implementation/Aggregation/InternalsVisibleTo.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using MrMeeseeks.DIE.TestInternalsVisibleToChild.Internal; using Xunit; @@ -11,9 +12,9 @@ internal partial class Container {} public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create(); Assert.IsType(instance); } diff --git a/Test/Implementation/Choice/Collection.cs b/Test/Implementation/Choice/Collection.cs index d266db46..ed2bbb84 100644 --- a/Test/Implementation/Choice/Collection.cs +++ b/Test/Implementation/Choice/Collection.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -17,9 +18,9 @@ internal partial class Container {} public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instances = container.Create(); Assert.True(instances.Count == 2); Assert.True(instances[0].GetType() == typeof(SubClassA) && instances[1].GetType() == typeof(SubClassB) diff --git a/Test/Implementation/Choice/CollectionWithoutChoice.cs b/Test/Implementation/Choice/CollectionWithoutChoice.cs index 16781f93..e56c05fe 100644 --- a/Test/Implementation/Choice/CollectionWithoutChoice.cs +++ b/Test/Implementation/Choice/CollectionWithoutChoice.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -16,9 +17,9 @@ internal partial class Container {} public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instances = container.Create(); Assert.True(instances.Count == 3); } diff --git a/Test/Implementation/Choice/SingleInCollection.cs b/Test/Implementation/Choice/SingleInCollection.cs index 2d6fe5ac..866f2178 100644 --- a/Test/Implementation/Choice/SingleInCollection.cs +++ b/Test/Implementation/Choice/SingleInCollection.cs @@ -1,4 +1,5 @@ -using MrMeeseeks.DIE.Configuration.Attributes; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Implementation.Choice.SingleInCollection; @@ -14,9 +15,9 @@ internal partial class Container {} public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create(); Assert.IsType(instance); } diff --git a/Test/Implementation/Choice/Vanilla.cs b/Test/Implementation/Choice/Vanilla.cs index ee9c8156..43978482 100644 --- a/Test/Implementation/Choice/Vanilla.cs +++ b/Test/Implementation/Choice/Vanilla.cs @@ -1,4 +1,5 @@ -using MrMeeseeks.DIE.Configuration.Attributes; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Implementation.Choice.Vanilla; @@ -14,9 +15,9 @@ internal partial class Container {} public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create(); Assert.IsType(instance); } diff --git a/Test/Implementation/Choice/VanillaWithoutChoice.cs b/Test/Implementation/Choice/VanillaWithoutChoice.cs index dfc72913..a627271e 100644 --- a/Test/Implementation/Choice/VanillaWithoutChoice.cs +++ b/Test/Implementation/Choice/VanillaWithoutChoice.cs @@ -1,4 +1,5 @@ -using MrMeeseeks.DIE.Configuration.Attributes; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Implementation.Choice.VanillaWithoutChoice; @@ -13,9 +14,9 @@ internal partial class Container {} public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create(); Assert.IsType(instance); } diff --git a/Test/Implementation/Choice/WithSingleInCollection.cs b/Test/Implementation/Choice/WithSingleInCollection.cs index d97cc148..3731adde 100644 --- a/Test/Implementation/Choice/WithSingleInCollection.cs +++ b/Test/Implementation/Choice/WithSingleInCollection.cs @@ -1,4 +1,5 @@ -using MrMeeseeks.DIE.Configuration.Attributes; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Implementation.Choice.WithSingleInCollection; @@ -17,9 +18,9 @@ internal partial class Container {} public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create(); Assert.IsType(instance); } diff --git a/Test/InitProperty/Vanilla.cs b/Test/InitProperty/Vanilla.cs index e275ddd9..f397d95c 100644 --- a/Test/InitProperty/Vanilla.cs +++ b/Test/InitProperty/Vanilla.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -18,9 +19,9 @@ internal partial class Container public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var hasInitProperty = container.Create(); Assert.NotNull(hasInitProperty); Assert.NotNull(hasInitProperty.Dependency); diff --git a/Test/Lazy/Vanilla.cs b/Test/Lazy/Vanilla.cs index 83f77c36..2d61a059 100644 --- a/Test/Lazy/Vanilla.cs +++ b/Test/Lazy/Vanilla.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -14,9 +15,9 @@ internal partial class Container public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var lazy = container.Create(); var _ = lazy.Value; } diff --git a/Test/Nullability/NonOptional/MultipleImplementations.cs b/Test/Nullability/NonOptional/MultipleImplementations.cs index 0404979b..e1c54a2b 100644 --- a/Test/Nullability/NonOptional/MultipleImplementations.cs +++ b/Test/Nullability/NonOptional/MultipleImplementations.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -24,9 +25,9 @@ internal partial class Container public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var dependency = container.Create().Dependency; Assert.Null(dependency); } diff --git a/Test/Nullability/NonOptional/NoImplementation.cs b/Test/Nullability/NonOptional/NoImplementation.cs index b61a3735..6779aaf2 100644 --- a/Test/Nullability/NonOptional/NoImplementation.cs +++ b/Test/Nullability/NonOptional/NoImplementation.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -20,9 +21,9 @@ internal partial class Container public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var dependency = container.Create().Dependency; Assert.Null(dependency); } diff --git a/Test/Nullability/Optional/MultipleImplementations.cs b/Test/Nullability/Optional/MultipleImplementations.cs index 77df9a08..6ed21771 100644 --- a/Test/Nullability/Optional/MultipleImplementations.cs +++ b/Test/Nullability/Optional/MultipleImplementations.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -24,9 +25,9 @@ internal partial class Container public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var dependency = container.Create().Dependency; Assert.Null(dependency); } diff --git a/Test/Nullability/Optional/NoImplementation.cs b/Test/Nullability/Optional/NoImplementation.cs index 2ab9638e..e6f0f88e 100644 --- a/Test/Nullability/Optional/NoImplementation.cs +++ b/Test/Nullability/Optional/NoImplementation.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -20,9 +21,9 @@ internal partial class Container public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var dependency = container.Create().Dependency; Assert.Null(dependency); } diff --git a/Test/Record/CustomProperty.cs b/Test/Record/CustomProperty.cs index 2c7245ab..67f4ddfd 100644 --- a/Test/Record/CustomProperty.cs +++ b/Test/Record/CustomProperty.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -18,9 +19,9 @@ internal partial class Container{} public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create(); Assert.IsType(instance); Assert.IsType(instance.Dependency); diff --git a/Test/Record/PrimaryConstr.cs b/Test/Record/PrimaryConstr.cs index f8987bc4..c2e6f641 100644 --- a/Test/Record/PrimaryConstr.cs +++ b/Test/Record/PrimaryConstr.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -13,9 +14,9 @@ internal partial class Container{} public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create(); Assert.IsType(instance); Assert.IsType(instance.Dependency); diff --git a/Test/Record/Vanilla.cs b/Test/Record/Vanilla.cs index 2a9341a2..d260a3b3 100644 --- a/Test/Record/Vanilla.cs +++ b/Test/Record/Vanilla.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -11,9 +12,9 @@ internal partial class Container{} public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create(); Assert.IsType(instance); } diff --git a/Test/Scoping/InScope.cs b/Test/Scoping/InScope.cs index eaf2f105..48f78db3 100644 --- a/Test/Scoping/InScope.cs +++ b/Test/Scoping/InScope.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -18,8 +19,8 @@ internal partial class Container public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); } } \ No newline at end of file diff --git a/Test/Scoping/ScopeSpecificAttributes/Decorator.cs b/Test/Scoping/ScopeSpecificAttributes/Decorator.cs index bd325016..52cbe196 100644 --- a/Test/Scoping/ScopeSpecificAttributes/Decorator.cs +++ b/Test/Scoping/ScopeSpecificAttributes/Decorator.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -126,37 +127,37 @@ partial class DIE_Scope_A public class Tests { [Fact] - public void Container() + public async ValueTask Container() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create0(); Assert.Equal(69, instance.CheckNumber); } [Fact] - public void TransientScope() + public async ValueTask TransientScope() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create1(); Assert.Equal(23, instance.Dep.CheckNumber); } [Fact] - public void TransientScopeSpecific() + public async ValueTask TransientScopeSpecific() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create2(); Assert.Equal(7, instance.Dep.CheckNumber); } [Fact] - public void Scope() + public async ValueTask Scope() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create3(); Assert.Equal(3, instance.Dep.CheckNumber); } [Fact] - public void ScopeSpecific() + public async ValueTask ScopeSpecific() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create4(); Assert.Equal(13, instance.Dep.CheckNumber); } diff --git a/Test/Scoping/ScopeSpecificAttributes/Implementation.cs b/Test/Scoping/ScopeSpecificAttributes/Implementation.cs index 23a96aef..d830d0a0 100644 --- a/Test/Scoping/ScopeSpecificAttributes/Implementation.cs +++ b/Test/Scoping/ScopeSpecificAttributes/Implementation.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -50,23 +51,23 @@ public class Tests { [Fact] - public void Container() + public async ValueTask Container() { - var container = new Container(); + await using var container = new Container(); var dependency = container.Create0(); Assert.IsType(dependency); } [Fact] - public void TransientScope() + public async ValueTask TransientScope() { - var container = new Container(); + await using var container = new Container(); var dependency = container.Create1(); Assert.IsType(dependency.Dependency); } [Fact] - public void Scope() + public async ValueTask Scope() { - var container = new Container(); + await using var container = new Container(); var dependency = container.Create2(); Assert.IsType(dependency.Dependency); } diff --git a/Test/Scoping/ScopeSpecificAttributes/ImplementationCollection.cs b/Test/Scoping/ScopeSpecificAttributes/ImplementationCollection.cs index 5e50fe8b..ff32ebe1 100644 --- a/Test/Scoping/ScopeSpecificAttributes/ImplementationCollection.cs +++ b/Test/Scoping/ScopeSpecificAttributes/ImplementationCollection.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -49,9 +50,9 @@ public class Tests { [Fact] - public void Container() + public async ValueTask Container() { - var container = new Container(); + await using var container = new Container(); var dependencies = container.Create0(); Assert.Equal(3, dependencies.Count); Assert.Contains(dependencies, d => d.GetType() == typeof(DependencyContainer)); @@ -59,17 +60,17 @@ public void Container() Assert.Contains(dependencies, d => d.GetType() == typeof(DependencyScope)); } [Fact] - public void TransientScope() + public async ValueTask TransientScope() { - var container = new Container(); + await using var container = new Container(); var dependencies = container.Create1(); Assert.Equal(1, dependencies.Dependencies.Count); Assert.Contains(dependencies.Dependencies, d => d.GetType() == typeof(DependencyTransientScope)); } [Fact] - public void Scope() + public async ValueTask Scope() { - var container = new Container(); + await using var container = new Container(); var dependencies = container.Create2(); Assert.Equal(1, dependencies.Dependencies.Count); Assert.Contains(dependencies.Dependencies, d => d.GetType() == typeof(DependencyScope)); diff --git a/Test/Scoping/TransientScopeInstance/InContainer.cs b/Test/Scoping/TransientScopeInstance/InContainer.cs index 6e7dc364..fcc86faf 100644 --- a/Test/Scoping/TransientScopeInstance/InContainer.cs +++ b/Test/Scoping/TransientScopeInstance/InContainer.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -16,9 +17,9 @@ internal partial class Container public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create(); Assert.IsType(instance); } diff --git a/Test/Scoping/TransientScopeInstance/InScope.cs b/Test/Scoping/TransientScopeInstance/InScope.cs index 462ffc55..25441fd9 100644 --- a/Test/Scoping/TransientScopeInstance/InScope.cs +++ b/Test/Scoping/TransientScopeInstance/InScope.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -22,9 +23,9 @@ internal partial class Container public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var scopeRoot = container.Create(); Assert.IsType(scopeRoot.Dependency); } diff --git a/Test/Scoping/TransientScopeInstance/InScopeInScope.cs b/Test/Scoping/TransientScopeInstance/InScopeInScope.cs index 826bcd90..1bbe6053 100644 --- a/Test/Scoping/TransientScopeInstance/InScopeInScope.cs +++ b/Test/Scoping/TransientScopeInstance/InScopeInScope.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -28,9 +29,9 @@ internal partial class Container public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var scopeRoot = container.Create(); Assert.IsType(scopeRoot.InnerScope.Dependency); } diff --git a/Test/Scoping/TransientScopeInstance/InTransientScope.cs b/Test/Scoping/TransientScopeInstance/InTransientScope.cs index 9fffbc54..12d0770b 100644 --- a/Test/Scoping/TransientScopeInstance/InTransientScope.cs +++ b/Test/Scoping/TransientScopeInstance/InTransientScope.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -38,9 +39,9 @@ internal partial class Container public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - using var container = new Container(); + await using var container = new Container(); var transientScopeRoot = container.Create(); Assert.IsType(transientScopeRoot.Dependency); Assert.False(transientScopeRoot.Dependency.IsDisposed); diff --git a/Test/Scoping/TransientScopeInstance/InTransientScopeWithScopes.cs b/Test/Scoping/TransientScopeInstance/InTransientScopeWithScopes.cs index da4371d7..5a4c99d7 100644 --- a/Test/Scoping/TransientScopeInstance/InTransientScopeWithScopes.cs +++ b/Test/Scoping/TransientScopeInstance/InTransientScopeWithScopes.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -65,9 +66,9 @@ internal partial class Container public partial class Tests { [Fact] - public void TransientScopeWithScopes() + public async ValueTask TransientScopeWithScopes() { - using var container = new Container(); + await using var container = new Container(); var transientScopeRoot = container.Create(); Assert.NotEqual(transientScopeRoot.A, transientScopeRoot.B); Assert.Equal(transientScopeRoot.A.TransientScopeInstance, transientScopeRoot.B.TransientScopeInstance); diff --git a/Test/Struct/NoExplicitConstructor.cs b/Test/Struct/NoExplicitConstructor.cs index ce9c3109..fd95904f 100644 --- a/Test/Struct/NoExplicitConstructor.cs +++ b/Test/Struct/NoExplicitConstructor.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -11,9 +12,9 @@ internal partial class Container { } public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var value = container.Create(); Assert.IsType(value); } diff --git a/Test/Struct/OneExplicitConstructor.cs b/Test/Struct/OneExplicitConstructor.cs index 1df204f0..c511ef61 100644 --- a/Test/Struct/OneExplicitConstructor.cs +++ b/Test/Struct/OneExplicitConstructor.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -18,9 +19,9 @@ internal partial class Container { } public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var value = container.Create(); Assert.IsType(value); Assert.NotNull(value.Inner); diff --git a/Test/Struct/RecordNoExplicitConstructor.cs b/Test/Struct/RecordNoExplicitConstructor.cs index 5063e1a0..fb8a7d12 100644 --- a/Test/Struct/RecordNoExplicitConstructor.cs +++ b/Test/Struct/RecordNoExplicitConstructor.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -11,9 +12,9 @@ internal partial class Container { } public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var value = container.Create(); Assert.IsType(value); } diff --git a/Test/Struct/RecordOneExplicitConstructor.cs b/Test/Struct/RecordOneExplicitConstructor.cs index 5857b1c2..3e309924 100644 --- a/Test/Struct/RecordOneExplicitConstructor.cs +++ b/Test/Struct/RecordOneExplicitConstructor.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -13,9 +14,9 @@ internal partial class Container { } public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var value = container.Create(); Assert.IsType(value); Assert.NotNull(value.Inner); diff --git a/Test/TypeInitializer/AsyncTask.cs b/Test/TypeInitializer/AsyncTask.cs index 376fa518..26898fde 100644 --- a/Test/TypeInitializer/AsyncTask.cs +++ b/Test/TypeInitializer/AsyncTask.cs @@ -25,7 +25,7 @@ public class Tests [Fact] public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = await container.CreateAsync().ConfigureAwait(false); Assert.True(instance.IsInitialized); } diff --git a/Test/TypeInitializer/AsyncValueTask.cs b/Test/TypeInitializer/AsyncValueTask.cs index d5e4df4f..fd68ef84 100644 --- a/Test/TypeInitializer/AsyncValueTask.cs +++ b/Test/TypeInitializer/AsyncValueTask.cs @@ -25,7 +25,7 @@ public class Tests [Fact] public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = await container.CreateValueAsync().ConfigureAwait(false); Assert.True(instance.IsInitialized); } diff --git a/Test/TypeInitializer/Sync.cs b/Test/TypeInitializer/Sync.cs index 5f00598a..9aa6bd23 100644 --- a/Test/TypeInitializer/Sync.cs +++ b/Test/TypeInitializer/Sync.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -18,9 +19,9 @@ internal partial class Container public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var instance = container.Create(); Assert.True(instance.IsInitialized); } diff --git a/Test/ValueTuple/NonSyntaxVariant.cs b/Test/ValueTuple/NonSyntaxVariant.cs index c874d470..4a03f029 100644 --- a/Test/ValueTuple/NonSyntaxVariant.cs +++ b/Test/ValueTuple/NonSyntaxVariant.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -32,9 +33,9 @@ internal partial class Container public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var nonSyntaxValueTupleBase = container.Create(); Assert.Equal(25, nonSyntaxValueTupleBase.Dependency.Item26); } diff --git a/Test/ValueTuple/NonSyntaxVariantSingleItem.cs b/Test/ValueTuple/NonSyntaxVariantSingleItem.cs index 754fee05..77755e87 100644 --- a/Test/ValueTuple/NonSyntaxVariantSingleItem.cs +++ b/Test/ValueTuple/NonSyntaxVariantSingleItem.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -26,9 +27,9 @@ internal partial class Container public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var wrapper = container.Create(); Assert.Equal(0, wrapper.Dependency.Item1); } diff --git a/Test/ValueTuple/SyntaxVariant.cs b/Test/ValueTuple/SyntaxVariant.cs index 9d4eb84b..7cce9d35 100644 --- a/Test/ValueTuple/SyntaxVariant.cs +++ b/Test/ValueTuple/SyntaxVariant.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -33,9 +34,9 @@ internal partial class Container public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var valueTupleBase = container.Create(); Assert.Equal(25, valueTupleBase.Dependency._25); } diff --git a/Test/ValueTuple/ValueTupleTests.cs b/Test/ValueTuple/ValueTupleTests.cs index ff1b468f..0a91ca18 100644 --- a/Test/ValueTuple/ValueTupleTests.cs +++ b/Test/ValueTuple/ValueTupleTests.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -26,9 +27,9 @@ internal partial class Container public class Tests { [Fact] - public void Test() + public async ValueTask Test() { - var container = new Container(); + await using var container = new Container(); var wrapper = container.Create(); Assert.Equal(1, wrapper.Dependency.Item2); } From 90dbd346801044189a979ab85c30e064872c2b34 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Wed, 1 Jun 2022 22:44:46 +0200 Subject: [PATCH 080/162] Enabling user to add disposables for disposable handling --- Main/CodeBuilding/RangeCodeBaseBuilder.cs | 14 +++++ .../ContainerResolutionBuilder.cs | 4 +- .../RangeResolutionBaseBuilder.cs | 22 ++++++- .../ScopeResolutionBuilder.cs | 4 +- .../TransientScopeResolutionBuilder.cs | 4 +- Main/ResolutionTreeItem.cs | 43 +++++++++++--- Main/SourceGenerator.cs | 4 +- Main/UserProvidedScopeElements.cs | 41 ++++++++++++- Test/CustomEmbedding/FactoryInContainercs.cs | 2 +- Test/CustomEmbedding/FactoryInScope.cs | 2 +- .../FactoryInTransientScope.cs | 2 +- .../FactoryWithParameterInContainercs.cs | 2 +- .../FactoryWithParameterInScope.cs | 2 +- .../FactoryWithParameterInTransientScope.cs | 2 +- Test/CustomEmbedding/FieldInContainercs.cs | 2 +- Test/CustomEmbedding/FieldInScope.cs | 2 +- Test/CustomEmbedding/FieldInTransientScope.cs | 2 +- Test/CustomEmbedding/PropertyInContainercs.cs | 2 +- Test/CustomEmbedding/PropertyInScope.cs | 2 +- .../PropertyInTransientScope.cs | 2 +- .../ContainerUserDefinedAddForDisposal.cs | 41 +++++++++++++ ...ContainerUserDefinedAddForDisposalAsync.cs | 45 ++++++++++++++ .../ScopeUserDefinedAddForDisposal.cs | 54 +++++++++++++++++ .../ScopeUserDefinedAddForDisposalAsync.cs | 58 +++++++++++++++++++ ...TransientScopeUserDefinedAddForDisposal.cs | 54 +++++++++++++++++ ...ientScopeUserDefinedAddForDisposalAsync.cs | 58 +++++++++++++++++++ 26 files changed, 443 insertions(+), 27 deletions(-) create mode 100644 Test/Disposal/ContainerUserDefinedAddForDisposal.cs create mode 100644 Test/Disposal/ContainerUserDefinedAddForDisposalAsync.cs create mode 100644 Test/Disposal/ScopeUserDefinedAddForDisposal.cs create mode 100644 Test/Disposal/ScopeUserDefinedAddForDisposalAsync.cs create mode 100644 Test/Disposal/TransientScopeUserDefinedAddForDisposal.cs create mode 100644 Test/Disposal/TransientScopeUserDefinedAddForDisposalAsync.cs diff --git a/Main/CodeBuilding/RangeCodeBaseBuilder.cs b/Main/CodeBuilding/RangeCodeBaseBuilder.cs index e73acf50..865f8199 100644 --- a/Main/CodeBuilding/RangeCodeBaseBuilder.cs +++ b/Main/CodeBuilding/RangeCodeBaseBuilder.cs @@ -33,6 +33,20 @@ protected StringBuilder GenerateResolutionRange( stringBuilder = rangeResolution.RootResolutions.Aggregate(stringBuilder, GenerateResolutionFunction); stringBuilder = rangeResolution.LocalFunctions.Aggregate(stringBuilder, GenerateResolutionFunction); + + if (_rangeResolution.AddForDisposal is { } addForDisposalMethod) + { + stringBuilder = stringBuilder + .AppendLine($"private partial void {addForDisposalMethod.Name}({WellKnownTypes.Disposable.FullName()} disposable) =>") + .AppendLine($"{_rangeResolution.DisposalHandling.SyncDisposableCollection.Reference}.Add(({WellKnownTypes.Disposable.FullName()}) disposable);"); + } + + if (_rangeResolution.AddForDisposalAsync is { } addForDisposalAsyncMethod) + { + stringBuilder = stringBuilder + .AppendLine($"private partial void {addForDisposalAsyncMethod.Name}({WellKnownTypes.AsyncDisposable.FullName()} asyncDisposable) =>") + .AppendLine($"{_rangeResolution.DisposalHandling.AsyncDisposableCollection.Reference}.Add(({WellKnownTypes.AsyncDisposable.FullName()}) asyncDisposable);"); + } return GenerateDisposalFunction( stringBuilder, diff --git a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs index 244d7f92..8c4dd2c1 100644 --- a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs @@ -346,7 +346,9 @@ public ContainerResolution Build() new SyncToAsyncDisposable( RootReferenceGenerator.Generate("NopDisposable"), RootReferenceGenerator.Generate("disposable"), - RootReferenceGenerator.Generate("_disposable"))); + RootReferenceGenerator.Generate("_disposable")), + AddForDisposal, + AddForDisposalAsync); } public MultiSynchronicityFunctionCallResolution EnqueueRangedInstanceResolution( diff --git a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs index 5e25e4ca..69b9089e 100644 --- a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs +++ b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs @@ -38,6 +38,9 @@ internal abstract class RangeResolutionBaseBuilder : IRangeResolutionBaseBuilder { public ICheckTypeProperties CheckTypeProperties { get; } public IUserProvidedScopeElements UserProvidedScopeElements { get; } + + protected IMethodSymbol? AddForDisposal { get; } + protected IMethodSymbol? AddForDisposalAsync { get; } private readonly WellKnownTypes _wellKnownTypes; private readonly Func _rangedFunctionGroupResolutionBuilderFactory; @@ -75,6 +78,9 @@ protected RangeResolutionBaseBuilder( RootReferenceGenerator = referenceGeneratorFactory.Create(); Name = name; + + AddForDisposal = userProvidedScopeElements.AddForDisposal; + AddForDisposalAsync = userProvidedScopeElements.AddForDisposalAsync; } public abstract MultiSynchronicityFunctionCallResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter); @@ -162,8 +168,19 @@ protected void DoLocalFunctionsWork() } } - protected DisposalHandling BuildDisposalHandling() => - new(new SyncDisposableCollectionResolution( + protected DisposalHandling BuildDisposalHandling() + { + if (AddForDisposal is { }) + { + RegisterDisposalType(DisposalType.Sync); + } + + if (AddForDisposalAsync is { }) + { + RegisterDisposalType(DisposalType.Async); + } + + return new(new SyncDisposableCollectionResolution( RootReferenceGenerator.Generate(_wellKnownTypes.ConcurrentBagOfSyncDisposable), _wellKnownTypes.ConcurrentBagOfSyncDisposable.FullName()), new AsyncDisposableCollectionResolution( @@ -174,4 +191,5 @@ protected DisposalHandling BuildDisposalHandling() => RootReferenceGenerator.Generate("disposed"), RootReferenceGenerator.Generate("Disposed"), RootReferenceGenerator.Generate("disposable")); + } } \ No newline at end of file diff --git a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs index ca490235..b38fff23 100644 --- a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs @@ -168,5 +168,7 @@ public ScopeResolution Build() => _containerParameterReference, _transientScopeReference, _transientScopeParameterReference, - Name); + Name, + AddForDisposal, + AddForDisposalAsync); } \ No newline at end of file diff --git a/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs b/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs index 8b804970..dc81e703 100644 --- a/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs @@ -159,7 +159,9 @@ public TransientScopeResolution Build() => RangedInstanceReferenceResolutions.Values.Select(b => b.Build()).ToList(), _containerReference, _containerParameterReference, - Name); + Name, + AddForDisposal, + AddForDisposalAsync); public MultiSynchronicityFunctionCallResolution EnqueueRangedInstanceResolution( ForConstructorParameter parameter, diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index e573437f..40a23b7d 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -204,7 +204,9 @@ internal abstract record RangeResolution( IReadOnlyList LocalFunctions, DisposalHandling DisposalHandling, IReadOnlyList RangedInstanceFunctionGroups, - string ContainerReference) : ResolutionTreeItem; + string ContainerReference, + IMethodSymbol? AddForDisposal, + IMethodSymbol? AddForDisposalAsync) : ResolutionTreeItem; internal record TransientScopeInterfaceResolution( IReadOnlyList Functions, @@ -220,8 +222,17 @@ internal record ScopeResolution( string ContainerParameterReference, string TransientScopeReference, string TransientScopeParameterReference, - string Name) - : RangeResolution(RootResolutions, LocalFunctions, DisposalHandling, RangedInstanceFunctionGroups, ContainerReference); + string Name, + IMethodSymbol? AddForDisposal, + IMethodSymbol? AddForDisposalAsync) + : RangeResolution( + RootResolutions, + LocalFunctions, + DisposalHandling, + RangedInstanceFunctionGroups, + ContainerReference, + AddForDisposal, + AddForDisposalAsync); internal record TransientScopeResolution( IReadOnlyList RootResolutions, @@ -230,8 +241,17 @@ internal record TransientScopeResolution( IReadOnlyList RangedInstanceFunctionGroups, string ContainerReference, string ContainerParameterReference, - string Name) - : RangeResolution(RootResolutions, LocalFunctions, DisposalHandling, RangedInstanceFunctionGroups, ContainerReference); + string Name, + IMethodSymbol? AddForDisposal, + IMethodSymbol? AddForDisposalAsync) + : RangeResolution( + RootResolutions, + LocalFunctions, + DisposalHandling, + RangedInstanceFunctionGroups, + ContainerReference, + AddForDisposal, + AddForDisposalAsync); internal record ContainerResolution( IReadOnlyList RootResolutions, @@ -247,8 +267,17 @@ internal record ContainerResolution( string TransientScopeDisposalElement, NopDisposable NopDisposable, NopAsyncDisposable NopAsyncDisposable, - SyncToAsyncDisposable SyncToAsyncDisposable) - : RangeResolution(RootResolutions, LocalFunctions, DisposalHandling, RangedInstanceFunctionGroups, "this"); + SyncToAsyncDisposable SyncToAsyncDisposable, + IMethodSymbol? AddForDisposal, + IMethodSymbol? AddForDisposalAsync) + : RangeResolution( + RootResolutions, + LocalFunctions, + DisposalHandling, + RangedInstanceFunctionGroups, + "this", + AddForDisposal, + AddForDisposalAsync); internal record NopDisposable( string ClassName, diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index 8a64e5ef..2e709c05 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -68,7 +68,7 @@ IContainerResolutionBuilder ResolutionTreeFactory(IContainerInfo ci) RangedFunctionGroupResolutionBuilderFactory, FunctionResolutionSynchronicityDecisionMakerFactory, LocalFunctionResolutionBuilderFactory, - new UserProvidedScopeElements(ci.ContainerType), + new UserProvidedScopeElements(ci.ContainerType, wellKnownTypes), functionCycleTracker); IScopeManager ScopeManagerFactory( @@ -86,7 +86,7 @@ IScopeManager ScopeManagerFactory( wellKnownTypesChoice, wellKnownTypesMiscellaneous), tfa => new CheckTypeProperties(new CurrentlyConsideredTypes(tfa, implementationTypeSetCache), wellKnownTypes), - st => new UserProvidedScopeElements(st), + st => new UserProvidedScopeElements(st, wellKnownTypes), new EmptyUserProvidedScopeElements(), wellKnownTypesMiscellaneous); diff --git a/Main/UserProvidedScopeElements.cs b/Main/UserProvidedScopeElements.cs index 1f9bddff..1ad85a17 100644 --- a/Main/UserProvidedScopeElements.cs +++ b/Main/UserProvidedScopeElements.cs @@ -5,6 +5,8 @@ internal interface IUserProvidedScopeElements IFieldSymbol? GetInstanceFor(ITypeSymbol typeSymbol); IPropertySymbol? GetPropertyFor(ITypeSymbol typeSymbol); IMethodSymbol? GetFactoryFor(ITypeSymbol typeSymbol); + IMethodSymbol? AddForDisposal { get; } + IMethodSymbol? AddForDisposalAsync { get; } } internal class EmptyUserProvidedScopeElements : IUserProvidedScopeElements @@ -12,6 +14,8 @@ internal class EmptyUserProvidedScopeElements : IUserProvidedScopeElements public IFieldSymbol? GetInstanceFor(ITypeSymbol typeSymbol) => null; public IPropertySymbol? GetPropertyFor(ITypeSymbol typeSymbol) => null; public IMethodSymbol? GetFactoryFor(ITypeSymbol typeSymbol) => null; + public IMethodSymbol? AddForDisposal => null; + public IMethodSymbol? AddForDisposalAsync => null; } internal class UserProvidedScopeElements : IUserProvidedScopeElements @@ -20,7 +24,12 @@ internal class UserProvidedScopeElements : IUserProvidedScopeElements private readonly IReadOnlyDictionary _typeToProperty; private readonly IReadOnlyDictionary _typeToMethod; - public UserProvidedScopeElements(INamedTypeSymbol scopeType) + public UserProvidedScopeElements( + // parameter + INamedTypeSymbol scopeType, + + // dependencies + WellKnownTypes wellKnownTypes) { var dieMembers = scopeType.GetMembers() .Where(s => s.Name.StartsWith("DIE_")) @@ -29,17 +38,44 @@ public UserProvidedScopeElements(INamedTypeSymbol scopeType) _typeToField = dieMembers .Where(s => s is IFieldSymbol) .OfType() + .Where(f => f.Name.StartsWith("DIE_Factory_")) .ToDictionary(fs => fs.Type, fs => fs, SymbolEqualityComparer.IncludeNullability); _typeToProperty = dieMembers .Where(s => s is IPropertySymbol { GetMethod: { } }) .OfType() + .Where(f => f.Name.StartsWith("DIE_Factory_")) .ToDictionary(ps => ps.Type, ps => ps, SymbolEqualityComparer.IncludeNullability); _typeToMethod = dieMembers .Where(s => s is IMethodSymbol { ReturnsVoid: false, Arity: 0, IsConditional: false, MethodKind: MethodKind.Ordinary }) .OfType() + .Where(f => f.Name.StartsWith("DIE_Factory_")) .ToDictionary(ps => ps.ReturnType, ps => ps, SymbolEqualityComparer.IncludeNullability); + + AddForDisposal = dieMembers + .Where(s => s is IMethodSymbol + { + DeclaredAccessibility: Accessibility.Private, + ReturnsVoid: true, + IsPartialDefinition: true, + Name: "DIE_AddForDisposal", + Parameters.Length: 1 + } method && SymbolEqualityComparer.Default.Equals(method.Parameters[0].Type, wellKnownTypes.Disposable)) + .OfType() + .FirstOrDefault(); + + AddForDisposalAsync = dieMembers + .Where(s => s is IMethodSymbol + { + DeclaredAccessibility: Accessibility.Private, + ReturnsVoid: true, + IsPartialDefinition: true, + Name: "DIE_AddForDisposalAsync", + Parameters.Length: 1 + } method && SymbolEqualityComparer.Default.Equals(method.Parameters[0].Type, wellKnownTypes.AsyncDisposable)) + .OfType() + .FirstOrDefault(); } public IFieldSymbol? GetInstanceFor(ITypeSymbol typeSymbol) => @@ -50,4 +86,7 @@ public UserProvidedScopeElements(INamedTypeSymbol scopeType) public IMethodSymbol? GetFactoryFor(ITypeSymbol typeSymbol) => _typeToMethod.TryGetValue(typeSymbol, out var ret) ? ret : null; + + public IMethodSymbol? AddForDisposal { get; } + public IMethodSymbol? AddForDisposalAsync { get; } } \ No newline at end of file diff --git a/Test/CustomEmbedding/FactoryInContainercs.cs b/Test/CustomEmbedding/FactoryInContainercs.cs index 42c62fa9..67e67856 100644 --- a/Test/CustomEmbedding/FactoryInContainercs.cs +++ b/Test/CustomEmbedding/FactoryInContainercs.cs @@ -14,7 +14,7 @@ internal class Wrapper [CreateFunction(typeof(Wrapper), "Create")] internal partial class Container { - private string DIE_Factory() => "Yeah"; + private string DIE_Factory_Yeah() => "Yeah"; } public class Tests diff --git a/Test/CustomEmbedding/FactoryInScope.cs b/Test/CustomEmbedding/FactoryInScope.cs index 8a1b2e8a..f834a6a7 100644 --- a/Test/CustomEmbedding/FactoryInScope.cs +++ b/Test/CustomEmbedding/FactoryInScope.cs @@ -16,7 +16,7 @@ internal partial class Container { partial class DIE_DefaultScope { - private string DIE_Factory() => "Yeah"; + private string DIE_Factory_Yeah() => "Yeah"; } } diff --git a/Test/CustomEmbedding/FactoryInTransientScope.cs b/Test/CustomEmbedding/FactoryInTransientScope.cs index a11c8dfe..4cd08ca5 100644 --- a/Test/CustomEmbedding/FactoryInTransientScope.cs +++ b/Test/CustomEmbedding/FactoryInTransientScope.cs @@ -16,7 +16,7 @@ internal partial class Container { partial class DIE_DefaultTransientScope { - private string DIE_Factory() => "Yeah"; + private string DIE_Factory_Yeah() => "Yeah"; } } diff --git a/Test/CustomEmbedding/FactoryWithParameterInContainercs.cs b/Test/CustomEmbedding/FactoryWithParameterInContainercs.cs index ec957521..5b6e53e3 100644 --- a/Test/CustomEmbedding/FactoryWithParameterInContainercs.cs +++ b/Test/CustomEmbedding/FactoryWithParameterInContainercs.cs @@ -9,7 +9,7 @@ namespace MrMeeseeks.DIE.Test.CustomEmbedding.FactoryWithParameterInContainer; [CreateFunction(typeof(FileInfo), "Create")] internal partial class Container { - private string DIE_Path => "C:\\Yeah.txt"; + private string DIE_Factory_Path => "C:\\Yeah.txt"; private FileInfo DIE_Factory(string path) => new (path); } diff --git a/Test/CustomEmbedding/FactoryWithParameterInScope.cs b/Test/CustomEmbedding/FactoryWithParameterInScope.cs index e074d7bd..683d9096 100644 --- a/Test/CustomEmbedding/FactoryWithParameterInScope.cs +++ b/Test/CustomEmbedding/FactoryWithParameterInScope.cs @@ -17,7 +17,7 @@ internal partial class Container { partial class DIE_DefaultScope { - private string DIE_Path => "C:\\Yeah.txt"; + private string DIE_Factory_Path => "C:\\Yeah.txt"; private FileInfo DIE_Factory(string path) => new (path); } } diff --git a/Test/CustomEmbedding/FactoryWithParameterInTransientScope.cs b/Test/CustomEmbedding/FactoryWithParameterInTransientScope.cs index c6cbfc95..7e92ca2f 100644 --- a/Test/CustomEmbedding/FactoryWithParameterInTransientScope.cs +++ b/Test/CustomEmbedding/FactoryWithParameterInTransientScope.cs @@ -17,7 +17,7 @@ internal partial class Container { partial class DIE_DefaultTransientScope { - private string DIE_Path => "C:\\Yeah.txt"; + private string DIE_Factory_Path => "C:\\Yeah.txt"; private FileInfo DIE_Factory(string path) => new (path); } } diff --git a/Test/CustomEmbedding/FieldInContainercs.cs b/Test/CustomEmbedding/FieldInContainercs.cs index a462cb1b..7413d8b3 100644 --- a/Test/CustomEmbedding/FieldInContainercs.cs +++ b/Test/CustomEmbedding/FieldInContainercs.cs @@ -14,7 +14,7 @@ internal class Wrapper [CreateFunction(typeof(Wrapper), "Create")] internal partial class Container { - private readonly string DIE_Yeah = "Yeah"; + private readonly string DIE_Factory_Yeah = "Yeah"; } public class Tests diff --git a/Test/CustomEmbedding/FieldInScope.cs b/Test/CustomEmbedding/FieldInScope.cs index 5a9226de..934faa58 100644 --- a/Test/CustomEmbedding/FieldInScope.cs +++ b/Test/CustomEmbedding/FieldInScope.cs @@ -16,7 +16,7 @@ internal partial class Container { partial class DIE_DefaultScope { - private readonly string DIE_Yeah = "Yeah"; + private readonly string DIE_Factory_Yeah = "Yeah"; } } diff --git a/Test/CustomEmbedding/FieldInTransientScope.cs b/Test/CustomEmbedding/FieldInTransientScope.cs index 534dc50b..3e615070 100644 --- a/Test/CustomEmbedding/FieldInTransientScope.cs +++ b/Test/CustomEmbedding/FieldInTransientScope.cs @@ -16,7 +16,7 @@ internal partial class Container { partial class DIE_DefaultTransientScope { - private readonly string DIE_Yeah = "Yeah"; + private readonly string DIE_Factory_Yeah = "Yeah"; } } diff --git a/Test/CustomEmbedding/PropertyInContainercs.cs b/Test/CustomEmbedding/PropertyInContainercs.cs index e3137e6e..0f26d356 100644 --- a/Test/CustomEmbedding/PropertyInContainercs.cs +++ b/Test/CustomEmbedding/PropertyInContainercs.cs @@ -14,7 +14,7 @@ internal class Wrapper [CreateFunction(typeof(Wrapper), "Create")] internal partial class Container { - private string DIE_Yeah => "Yeah"; + private string DIE_Factory_Yeah => "Yeah"; } public class Tests diff --git a/Test/CustomEmbedding/PropertyInScope.cs b/Test/CustomEmbedding/PropertyInScope.cs index 1ef956cc..d093e7cb 100644 --- a/Test/CustomEmbedding/PropertyInScope.cs +++ b/Test/CustomEmbedding/PropertyInScope.cs @@ -16,7 +16,7 @@ internal partial class Container { partial class DIE_DefaultScope { - private string DIE_Yeah => "Yeah"; + private string DIE_Factory_Yeah => "Yeah"; } } diff --git a/Test/CustomEmbedding/PropertyInTransientScope.cs b/Test/CustomEmbedding/PropertyInTransientScope.cs index dac4e611..606dbab0 100644 --- a/Test/CustomEmbedding/PropertyInTransientScope.cs +++ b/Test/CustomEmbedding/PropertyInTransientScope.cs @@ -16,7 +16,7 @@ internal partial class Container { partial class DIE_DefaultTransientScope { - private string DIE_Yeah => "Yeah"; + private string DIE_Factory_Yeah => "Yeah"; } } diff --git a/Test/Disposal/ContainerUserDefinedAddForDisposal.cs b/Test/Disposal/ContainerUserDefinedAddForDisposal.cs new file mode 100644 index 00000000..e10c04bc --- /dev/null +++ b/Test/Disposal/ContainerUserDefinedAddForDisposal.cs @@ -0,0 +1,41 @@ +using System; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Disposal.ContainerUserDefinedAddForDisposal; + +internal class Dependency : IDisposable +{ + internal bool IsDisposed { get; private set; } + + public void Dispose() => IsDisposed = true; +} + +[CreateFunction(typeof(Dependency), "Create")] +internal partial class Container +{ + private Dependency DIE_Factory_Dependency + { + get + { + var dependency = new Dependency(); + DIE_AddForDisposal(dependency); + return dependency; + } + } + + private partial void DIE_AddForDisposal(IDisposable disposable); +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var instance = container.Create(); + await container.DisposeAsync().ConfigureAwait(false); + Assert.True(instance.IsDisposed); + } +} \ No newline at end of file diff --git a/Test/Disposal/ContainerUserDefinedAddForDisposalAsync.cs b/Test/Disposal/ContainerUserDefinedAddForDisposalAsync.cs new file mode 100644 index 00000000..106e646b --- /dev/null +++ b/Test/Disposal/ContainerUserDefinedAddForDisposalAsync.cs @@ -0,0 +1,45 @@ +using System; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Disposal.ContainerUserDefinedAddForDisposalAsync; + +internal class Dependency : IAsyncDisposable +{ + internal bool IsDisposed { get; private set; } + + public ValueTask DisposeAsync() + { + IsDisposed = true; + return new ValueTask(Task.CompletedTask); + } +} + +[CreateFunction(typeof(Dependency), "Create")] +internal partial class Container +{ + private Dependency DIE_Factory_Dependency + { + get + { + var dependency = new Dependency(); + DIE_AddForDisposalAsync(dependency); + return dependency; + } + } + + private partial void DIE_AddForDisposalAsync(IAsyncDisposable asyncDisposable); +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var instance = container.Create(); + await container.DisposeAsync().ConfigureAwait(false); + Assert.True(instance.IsDisposed); + } +} \ No newline at end of file diff --git a/Test/Disposal/ScopeUserDefinedAddForDisposal.cs b/Test/Disposal/ScopeUserDefinedAddForDisposal.cs new file mode 100644 index 00000000..df4b7690 --- /dev/null +++ b/Test/Disposal/ScopeUserDefinedAddForDisposal.cs @@ -0,0 +1,54 @@ +using System; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Disposal.ScopeUserDefinedAddForDisposal; + +internal class Dependency : IDisposable +{ + internal bool IsDisposed { get; private set; } + + public void Dispose() => IsDisposed = true; +} + +internal class ScopeRoot : IScopeRoot +{ + public Dependency Dependency { get; } + + internal ScopeRoot(Dependency dependency) + { + Dependency = dependency; + } +} + +[CreateFunction(typeof(ScopeRoot), "Create")] +internal partial class Container +{ + private partial class DIE_DefaultScope + { + private Dependency DIE_Factory_Dependency + { + get + { + var dependency = new Dependency(); + DIE_AddForDisposal(dependency); + return dependency; + } + } + + private partial void DIE_AddForDisposal(IDisposable disposable); + } +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var root = container.Create(); + await container.DisposeAsync().ConfigureAwait(false); + Assert.True(root.Dependency.IsDisposed); + } +} \ No newline at end of file diff --git a/Test/Disposal/ScopeUserDefinedAddForDisposalAsync.cs b/Test/Disposal/ScopeUserDefinedAddForDisposalAsync.cs new file mode 100644 index 00000000..3c5b6352 --- /dev/null +++ b/Test/Disposal/ScopeUserDefinedAddForDisposalAsync.cs @@ -0,0 +1,58 @@ +using System; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Disposal.ScopeUserDefinedAddForDisposalAsync; + +internal class Dependency : IAsyncDisposable +{ + internal bool IsDisposed { get; private set; } + + public ValueTask DisposeAsync() + { + IsDisposed = true; + return new ValueTask(Task.CompletedTask); + } +} + +internal class ScopeRoot : IScopeRoot +{ + public Dependency Dependency { get; } + + internal ScopeRoot(Dependency dependency) + { + Dependency = dependency; + } +} + +[CreateFunction(typeof(ScopeRoot), "Create")] +internal partial class Container +{ + private partial class DIE_DefaultScope + { + private Dependency DIE_Factory_Dependency + { + get + { + var dependency = new Dependency(); + DIE_AddForDisposalAsync(dependency); + return dependency; + } + } + + private partial void DIE_AddForDisposalAsync(IAsyncDisposable disposable); + } +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var instance = container.Create(); + await container.DisposeAsync().ConfigureAwait(false); + Assert.True(instance.Dependency.IsDisposed); + } +} \ No newline at end of file diff --git a/Test/Disposal/TransientScopeUserDefinedAddForDisposal.cs b/Test/Disposal/TransientScopeUserDefinedAddForDisposal.cs new file mode 100644 index 00000000..a3f1a94e --- /dev/null +++ b/Test/Disposal/TransientScopeUserDefinedAddForDisposal.cs @@ -0,0 +1,54 @@ +using System; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Disposal.TransientScopeUserDefinedAddForDisposal; + +internal class Dependency : IDisposable +{ + internal bool IsDisposed { get; private set; } + + public void Dispose() => IsDisposed = true; +} + +internal class TransientScopeRoot : ITransientScopeRoot +{ + public Dependency Dependency { get; } + + internal TransientScopeRoot(Dependency dependency) + { + Dependency = dependency; + } +} + +[CreateFunction(typeof(TransientScopeRoot), "Create")] +internal partial class Container +{ + private partial class DIE_DefaultTransientScope + { + private Dependency DIE_Factory_Dependency + { + get + { + var dependency = new Dependency(); + DIE_AddForDisposal(dependency); + return dependency; + } + } + + private partial void DIE_AddForDisposal(IDisposable disposable); + } +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var root = container.Create(); + await container.DisposeAsync().ConfigureAwait(false); + Assert.True(root.Dependency.IsDisposed); + } +} \ No newline at end of file diff --git a/Test/Disposal/TransientScopeUserDefinedAddForDisposalAsync.cs b/Test/Disposal/TransientScopeUserDefinedAddForDisposalAsync.cs new file mode 100644 index 00000000..df011fad --- /dev/null +++ b/Test/Disposal/TransientScopeUserDefinedAddForDisposalAsync.cs @@ -0,0 +1,58 @@ +using System; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Disposal.TransientScopeUserDefinedAddForDisposalAsync; + +internal class Dependency : IAsyncDisposable +{ + internal bool IsDisposed { get; private set; } + + public ValueTask DisposeAsync() + { + IsDisposed = true; + return new ValueTask(Task.CompletedTask); + } +} + +internal class TransientScopeRoot : ITransientScopeRoot +{ + public Dependency Dependency { get; } + + internal TransientScopeRoot(Dependency dependency) + { + Dependency = dependency; + } +} + +[CreateFunction(typeof(TransientScopeRoot), "Create")] +internal partial class Container +{ + private partial class DIE_DefaultTransientScope + { + private Dependency DIE_Factory_Dependency + { + get + { + var dependency = new Dependency(); + DIE_AddForDisposalAsync(dependency); + return dependency; + } + } + + private partial void DIE_AddForDisposalAsync(IAsyncDisposable disposable); + } +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var instance = container.Create(); + await container.DisposeAsync().ConfigureAwait(false); + Assert.True(instance.Dependency.IsDisposed); + } +} \ No newline at end of file From 0ece96ee8114be2f70615c531b69f01f3b30a412 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Fri, 3 Jun 2022 17:02:38 +0200 Subject: [PATCH 081/162] User-defined constructor parameter choices --- Main/CodeBuilding/RangeCodeBaseBuilder.cs | 21 +++++++- Main/Configuration/Attributes/Choice.cs | 8 +++ .../Function/FunctionResolutionBuilder.cs | 41 ++++++++++++++- Main/ResolutionTreeItem.cs | 13 ++++- Main/SourceGenerator.cs | 4 +- Main/UserProvidedScopeElements.cs | 51 +++++++++++++++---- Main/WellKnownTypesChoice.cs | 12 +++-- Sample/Context.cs | 32 +++++++++--- Test/CustomEmbedding/ConstructorParameter.cs | 30 +++++++++++ .../ConstructorParameterInScope.cs | 41 +++++++++++++++ .../ConstructorParameterInTransientScope.cs | 41 +++++++++++++++ ...ConstructorParameterWithAsyncDependency.cs | 36 +++++++++++++ ...ctorParameterWithAsyncDependencyInScope.cs | 47 +++++++++++++++++ ...eterWithAsyncDependencyInTransientScope.cs | 47 +++++++++++++++++ .../ConstructorParameterWithDependency.cs | 35 +++++++++++++ ...nstructorParameterWithDependencyInScope.cs | 46 +++++++++++++++++ ...ParameterWithDependencyInTransientScope.cs | 46 +++++++++++++++++ 17 files changed, 524 insertions(+), 27 deletions(-) create mode 100644 Test/CustomEmbedding/ConstructorParameter.cs create mode 100644 Test/CustomEmbedding/ConstructorParameterInScope.cs create mode 100644 Test/CustomEmbedding/ConstructorParameterInTransientScope.cs create mode 100644 Test/CustomEmbedding/ConstructorParameterWithAsyncDependency.cs create mode 100644 Test/CustomEmbedding/ConstructorParameterWithAsyncDependencyInScope.cs create mode 100644 Test/CustomEmbedding/ConstructorParameterWithAsyncDependencyInTransientScope.cs create mode 100644 Test/CustomEmbedding/ConstructorParameterWithDependency.cs create mode 100644 Test/CustomEmbedding/ConstructorParameterWithDependencyInScope.cs create mode 100644 Test/CustomEmbedding/ConstructorParameterWithDependencyInTransientScope.cs diff --git a/Main/CodeBuilding/RangeCodeBaseBuilder.cs b/Main/CodeBuilding/RangeCodeBaseBuilder.cs index 865f8199..035d8ed3 100644 --- a/Main/CodeBuilding/RangeCodeBaseBuilder.cs +++ b/Main/CodeBuilding/RangeCodeBaseBuilder.cs @@ -303,7 +303,15 @@ private static StringBuilder GenerateFields( stringBuilder = GenerateFields(stringBuilder, resolutionBase); stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); break; - case ConstructorResolution(var reference, var typeFullName, _, var parameters, var initializedProperties, var initialization): + case OutParameterResolution(var reference, var typeFullName): + stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); + break; + case ConstructorParameterChoiceResolution(_, var parameters): + stringBuilder = parameters.Aggregate(stringBuilder, (builder, tuple) => GenerateFields(builder, tuple.Dependency)); + break; + case ConstructorResolution(var reference, var typeFullName, _, var parameters, var initializedProperties, var initialization, var parameterChoiceResolution): + if (parameterChoiceResolution is {}) + stringBuilder = GenerateFields(stringBuilder, parameterChoiceResolution); stringBuilder = parameters.Aggregate(stringBuilder, (builder, tuple) => GenerateFields(builder, tuple.Dependency)); stringBuilder = initializedProperties.Aggregate(stringBuilder, @@ -503,7 +511,16 @@ private StringBuilder GenerateResolutions( _ => stringBuilder }; break; - case ConstructorResolution(var reference, var typeFullName, var disposalType, var parameters, var initializedProperties, var initialization): + case OutParameterResolution(_, _): + break; + case ConstructorParameterChoiceResolution(var functionName, var parameters): + stringBuilder = parameters.Aggregate(stringBuilder, + (builder, tuple) => GenerateResolutions(builder, tuple.Dependency)); + stringBuilder = stringBuilder.AppendLine($"{functionName}({string.Join(", ", parameters.Select(p => $"{p.Name}: {(p.isOut ? "out " : "")}{p.Dependency.Reference}"))});"); + break; + case ConstructorResolution(var reference, var typeFullName, var disposalType, var parameters, var initializedProperties, var initialization, var parameterChoiceResolution): + if (parameterChoiceResolution is { }) + GenerateResolutions(stringBuilder, parameterChoiceResolution); stringBuilder = parameters.Aggregate(stringBuilder, (builder, tuple) => GenerateResolutions(builder, tuple.Dependency)); stringBuilder = initializedProperties.Aggregate(stringBuilder, diff --git a/Main/Configuration/Attributes/Choice.cs b/Main/Configuration/Attributes/Choice.cs index 18212036..f7525c4c 100644 --- a/Main/Configuration/Attributes/Choice.cs +++ b/Main/Configuration/Attributes/Choice.cs @@ -91,4 +91,12 @@ public ImplementationCollectionChoiceAttribute(Type type, params Type[] implemen public class FilterImplementationCollectionChoiceAttribute : Attribute { public FilterImplementationCollectionChoiceAttribute(Type type) {} +} + +[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] +public class CustomConstructorParameterChoiceAttribute : Attribute +{ + public CustomConstructorParameterChoiceAttribute(Type type) + { + } } \ No newline at end of file diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs index 5a8b7c36..89646652 100644 --- a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs @@ -164,6 +164,7 @@ internal FunctionResolutionBuilder( .Select((t, i) => ($"item{(i + 1)}", SwitchType(new SwitchTypeParameter(t, currentFuncParameters, implementationStack)).Item1)) .ToList(), Array.Empty<(string Name, Resolvable Dependency)>(), + null, null); return (constructorResolution, constructorResolution); } @@ -692,6 +693,40 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup var isTransientScopeRoot = _checkTypeProperties.ShouldBeScopeRoot(implementationType) == ScopeLevel.TransientScope; + var outParameters = ImmutableDictionary.Empty; + ConstructorParameterChoiceResolution? constructorParameterChoiceResolution = null; + + if (_userProvidedScopeElements.GetCustomConstructorParameterChoiceFor(implementationType) is + { } parameterChoiceMethod) + { + constructorParameterChoiceResolution = new ConstructorParameterChoiceResolution( + parameterChoiceMethod.Name, + parameterChoiceMethod + .Parameters + .Select(p => + { + var isOut = p.RefKind == RefKind.Out; + + if (isOut) + { + var outParameter = new OutParameterResolution( + RootReferenceGenerator.Generate(p.Type), + p.Type.FullName()); + outParameters = outParameters.Add(p.Name, outParameter); + return ( + p.Name, + outParameter, + isOut); + } + + return ( + p.Name, + SwitchType(new SwitchTypeParameter(p.Type, currentParameters, implementationStack)).Item1, + isOut); + }) + .ToList()); + } + ITypeInitializationResolution? typeInitializationResolution = null; if (_checkTypeProperties.GetInitializerFor(implementationType) is { } tuple) @@ -740,7 +775,8 @@ false when initializationMethod.ReturnType.Equals(_wellKnownTypes.ValueTask, Sym .Where(p => p.SetMethod?.IsInitOnly ?? false)) .Select(p => ProcessChildType(p.Type, p.Name, implementationType, currentParameters)) .ToList()), - typeInitializationResolution); + typeInitializationResolution, + constructorParameterChoiceResolution); return (resolution, resolution); @@ -750,6 +786,9 @@ false when initializationMethod.ReturnType.Equals(_wellKnownTypes.ValueTask, Sym INamedTypeSymbol impType, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currParameter) { + if (outParameters.TryGetValue(parameterName, out var outParameterResolution)) + return (parameterName, new ParameterResolution(outParameterResolution.Reference, outParameterResolution.TypeFullName)); + if (checkForDecoration && decoration is {}) { if (typeSymbol.Equals(decoration.InterfaceType, SymbolEqualityComparer.Default)) diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index 40a23b7d..ecb93f50 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -119,7 +119,8 @@ internal record ConstructorResolution( DisposalType DisposalType, IReadOnlyList<(string Name, Resolvable Dependency)> Parameter, IReadOnlyList<(string Name, Resolvable Dependency)> InitializedProperties, - ITypeInitializationResolution? Initialization) : Resolvable(Reference, TypeFullName), ITaskConsumableResolution; + ITypeInitializationResolution? Initialization, + ConstructorParameterChoiceResolution? ParameterChoices) : Resolvable(Reference, TypeFullName), ITaskConsumableResolution; internal record LazyResolution( string Reference, @@ -171,6 +172,14 @@ internal record FactoryResolution( string FunctionName, IReadOnlyList<(string Name, Resolvable Dependency)> Parameter) : Resolvable(Reference, TypeFullName); +internal record OutParameterResolution( + string Reference, + string TypeFullName) : Resolvable(Reference, TypeFullName); + +internal record ConstructorParameterChoiceResolution( + string FunctionName, + IReadOnlyList<(string Name, Resolvable Dependency, bool isOut)> Parameter) : Resolvable("foo", "bar"); + internal record CollectionResolution( string Reference, string TypeFullName, @@ -186,6 +195,7 @@ internal record SyncDisposableCollectionResolution( DisposalType.None, Array.Empty<(string Name, Resolvable Dependency)>(), Array.Empty<(string Name, Resolvable Dependency)>(), + null, null); internal record AsyncDisposableCollectionResolution( @@ -197,6 +207,7 @@ internal record AsyncDisposableCollectionResolution( DisposalType.None, Array.Empty<(string Name, Resolvable Dependency)>(), Array.Empty<(string Name, Resolvable Dependency)>(), + null, null); internal abstract record RangeResolution( diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index 2e709c05..db0df2ca 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -68,7 +68,7 @@ IContainerResolutionBuilder ResolutionTreeFactory(IContainerInfo ci) RangedFunctionGroupResolutionBuilderFactory, FunctionResolutionSynchronicityDecisionMakerFactory, LocalFunctionResolutionBuilderFactory, - new UserProvidedScopeElements(ci.ContainerType, wellKnownTypes), + new UserProvidedScopeElements(ci.ContainerType, wellKnownTypes, wellKnownTypesChoice), functionCycleTracker); IScopeManager ScopeManagerFactory( @@ -86,7 +86,7 @@ IScopeManager ScopeManagerFactory( wellKnownTypesChoice, wellKnownTypesMiscellaneous), tfa => new CheckTypeProperties(new CurrentlyConsideredTypes(tfa, implementationTypeSetCache), wellKnownTypes), - st => new UserProvidedScopeElements(st, wellKnownTypes), + st => new UserProvidedScopeElements(st, wellKnownTypes, wellKnownTypesChoice), new EmptyUserProvidedScopeElements(), wellKnownTypesMiscellaneous); diff --git a/Main/UserProvidedScopeElements.cs b/Main/UserProvidedScopeElements.cs index 1ad85a17..6affeb98 100644 --- a/Main/UserProvidedScopeElements.cs +++ b/Main/UserProvidedScopeElements.cs @@ -2,20 +2,22 @@ namespace MrMeeseeks.DIE; internal interface IUserProvidedScopeElements { - IFieldSymbol? GetInstanceFor(ITypeSymbol typeSymbol); - IPropertySymbol? GetPropertyFor(ITypeSymbol typeSymbol); - IMethodSymbol? GetFactoryFor(ITypeSymbol typeSymbol); + IFieldSymbol? GetInstanceFor(ITypeSymbol type); + IPropertySymbol? GetPropertyFor(ITypeSymbol type); + IMethodSymbol? GetFactoryFor(ITypeSymbol type); IMethodSymbol? AddForDisposal { get; } IMethodSymbol? AddForDisposalAsync { get; } + IMethodSymbol? GetCustomConstructorParameterChoiceFor(INamedTypeSymbol type); } internal class EmptyUserProvidedScopeElements : IUserProvidedScopeElements { - public IFieldSymbol? GetInstanceFor(ITypeSymbol typeSymbol) => null; - public IPropertySymbol? GetPropertyFor(ITypeSymbol typeSymbol) => null; - public IMethodSymbol? GetFactoryFor(ITypeSymbol typeSymbol) => null; + public IFieldSymbol? GetInstanceFor(ITypeSymbol type) => null; + public IPropertySymbol? GetPropertyFor(ITypeSymbol type) => null; + public IMethodSymbol? GetFactoryFor(ITypeSymbol type) => null; public IMethodSymbol? AddForDisposal => null; public IMethodSymbol? AddForDisposalAsync => null; + public IMethodSymbol? GetCustomConstructorParameterChoiceFor(INamedTypeSymbol type) => null; } internal class UserProvidedScopeElements : IUserProvidedScopeElements @@ -23,34 +25,35 @@ internal class UserProvidedScopeElements : IUserProvidedScopeElements private readonly IReadOnlyDictionary _typeToField; private readonly IReadOnlyDictionary _typeToProperty; private readonly IReadOnlyDictionary _typeToMethod; + private readonly IReadOnlyDictionary _customConstructorParameterChoiceMethods; public UserProvidedScopeElements( // parameter INamedTypeSymbol scopeType, // dependencies - WellKnownTypes wellKnownTypes) + WellKnownTypes wellKnownTypes, + WellKnownTypesChoice wellKnownTypesChoice) { var dieMembers = scopeType.GetMembers() .Where(s => s.Name.StartsWith("DIE_")) .ToList(); _typeToField = dieMembers - .Where(s => s is IFieldSymbol) + .Where(s => s.Name.StartsWith("DIE_Factory_")) .OfType() - .Where(f => f.Name.StartsWith("DIE_Factory_")) .ToDictionary(fs => fs.Type, fs => fs, SymbolEqualityComparer.IncludeNullability); _typeToProperty = dieMembers + .Where(s => s.Name.StartsWith("DIE_Factory_")) .Where(s => s is IPropertySymbol { GetMethod: { } }) .OfType() - .Where(f => f.Name.StartsWith("DIE_Factory_")) .ToDictionary(ps => ps.Type, ps => ps, SymbolEqualityComparer.IncludeNullability); _typeToMethod = dieMembers + .Where(s => s.Name.StartsWith("DIE_Factory_")) .Where(s => s is IMethodSymbol { ReturnsVoid: false, Arity: 0, IsConditional: false, MethodKind: MethodKind.Ordinary }) .OfType() - .Where(f => f.Name.StartsWith("DIE_Factory_")) .ToDictionary(ps => ps.ReturnType, ps => ps, SymbolEqualityComparer.IncludeNullability); AddForDisposal = dieMembers @@ -76,6 +79,30 @@ public UserProvidedScopeElements( } method && SymbolEqualityComparer.Default.Equals(method.Parameters[0].Type, wellKnownTypes.AsyncDisposable)) .OfType() .FirstOrDefault(); + + _customConstructorParameterChoiceMethods = dieMembers + .Where(s => s.Name.StartsWith("DIE_ConstrParam_")) + .Where(s => s is IMethodSymbol { ReturnsVoid: true, Arity: 0, IsConditional: false, MethodKind: MethodKind.Ordinary } method + && method.Parameters.Any(p => p.RefKind == RefKind.Out)) + .OfType() + .Select(m => + { + var type = m.GetAttributes() + .Where(ad => SymbolEqualityComparer.Default.Equals(ad.AttributeClass, + wellKnownTypesChoice.CustomConstructorParameterChoiceAttribute)) + .Select(ad => + { + if (ad.ConstructorArguments.Length != 1) + return null; + return ad.ConstructorArguments[0].Value is INamedTypeSymbol type ? type : null; + }) + .OfType() + .FirstOrDefault(); + + return type is { } ? (type, m) : ((INamedTypeSymbol, IMethodSymbol)?) null; + }) + .OfType<(INamedTypeSymbol, IMethodSymbol)>() + .ToDictionary(t => t.Item1, t => t.Item2, SymbolEqualityComparer.Default); } public IFieldSymbol? GetInstanceFor(ITypeSymbol typeSymbol) => @@ -89,4 +116,6 @@ public UserProvidedScopeElements( public IMethodSymbol? AddForDisposal { get; } public IMethodSymbol? AddForDisposalAsync { get; } + public IMethodSymbol? GetCustomConstructorParameterChoiceFor(INamedTypeSymbol type) => + _customConstructorParameterChoiceMethods.TryGetValue(type, out var ret) ? ret : null; } \ No newline at end of file diff --git a/Main/WellKnownTypesChoice.cs b/Main/WellKnownTypesChoice.cs index a5c32b0f..2f801db3 100644 --- a/Main/WellKnownTypesChoice.cs +++ b/Main/WellKnownTypesChoice.cs @@ -16,7 +16,8 @@ internal record WellKnownTypesChoice( INamedTypeSymbol FilterConstructorChoiceAttribute, INamedTypeSymbol FilterPropertyChoiceAttribute, INamedTypeSymbol FilterImplementationChoiceAttribute, - INamedTypeSymbol FilterImplementationCollectionChoiceAttribute) + INamedTypeSymbol FilterImplementationCollectionChoiceAttribute, + INamedTypeSymbol CustomConstructorParameterChoiceAttribute) { internal static bool TryCreate(Compilation compilation, out WellKnownTypesChoice wellKnownTypes) { @@ -62,6 +63,9 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypesChoice var filterImplementationCollectionChoiceAttribute = compilation .GetTypeByMetadataName(typeof(FilterImplementationCollectionChoiceAttribute).FullName ?? ""); + var customConstructorParameterChoiceAttribute = compilation + .GetTypeByMetadataName(typeof(CustomConstructorParameterChoiceAttribute).FullName ?? ""); + if (implementationChoiceAttribute is not null && implementationCollectionChoiceAttribute is not null && genericParameterSubstitutesChoiceAttribute is not null @@ -75,7 +79,8 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypesChoice && filterConstructorChoiceAttribute is not null && filterPropertyChoiceAttribute is not null && filterImplementationChoiceAttribute is not null - && filterImplementationCollectionChoiceAttribute is not null) + && filterImplementationCollectionChoiceAttribute is not null + && customConstructorParameterChoiceAttribute is not null) { wellKnownTypes = new WellKnownTypesChoice( @@ -92,7 +97,8 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypesChoice FilterConstructorChoiceAttribute: filterConstructorChoiceAttribute, FilterPropertyChoiceAttribute: filterPropertyChoiceAttribute, FilterImplementationChoiceAttribute: filterImplementationChoiceAttribute, - FilterImplementationCollectionChoiceAttribute: filterImplementationCollectionChoiceAttribute); + FilterImplementationCollectionChoiceAttribute: filterImplementationCollectionChoiceAttribute, + CustomConstructorParameterChoiceAttribute: customConstructorParameterChoiceAttribute); return true; } diff --git a/Sample/Context.cs b/Sample/Context.cs index f00d4997..e36bafb5 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -1,16 +1,34 @@ -using System; -using MrMeeseeks.DIE.Configuration.Attributes; +using MrMeeseeks.DIE.Configuration.Attributes; using MrMeeseeks.DIE.Sample; -namespace MrMeeseeks.DIE.Test.CycleDetection.Function.NoCycle.DirectRecursionScope; +namespace MrMeeseeks.DIE.Test.CustomEmbedding.ConstructorParameterWithDependencyInScope; -internal class Dependency : IScopeInstance +internal class Dependency { - internal Dependency(Func inner) {} + public int Number { get; } + + internal Dependency(int number) => Number = number; +} + +internal class OtherDependency +{ + public int Number => 69; +} + +internal class ScopeRoot : IScopeRoot +{ + public Dependency Dependency { get; } + + internal ScopeRoot( + Dependency dependency) => Dependency = dependency; } -[CreateFunction(typeof(Dependency), "Create")] +[CreateFunction(typeof(ScopeRoot), "Create")] internal partial class Container { - + partial class DIE_DefaultScope + { + [CustomConstructorParameterChoice(typeof(Dependency))] + private void DIE_ConstrParam_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; + } } \ No newline at end of file diff --git a/Test/CustomEmbedding/ConstructorParameter.cs b/Test/CustomEmbedding/ConstructorParameter.cs new file mode 100644 index 00000000..e6eeb21f --- /dev/null +++ b/Test/CustomEmbedding/ConstructorParameter.cs @@ -0,0 +1,30 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CustomEmbedding.ConstructorParameter; + +internal class Dependency +{ + public int Number { get; } + + internal Dependency(int number) => Number = number; +} + +[CreateFunction(typeof(Dependency), "Create")] +internal partial class Container +{ + [CustomConstructorParameterChoice(typeof(Dependency))] + private void DIE_ConstrParam_Dependency(out int number) => number = 69; +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var instance = container.Create(); + Assert.Equal(69, instance.Number); + } +} \ No newline at end of file diff --git a/Test/CustomEmbedding/ConstructorParameterInScope.cs b/Test/CustomEmbedding/ConstructorParameterInScope.cs new file mode 100644 index 00000000..827186a3 --- /dev/null +++ b/Test/CustomEmbedding/ConstructorParameterInScope.cs @@ -0,0 +1,41 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CustomEmbedding.ConstructorParameterInScope; + +internal class Dependency +{ + public int Number { get; } + + internal Dependency(int number) => Number = number; +} + +internal class ScopeRoot : IScopeRoot +{ + public Dependency Dependency { get; } + + internal ScopeRoot( + Dependency dependency) => Dependency = dependency; +} + +[CreateFunction(typeof(ScopeRoot), "Create")] +internal partial class Container +{ + partial class DIE_DefaultScope + { + [CustomConstructorParameterChoice(typeof(Dependency))] + private void DIE_ConstrParam_Dependency(out int number) => number = 69; + } +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var instance = container.Create().Dependency; + Assert.Equal(69, instance.Number); + } +} \ No newline at end of file diff --git a/Test/CustomEmbedding/ConstructorParameterInTransientScope.cs b/Test/CustomEmbedding/ConstructorParameterInTransientScope.cs new file mode 100644 index 00000000..faf67298 --- /dev/null +++ b/Test/CustomEmbedding/ConstructorParameterInTransientScope.cs @@ -0,0 +1,41 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CustomEmbedding.ConstructorParameterInTransientScope; + +internal class Dependency +{ + public int Number { get; } + + internal Dependency(int number) => Number = number; +} + +internal class TransientScopeRoot : ITransientScopeRoot +{ + public Dependency Dependency { get; } + + internal TransientScopeRoot( + Dependency dependency) => Dependency = dependency; +} + +[CreateFunction(typeof(TransientScopeRoot), "Create")] +internal partial class Container +{ + partial class DIE_DefaultTransientScope + { + [CustomConstructorParameterChoice(typeof(Dependency))] + private void DIE_ConstrParam_Dependency(out int number) => number = 69; + } +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var instance = container.Create().Dependency; + Assert.Equal(69, instance.Number); + } +} \ No newline at end of file diff --git a/Test/CustomEmbedding/ConstructorParameterWithAsyncDependency.cs b/Test/CustomEmbedding/ConstructorParameterWithAsyncDependency.cs new file mode 100644 index 00000000..ca17b6e9 --- /dev/null +++ b/Test/CustomEmbedding/ConstructorParameterWithAsyncDependency.cs @@ -0,0 +1,36 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CustomEmbedding.ConstructorParameterWithAsyncDependency; + +internal class Dependency +{ + public int Number { get; } + + internal Dependency(int number) => Number = number; +} + +internal class OtherDependency : IValueTaskTypeInitializer +{ + public int Number => 69; + public ValueTask InitializeAsync() => new (Task.CompletedTask); +} + +[CreateFunction(typeof(Dependency), "Create")] +internal partial class Container +{ + [CustomConstructorParameterChoice(typeof(Dependency))] + private void DIE_ConstrParam_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var instance = await container.CreateAsync().ConfigureAwait(false); + Assert.Equal(69, instance.Number); + } +} \ No newline at end of file diff --git a/Test/CustomEmbedding/ConstructorParameterWithAsyncDependencyInScope.cs b/Test/CustomEmbedding/ConstructorParameterWithAsyncDependencyInScope.cs new file mode 100644 index 00000000..51be0bd8 --- /dev/null +++ b/Test/CustomEmbedding/ConstructorParameterWithAsyncDependencyInScope.cs @@ -0,0 +1,47 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CustomEmbedding.ConstructorParameterWithAsyncDependencyInScope; + +internal class Dependency +{ + public int Number { get; } + + internal Dependency(int number) => Number = number; +} + +internal class OtherDependency : IValueTaskTypeInitializer +{ + public int Number => 69; + public ValueTask InitializeAsync() => new (Task.CompletedTask); +} + +internal class ScopeRoot : IScopeRoot +{ + public Dependency Dependency { get; } + + internal ScopeRoot( + Dependency dependency) => Dependency = dependency; +} + +[CreateFunction(typeof(ScopeRoot), "Create")] +internal partial class Container +{ + partial class DIE_DefaultScope + { + [CustomConstructorParameterChoice(typeof(Dependency))] + private void DIE_ConstrParam_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; + } +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var instance = await container.CreateAsync().ConfigureAwait(false); + Assert.Equal(69, instance.Dependency.Number); + } +} \ No newline at end of file diff --git a/Test/CustomEmbedding/ConstructorParameterWithAsyncDependencyInTransientScope.cs b/Test/CustomEmbedding/ConstructorParameterWithAsyncDependencyInTransientScope.cs new file mode 100644 index 00000000..fea68d86 --- /dev/null +++ b/Test/CustomEmbedding/ConstructorParameterWithAsyncDependencyInTransientScope.cs @@ -0,0 +1,47 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CustomEmbedding.ConstructorParameterWithAsyncDependencyInTransientScope; + +internal class Dependency +{ + public int Number { get; } + + internal Dependency(int number) => Number = number; +} + +internal class OtherDependency : IValueTaskTypeInitializer +{ + public int Number => 69; + public ValueTask InitializeAsync() => new (Task.CompletedTask); +} + +internal class TransientScopeRoot : ITransientScopeRoot +{ + public Dependency Dependency { get; } + + internal TransientScopeRoot( + Dependency dependency) => Dependency = dependency; +} + +[CreateFunction(typeof(TransientScopeRoot), "Create")] +internal partial class Container +{ + partial class DIE_DefaultTransientScope + { + [CustomConstructorParameterChoice(typeof(Dependency))] + private void DIE_ConstrParam_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; + } +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var instance = await container.CreateAsync().ConfigureAwait(false); + Assert.Equal(69, instance.Dependency.Number); + } +} \ No newline at end of file diff --git a/Test/CustomEmbedding/ConstructorParameterWithDependency.cs b/Test/CustomEmbedding/ConstructorParameterWithDependency.cs new file mode 100644 index 00000000..3decb8a9 --- /dev/null +++ b/Test/CustomEmbedding/ConstructorParameterWithDependency.cs @@ -0,0 +1,35 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CustomEmbedding.ConstructorParameterWithDependency; + +internal class Dependency +{ + public int Number { get; } + + internal Dependency(int number) => Number = number; +} + +internal class OtherDependency +{ + public int Number => 69; +} + +[CreateFunction(typeof(Dependency), "Create")] +internal partial class Container +{ + [CustomConstructorParameterChoice(typeof(Dependency))] + private void DIE_ConstrParam_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var instance = container.Create(); + Assert.Equal(69, instance.Number); + } +} \ No newline at end of file diff --git a/Test/CustomEmbedding/ConstructorParameterWithDependencyInScope.cs b/Test/CustomEmbedding/ConstructorParameterWithDependencyInScope.cs new file mode 100644 index 00000000..633e551e --- /dev/null +++ b/Test/CustomEmbedding/ConstructorParameterWithDependencyInScope.cs @@ -0,0 +1,46 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CustomEmbedding.ConstructorParameterWithDependencyInScope; + +internal class Dependency +{ + public int Number { get; } + + internal Dependency(int number) => Number = number; +} + +internal class OtherDependency +{ + public int Number => 69; +} + +internal class ScopeRoot : IScopeRoot +{ + public Dependency Dependency { get; } + + internal ScopeRoot( + Dependency dependency) => Dependency = dependency; +} + +[CreateFunction(typeof(ScopeRoot), "Create")] +internal partial class Container +{ + partial class DIE_DefaultScope + { + [CustomConstructorParameterChoice(typeof(Dependency))] + private void DIE_ConstrParam_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; + } +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var instance = container.Create(); + Assert.Equal(69, instance.Dependency.Number); + } +} \ No newline at end of file diff --git a/Test/CustomEmbedding/ConstructorParameterWithDependencyInTransientScope.cs b/Test/CustomEmbedding/ConstructorParameterWithDependencyInTransientScope.cs new file mode 100644 index 00000000..4d54641d --- /dev/null +++ b/Test/CustomEmbedding/ConstructorParameterWithDependencyInTransientScope.cs @@ -0,0 +1,46 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CustomEmbedding.ConstructorParameterWithDependencyInTransientScope; + +internal class Dependency +{ + public int Number { get; } + + internal Dependency(int number) => Number = number; +} + +internal class OtherDependency +{ + public int Number => 69; +} + +internal class TransientScopeRoot : ITransientScopeRoot +{ + public Dependency Dependency { get; } + + internal TransientScopeRoot( + Dependency dependency) => Dependency = dependency; +} + +[CreateFunction(typeof(TransientScopeRoot), "Create")] +internal partial class Container +{ + partial class DIE_DefaultTransientScope + { + [CustomConstructorParameterChoice(typeof(Dependency))] + private void DIE_ConstrParam_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; + } +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var instance = container.Create(); + Assert.Equal(69, instance.Dependency.Number); + } +} \ No newline at end of file From ba176098aa2979e0944bd629246bdb5ba0fe4b06 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sat, 4 Jun 2022 20:54:07 +0200 Subject: [PATCH 082/162] Preparations for nuget deployment --- .github/workflows/main.yml | 35 +++++++++++++++++++++++++++++++++++ Directory.build.props | 8 +++----- Main/Main.csproj | 4 +++- MrMeeseeks.DIE.sln | 1 + Sample/Sample.csproj | 2 +- 5 files changed, 43 insertions(+), 7 deletions(-) create mode 100644 .github/workflows/main.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 00000000..7d032782 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,35 @@ +name: OnVersionTag + +on: + push: + tags: + - '*' +jobs: + windows: + + strategy: + matrix: + configuration: [ Release ] + runs-on: windows-latest + + env: + Solution_Name: MrMeeseeks.DIE.sln # Replace with your solution name, i.e. MyWpfApp.sln. + + steps: + - uses: actions/checkout@main + - name: Setup .NET Core + uses: actions/setup-dotnet@v2.1.0 + with: + dotnet-version: 6.0.300 + - run: set DOTNET_CLI_TELEMETRY_OPTOUT=1 + - name: Install dependencies + run: dotnet restore .\MrMeeseeks.DIE.sln + - name: Build + run: dotnet build .\MrMeeseeks.DIE.sln --configuration Release --no-restore + - name: Publish to NuGet + uses: brandedoutcast/publish-nuget@master + with: + PROJECT_FILE_PATH: Main/Main.csproj + VERSION_FILE_PATH: Directory.Build.props + TAG_COMMIT: false + NUGET_KEY: ${{secrets.NUGET_API_KEY}} diff --git a/Directory.build.props b/Directory.build.props index 26fdbde9..92784045 100644 --- a/Directory.build.props +++ b/Directory.build.props @@ -23,8 +23,6 @@ $(MinVerVersion) git LICENSE - $(AssemblyName) - $(AssemblyName) For further information and updates please visit the projects page. @@ -37,9 +35,9 @@ - MrMeeseeks Generator Static Delegator + MrMeeseeks DI SourceGenerator -/- - https://github.com/Yeah69/MrMeeseeks.StaticDelegateGenerator - https://github.com/Yeah69/MrMeeseeks.StaticDelegateGenerator + https://github.com/Yeah69/MrMeeseeks.DIE + https://github.com/Yeah69/MrMeeseeks.DIE \ No newline at end of file diff --git a/Main/Main.csproj b/Main/Main.csproj index 2249215f..8ee7d231 100644 --- a/Main/Main.csproj +++ b/Main/Main.csproj @@ -5,6 +5,8 @@ netstandard2.0 MrMeeseeks.DIE MrMeeseeks.DIE + $(AssemblyName) + $(AssemblyName) true true @@ -29,7 +31,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/MrMeeseeks.DIE.sln b/MrMeeseeks.DIE.sln index 3aeefc54..1497f684 100644 --- a/MrMeeseeks.DIE.sln +++ b/MrMeeseeks.DIE.sln @@ -10,6 +10,7 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Misc", "Misc", "{4BFDBE50-2316-463E-B587-3F367D591FDF}" ProjectSection(SolutionItems) = preProject Directory.build.props = Directory.build.props + .github\workflows\main.yml = .github\workflows\main.yml EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test", "Test\Test.csproj", "{5075D83B-EF12-4372-8210-CEB5D81A4FE2}" diff --git a/Sample/Sample.csproj b/Sample/Sample.csproj index 1b755e49..3f68edf4 100644 --- a/Sample/Sample.csproj +++ b/Sample/Sample.csproj @@ -11,7 +11,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive From 15f51034aab4d7c82cc461dc5ab1585181f68060 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sat, 25 Jun 2022 22:05:43 +0200 Subject: [PATCH 083/162] Initial validation of container and its members --- Main/Constants.cs | 19 +- Main/DiagLogger.cs | 17 +- Main/Diagnostics.cs | 57 ++++ Main/DieException.cs | 8 +- Main/ExecuteImpl.cs | 24 +- .../ContainerResolutionBuilder.cs | 24 +- .../Function/FunctionResolutionBuilder.cs | 12 +- .../RangeResolutionBaseBuilder.cs | 14 +- Main/ResolutionBuilding/ScopeManager.cs | 18 +- .../ScopeResolutionBuilder.cs | 4 +- .../TransientScopeResolutionBuilder.cs | 8 +- Main/ResolutionTreeItem.cs | 2 +- Main/SourceGenerator.cs | 50 +++- Main/UserProvidedScopeElements.cs | 22 +- .../ValidateUserDefinedAddForDisposal.cs | 104 ++++++++ .../ValidateUserDefinedConstrParamMethod.cs | 82 ++++++ .../ValidateUserDefinedFactoryField.cs | 33 +++ .../ValidateUserDefinedFactoryMethod.cs | 60 +++++ .../UserDefined/ValidateUserDefinedMethod.cs | 64 +++++ Main/Validation/Range/ValidateContainer.cs | 65 +++++ Main/Validation/Range/ValidateRange.cs | 244 ++++++++++++++++++ Main/Validation/Range/ValidateScope.cs | 39 +++ Main/Validation/Range/ValidateScopeBase.cs | 100 +++++++ .../Range/ValidateTransientScope.cs | 39 +++ Sample/Context.cs | 9 +- .../Async/Awaited/AsyncScopeRootCallAsTask.cs | 2 +- .../Awaited/AsyncScopeRootCallAsValueTask.cs | 2 +- .../Awaited/AsyncScopeRootCallAwaited.cs | 2 +- .../ContainerInstanceFunctionAsTask.cs | 2 +- .../ContainerInstanceFunctionAsValueTask.cs | 2 +- .../Awaited/ScopeInstanceFunctionAsTask.cs | 2 +- .../ScopeInstanceFunctionAsValueTask.cs | 2 +- Test/Async/Awaited/TaskTypeInitializerTask.cs | 2 +- .../Awaited/TaskTypeInitializerValueTask.cs | 2 +- .../TransientScopeInstanceFunctionAsTask.cs | 2 +- ...ansientScopeInstanceFunctionAsValueTask.cs | 2 +- ...InstanceFunction_DifferentSynchronicity.cs | 6 +- .../ContainerInstanceFunctionAsTask.cs | 2 +- .../ContainerInstanceFunctionAsValueTask.cs | 2 +- Test/Async/Wrapped/DecorationChaining.cs | 2 +- Test/Async/Wrapped/Func.cs | 2 +- Test/Async/Wrapped/Lazy.cs | 2 +- .../Wrapped/ScopeInstanceFunctionAsTask.cs | 2 +- .../ScopeInstanceFunctionAsValueTask.cs | 2 +- Test/Async/Wrapped/SyncToTask.cs | 2 +- Test/Async/Wrapped/SyncToValueTask.cs | 2 +- Test/Async/Wrapped/TaskCollection.cs | 2 +- Test/Async/Wrapped/TaskComposition.cs | 2 +- Test/Async/Wrapped/TaskToTask.cs | 2 +- Test/Async/Wrapped/TaskToValueTask.cs | 2 +- .../TransientScopeInstanceFunctionAsTask.cs | 2 +- ...ceFunctionAsTask_DifferentSynchronicity.cs | 6 +- ...ansientScopeInstanceFunctionAsValueTask.cs | 2 +- ...ctionAsValueTask_DifferentSynchronicity.cs | 6 +- Test/Async/Wrapped/ValueTaskCollection.cs | 2 +- Test/Async/Wrapped/ValueTaskComposition.cs | 2 +- Test/Async/Wrapped/ValueTaskToTask.cs | 2 +- Test/Async/Wrapped/ValueTaskToValueTask.cs | 2 +- Test/Composite/Container.cs | 2 +- Test/Composite/Decorated.cs | 2 +- Test/Composite/MixedScoping.cs | 2 +- Test/Composite/Normal.cs | 2 +- Test/Composite/ScopeRoot.cs | 2 +- Test/ConstructorChoice/Parameterless.cs | 2 +- Test/ConstructorChoice/WithParameter.cs | 2 +- Test/CustomEmbedding/ConstructorParameter.cs | 2 +- .../ConstructorParameterInScope.cs | 4 +- .../ConstructorParameterInTransientScope.cs | 4 +- ...ConstructorParameterWithAsyncDependency.cs | 2 +- ...ctorParameterWithAsyncDependencyInScope.cs | 4 +- ...eterWithAsyncDependencyInTransientScope.cs | 4 +- .../ConstructorParameterWithDependency.cs | 2 +- ...nstructorParameterWithDependencyInScope.cs | 4 +- ...ParameterWithDependencyInTransientScope.cs | 4 +- Test/CustomEmbedding/FactoryInContainercs.cs | 2 +- Test/CustomEmbedding/FactoryInScope.cs | 4 +- .../FactoryInTransientScope.cs | 4 +- .../FactoryWithParameterInContainercs.cs | 2 +- .../FactoryWithParameterInScope.cs | 4 +- .../FactoryWithParameterInTransientScope.cs | 4 +- Test/CustomEmbedding/FieldInContainercs.cs | 2 +- Test/CustomEmbedding/FieldInScope.cs | 4 +- Test/CustomEmbedding/FieldInTransientScope.cs | 4 +- Test/CustomEmbedding/PropertyInContainercs.cs | 2 +- Test/CustomEmbedding/PropertyInScope.cs | 4 +- .../PropertyInTransientScope.cs | 4 +- .../Cycle/DirectRecursionContainer.cs | 2 +- .../Function/Cycle/DirectRecursionScope.cs | 2 +- .../Cycle/DirectRecursionTransientScope.cs | 2 +- .../NoCycle/DirectRecursionContainerFunc.cs | 2 +- .../NoCycle/DirectRecursionContainerLazy.cs | 2 +- .../NoCycle/DirectRecursionScopeFunc.cs | 2 +- .../NoCycle/DirectRecursionScopeLazy.cs | 2 +- .../DirectRecursionTransientScopeFunc.cs | 2 +- .../DirectRecursionTransientScopeLazy.cs | 2 +- .../Implementation/Cycle/DirectRecursion.cs | 2 +- .../Cycle/ImplementationProxied.cs | 2 +- .../NoCycle/NoCycleInParallel.cs | 2 +- Test/Decorator/ContainerInstance.cs | 2 +- Test/Decorator/List.cs | 2 +- Test/Decorator/Multi.cs | 2 +- Test/Decorator/Normal.cs | 2 +- .../ScopeDecoratorForContainerDependency.cs | 2 +- ...opeDecoratorForTransientScopeDependency.cs | 2 +- Test/Decorator/SequenceEdgeCase.cs | 6 +- Test/Disposal/Async/InContainer.cs | 2 +- Test/Disposal/Async/InScope.cs | 2 +- .../Disposal/Async/InScopeInTransientScope.cs | 2 +- Test/Disposal/Async/InTransientScope.cs | 2 +- .../Async/InTransientScopeInTransientScope.cs | 2 +- .../ContainerUserDefinedAddForDisposal.cs | 2 +- ...ContainerUserDefinedAddForDisposalAsync.cs | 2 +- .../ScopeUserDefinedAddForDisposal.cs | 4 +- .../ScopeUserDefinedAddForDisposalAsync.cs | 6 +- Test/Disposal/Sync/InContainer.cs | 2 +- Test/Disposal/Sync/InScope.cs | 2 +- Test/Disposal/Sync/InScopeInTransientScope.cs | 2 +- Test/Disposal/Sync/InTransientScope.cs | 2 +- .../Sync/InTransientScopeInTransientScope.cs | 2 +- .../AsyncContainerToAsyncDisposalHandle.cs | 2 +- .../NoneContainerToAsyncDisposalHandle.cs | 2 +- .../NoneContainerToSyncDisposalHandle.cs | 2 +- .../SyncContainerToAsyncDisposalHandle.cs | 2 +- .../SyncContainerToSyncDisposalHandle.cs | 2 +- ...TransientScopeUserDefinedAddForDisposal.cs | 4 +- ...ientScopeUserDefinedAddForDisposalAsync.cs | 6 +- Test/Func/Double.cs | 2 +- Test/Func/Vanilla.cs | 2 +- Test/Generics/Choice/Double.cs | 2 +- Test/Generics/Choice/DoubleBothChosen.cs | 2 +- ...ubleBothChosenWithSingleOtherSubstitute.cs | 2 +- .../Choice/DoubleWithSingleOtherSubstitute.cs | 2 +- Test/Generics/Choice/Single.cs | 2 +- .../Choice/SingleWithSingleOtherSubstitute.cs | 2 +- .../Double.cs | 2 +- .../Single.cs | 2 +- Test/Generics/Configuration/AsyncTransient.cs | 2 +- .../AsyncTransientWithJustTransient.cs | 2 +- Test/Generics/Configuration/Composite.cs | 2 +- .../Configuration/ConstructorChoice.cs | 2 +- .../Configuration/ContainerInstance.cs | 2 +- ...erInstanceWithDifferentGenericParameter.cs | 2 +- Test/Generics/Configuration/Decorator.cs | 2 +- .../InitializerImplementationAsync.cs | 2 +- .../InitializerImplementationAsyncValue.cs | 2 +- .../InitializerImplementationSync.cs | 2 +- .../InitializerInterfaceAsync.cs | 2 +- .../InitializerInterfaceAsyncValue.cs | 2 +- .../Configuration/InitializerInterfaceSync.cs | 2 +- .../InterfaceGenericComposite.cs | 2 +- .../InterfaceGenericDecorator.cs | 2 +- Test/Generics/Configuration/ScopeInstance.cs | 2 +- ...peInstanceWithDifferentGenericParameter.cs | 2 +- Test/Generics/Configuration/ScopeRoot.cs | 2 +- Test/Generics/Configuration/SyncTransient.cs | 2 +- .../SyncTransientWithJustTransient.cs | 2 +- .../Configuration/TransientScopeInstance.cs | 2 +- ...peInstanceWithDifferentGenericParameter.cs | 2 +- .../Configuration/TransientScopeRoot.cs | 2 +- Test/Generics/Implementation/Double.cs | 2 +- Test/Generics/Implementation/Single.cs | 2 +- Test/Generics/Interface/Double.cs | 2 +- Test/Generics/Interface/DoubleAndOneFixed.cs | 2 +- Test/Generics/Interface/DoubleAndSetToSame.cs | 2 +- Test/Generics/Interface/DoubleSwitched.cs | 2 +- Test/Generics/Interface/Single.cs | 2 +- ...eAndBaseImplementationDoubleButOneFixed.cs | 2 +- Test/Generics/SubstituteCollection/Double.cs | 2 +- .../DoubleBothSubstituted.cs | 2 +- .../DoubleBothSubstitutedWithChoice.cs | 2 +- .../SubstituteCollection/DoubleWithChoice.cs | 2 +- Test/Generics/SubstituteCollection/Single.cs | 2 +- .../SubstituteCollection/SingleWithChoice.cs | 2 +- .../SubstituteCollection/TripleInsanity.cs | 2 +- .../AssemblyImplementationsAggregation.cs | 2 +- .../Aggregation/ExternalType.cs | 2 +- .../Aggregation/FilterAllImplementations.cs | 2 +- .../Aggregation/InternalsVisibleTo.cs | 2 +- Test/Implementation/Choice/Collection.cs | 2 +- .../Choice/CollectionWithoutChoice.cs | 2 +- .../Choice/SingleInCollection.cs | 2 +- Test/Implementation/Choice/Vanilla.cs | 2 +- .../Choice/VanillaWithoutChoice.cs | 2 +- .../Choice/WithSingleInCollection.cs | 2 +- Test/InitProperty/Vanilla.cs | 2 +- Test/Lazy/Vanilla.cs | 2 +- .../NonOptional/MultipleImplementations.cs | 2 +- .../NonOptional/NoImplementation.cs | 2 +- .../Optional/MultipleImplementations.cs | 2 +- Test/Nullability/Optional/NoImplementation.cs | 2 +- Test/Record/CustomProperty.cs | 2 +- Test/Record/PrimaryConstr.cs | 2 +- Test/Record/Vanilla.cs | 2 +- Test/Scoping/InScope.cs | 2 +- .../ScopeSpecificAttributes/Decorator.cs | 10 +- .../ScopeSpecificAttributes/Implementation.cs | 7 +- .../ImplementationCollection.cs | 6 +- .../TransientScopeInstance/InContainer.cs | 2 +- .../Scoping/TransientScopeInstance/InScope.cs | 2 +- .../TransientScopeInstance/InScopeInScope.cs | 2 +- .../InTransientScope.cs | 2 +- .../InTransientScopeWithScopes.cs | 2 +- Test/Struct/NoExplicitConstructor.cs | 2 +- Test/Struct/OneExplicitConstructor.cs | 2 +- Test/Struct/RecordNoExplicitConstructor.cs | 2 +- Test/Struct/RecordOneExplicitConstructor.cs | 2 +- Test/TypeInitializer/AsyncTask.cs | 2 +- Test/TypeInitializer/AsyncValueTask.cs | 2 +- Test/TypeInitializer/Sync.cs | 2 +- Test/ValueTuple/NonSyntaxVariant.cs | 2 +- Test/ValueTuple/NonSyntaxVariantSingleItem.cs | 2 +- Test/ValueTuple/SyntaxVariant.cs | 2 +- Test/ValueTuple/ValueTupleTests.cs | 2 +- 213 files changed, 1269 insertions(+), 298 deletions(-) create mode 100644 Main/Diagnostics.cs create mode 100644 Main/Validation/Range/UserDefined/ValidateUserDefinedAddForDisposal.cs create mode 100644 Main/Validation/Range/UserDefined/ValidateUserDefinedConstrParamMethod.cs create mode 100644 Main/Validation/Range/UserDefined/ValidateUserDefinedFactoryField.cs create mode 100644 Main/Validation/Range/UserDefined/ValidateUserDefinedFactoryMethod.cs create mode 100644 Main/Validation/Range/UserDefined/ValidateUserDefinedMethod.cs create mode 100644 Main/Validation/Range/ValidateContainer.cs create mode 100644 Main/Validation/Range/ValidateRange.cs create mode 100644 Main/Validation/Range/ValidateScope.cs create mode 100644 Main/Validation/Range/ValidateScopeBase.cs create mode 100644 Main/Validation/Range/ValidateTransientScope.cs diff --git a/Main/Constants.cs b/Main/Constants.cs index 39bcba16..7ca4a800 100644 --- a/Main/Constants.cs +++ b/Main/Constants.cs @@ -2,9 +2,20 @@ namespace MrMeeseeks.DIE; internal static class Constants { + internal const string DieAbbreviation = "DIE"; internal const string ThisKeyword = "this"; - internal const string DefaultScopeName = "DIE_DefaultScope"; - internal const string CustomScopeName = "DIE_Scope"; - internal const string DefaultTransientScopeName = "DIE_DefaultTransientScope"; - internal const string CustomTransientScopeName = "DIE_TransientScope"; + + // Ranges + internal const string ScopeName = "Scope"; + internal const string DefaultScopeName = $"{DieAbbreviation}_Default{ScopeName}"; + internal const string CustomScopeName = $"{DieAbbreviation}_{ScopeName}"; + internal const string TransientScopeName = "TransientScope"; + internal const string DefaultTransientScopeName = $"{DieAbbreviation}_Default{TransientScopeName}"; + internal const string CustomTransientScopeName = $"{DieAbbreviation}_{TransientScopeName}"; + + // User-defined scope elements + internal const string UserDefinedFactory = $"{DieAbbreviation}_Factory"; + internal const string UserDefinedConstructorParameters = $"{DieAbbreviation}_ConstrParam"; + internal const string UserDefinedAddForDisposal = $"{DieAbbreviation}_AddForDisposal"; + internal const string UserDefinedAddForDisposalAsync = $"{DieAbbreviation}_AddForDisposalAsync"; } \ No newline at end of file diff --git a/Main/DiagLogger.cs b/Main/DiagLogger.cs index 66b8ad8a..15321ff0 100644 --- a/Main/DiagLogger.cs +++ b/Main/DiagLogger.cs @@ -7,13 +7,22 @@ internal interface IDiagLogger void Log(int id, string title, string message, string category, DiagnosticSeverity diagnosticSeverity); void Error(DieException exception); + + void Log(Diagnostic diagnostic); } internal class DiagLogger : IDiagLogger { + private readonly bool _ignoreErrors; private readonly GeneratorExecutionContext _context; - internal DiagLogger(GeneratorExecutionContext context) => _context = context; + internal DiagLogger( + bool ignoreErrors, + GeneratorExecutionContext context) + { + _ignoreErrors = ignoreErrors; + _context = context; + } public void Log(int id, string title, string message, string category, DiagnosticSeverity diagnosticSeverity) => _context.ReportDiagnostic(Diagnostic.Create( @@ -26,4 +35,10 @@ public void Error(DieException exception) => _context.ReportDiagnostic(Diagnostic.Create( new DiagnosticDescriptor($"DIE{69.ToString().PadLeft(3, '0')}", "Error", "Circular implementation references", "Error", DiagnosticSeverity.Error, true), Location.None)); + + public void Log(Diagnostic diagnostic) + { + if (!_ignoreErrors || diagnostic.Severity != DiagnosticSeverity.Error) + _context.ReportDiagnostic(diagnostic); + } } \ No newline at end of file diff --git a/Main/Diagnostics.cs b/Main/Diagnostics.cs new file mode 100644 index 00000000..2396c633 --- /dev/null +++ b/Main/Diagnostics.cs @@ -0,0 +1,57 @@ +namespace MrMeeseeks.DIE; + +public static class Diagnostics +{ + public static Diagnostic CircularReferenceInsideFactory => + Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_68_00", + "Circular Reference Exception (inside factory)", + "This container and/or its configuration lead to a circular reference inside one of its factory functions, which need to be generated.", + "Error", DiagnosticSeverity.Error, + true), + Location.None); + + public static Diagnostic CircularReferenceAmongFactories => + Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_68_01", + "Circular Reference Exception (among factories)", + "This container and/or its configuration lead to a circular reference among factory functions, which need to be generated.", + "Error", DiagnosticSeverity.Error, + true), + Location.None); + + public static Diagnostic ValidationContainer(INamedTypeSymbol container, string specification) => + Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_67_00", + "Validation (Container)", + $"The Container \"{container.Name}\" isn't validly defined: {specification}", + "Error", DiagnosticSeverity.Error, + true), + container.Locations.FirstOrDefault() ?? Location.None); + + public static Diagnostic ValidationTransientScope(INamedTypeSymbol transientScope, INamedTypeSymbol parentContainer, string specification) => + Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_67_01", + "Validation (TransientScope)", + $"The TransientScope \"{transientScope.Name}\" (of parent-Container \"{parentContainer.Name}\") isn't validly defined: {specification}", + "Error", DiagnosticSeverity.Error, + true), + transientScope.Locations.FirstOrDefault() ?? Location.None); + + public static Diagnostic ValidationScope(INamedTypeSymbol scope, INamedTypeSymbol parentContainer, string specification) => + Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_67_02", + "Validation (Scope)", + $"The Scope \"{scope.Name}\" (of parent-Container \"{parentContainer.Name}\") isn't validly defined: {specification}", + "Error", DiagnosticSeverity.Error, + true), + scope.Locations.FirstOrDefault() ?? Location.None); + + public static Diagnostic ValidationUserDefinedElement(ISymbol userDefinedElement, INamedTypeSymbol parentRange, INamedTypeSymbol parentContainer, string specification) + { + var rangeDescription = SymbolEqualityComparer.Default.Equals(parentRange, parentContainer) + ? $"parent-Container \"{parentContainer.Name}\"" + : $"Range \"{parentRange.Name}\" in parent-Container \"{parentContainer.Name}\""; + return Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_67_03", + "Validation (User-Defined Element)", + $"The user-defined \"{userDefinedElement.Name}\" (of \"{rangeDescription}) isn't validly defined: {specification}", + "Error", DiagnosticSeverity.Error, + true), + userDefinedElement.Locations.FirstOrDefault() ?? Location.None); + } +} \ No newline at end of file diff --git a/Main/DieException.cs b/Main/DieException.cs index 6b72013a..7067ee9c 100644 --- a/Main/DieException.cs +++ b/Main/DieException.cs @@ -3,7 +3,8 @@ namespace MrMeeseeks.DIE; public enum DieExceptionKind { ImplementationCycle, - FunctionCycle + FunctionCycle, + Validation } public abstract class DieException : Exception @@ -19,4 +20,9 @@ public class ImplementationCycleDieException : DieException public class FunctionCycleDieException : DieException { public override DieExceptionKind Kind => DieExceptionKind.FunctionCycle; +} + +public class ValidationDieException : DieException +{ + public override DieExceptionKind Kind => DieExceptionKind.Validation; } \ No newline at end of file diff --git a/Main/ExecuteImpl.cs b/Main/ExecuteImpl.cs index 0a3a0433..664d0673 100644 --- a/Main/ExecuteImpl.cs +++ b/Main/ExecuteImpl.cs @@ -1,6 +1,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using MrMeeseeks.DIE.CodeBuilding; using MrMeeseeks.DIE.ResolutionBuilding; +using MrMeeseeks.DIE.Validation.Range; namespace MrMeeseeks.DIE; @@ -11,32 +12,38 @@ internal interface IExecute internal class ExecuteImpl : IExecute { + private readonly bool _errorDescriptionInsteadOfBuildFailure; private readonly GeneratorExecutionContext _context; private readonly WellKnownTypesMiscellaneous _wellKnownTypesMiscellaneous; private readonly IContainerGenerator _containerGenerator; private readonly IContainerErrorGenerator _containerErrorGenerator; private readonly IContainerDieExceptionGenerator _containerDieExceptionGenerator; + private readonly IValidateContainer _validateContainer; private readonly Func _containerResolutionBuilderFactory; private readonly IResolutionTreeCreationErrorHarvester _resolutionTreeCreationErrorHarvester; private readonly Func _containerInfoFactory; private readonly IDiagLogger _diagLogger; internal ExecuteImpl( + bool errorDescriptionInsteadOfBuildFailure, GeneratorExecutionContext context, WellKnownTypesMiscellaneous wellKnownTypesMiscellaneous, IContainerGenerator containerGenerator, IContainerErrorGenerator containerErrorGenerator, IContainerDieExceptionGenerator containerDieExceptionGenerator, + IValidateContainer validateContainer, Func containerResolutionBuilderFactory, IResolutionTreeCreationErrorHarvester resolutionTreeCreationErrorHarvester, Func containerInfoFactory, IDiagLogger diagLogger) { + _errorDescriptionInsteadOfBuildFailure = errorDescriptionInsteadOfBuildFailure; _context = context; _wellKnownTypesMiscellaneous = wellKnownTypesMiscellaneous; _containerGenerator = containerGenerator; _containerErrorGenerator = containerErrorGenerator; _containerDieExceptionGenerator = containerDieExceptionGenerator; + _validateContainer = validateContainer; _containerResolutionBuilderFactory = containerResolutionBuilderFactory; _resolutionTreeCreationErrorHarvester = resolutionTreeCreationErrorHarvester; _containerInfoFactory = containerInfoFactory; @@ -47,9 +54,6 @@ public void Execute() { _diagLogger.Log("Start Execute"); - var errorDescriptionInsteadOfBuildFailure = _context.Compilation.Assembly.GetAttributes() - .Any(ad => _wellKnownTypesMiscellaneous.ErrorDescriptionInsteadOfBuildFailureAttribute.Equals(ad.AttributeClass, SymbolEqualityComparer.Default)); - foreach (var syntaxTree in _context.Compilation.SyntaxTrees) { var semanticModel = _context.Compilation.GetSemanticModel(syntaxTree); @@ -67,7 +71,9 @@ public void Execute() try { var containerInfo = _containerInfoFactory(containerSymbol); - if (containerInfo.IsValid) + var validationDiagnostics = _validateContainer.Validate(containerInfo.ContainerType, containerInfo.ContainerType) + .ToImmutableArray(); + if (!validationDiagnostics.Any()) { var containerResolutionBuilder = _containerResolutionBuilderFactory(containerInfo); containerResolutionBuilder.AddCreateResolveFunctions(containerInfo.CreateFunctionData); @@ -85,11 +91,17 @@ public void Execute() else _containerGenerator.Generate(containerInfo, containerResolution); } - else throw new NotImplementedException("Handle non-valid container information"); + else + { + foreach (var validationDiagnostic in validationDiagnostics) + _diagLogger.Log(validationDiagnostic); + + throw new ValidationDieException(); + } } catch (DieException dieException) { - if (errorDescriptionInsteadOfBuildFailure) + if (_errorDescriptionInsteadOfBuildFailure) _containerDieExceptionGenerator.Generate( containerSymbol.ContainingNamespace.FullName(), containerSymbol.Name, diff --git a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs index 8c4dd2c1..a688c113 100644 --- a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs @@ -41,12 +41,12 @@ internal ContainerResolutionBuilder( Func rangedFunctionGroupResolutionBuilderFactory, Func synchronicityDecisionMakerFactory, Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory, - IUserProvidedScopeElements userProvidedScopeElement, + IUserDefinedElements userDefinedElement, IFunctionCycleTracker functionCycleTracker) : base( containerInfo.Name, checkTypeProperties, - userProvidedScopeElement, + userDefinedElement, wellKnownTypes, referenceGeneratorFactory, rangedFunctionGroupResolutionBuilderFactory, @@ -81,7 +81,7 @@ public MultiSynchronicityFunctionCallResolution CreateContainerInstanceReference public IFunctionCycleTracker FunctionCycleTracker { get; } public override MultiSynchronicityFunctionCallResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter) => - CreateContainerInstanceReferenceResolution(parameter, "this"); + CreateContainerInstanceReferenceResolution(parameter, Constants.ThisKeyword); public override MultiSynchronicityFunctionCallResolution CreateTransientScopeInstanceReferenceResolution(ForConstructorParameter parameter) => _transientScopeInterfaceResolutionBuilder.CreateTransientScopeInstanceReferenceResolution(parameter, _transientScopeAdapterReference); @@ -95,7 +95,7 @@ public override TransientScopeRootResolution CreateTransientScopeRootResolution( .AddCreateResolveFunction( parameter, rootType, - "this", + Constants.ThisKeyword, currentParameters); public override ScopeRootResolution CreateScopeRootResolution( @@ -107,7 +107,7 @@ public override ScopeRootResolution CreateScopeRootResolution( .AddCreateResolveFunction( parameter, rootType, - "this", + Constants.ThisKeyword, _transientScopeAdapterReference, currentParameters); @@ -160,7 +160,7 @@ public ContainerResolution Build() { var call = createFunction.BuildFunctionCall( Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>(), - "this"); + Constants.ThisKeyword); call.Sync.Await = false; call.AsyncTask.Await = false; call.AsyncValueTask.Await = false; @@ -181,7 +181,7 @@ public ContainerResolution Build() var wrappedTaskReference = RootReferenceGenerator.Generate(_wellKnownTypes.Task); var taskCall = createFunction.BuildFunctionCall( Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>(), - "this"); + Constants.ThisKeyword); taskCall.Sync.Await = false; taskCall.AsyncTask.Await = false; taskCall.AsyncValueTask.Await = false; @@ -205,7 +205,7 @@ public ContainerResolution Build() var wrappedValueTaskReference = RootReferenceGenerator.Generate(_wellKnownTypes.Task); var valueTaskCall = createFunction.BuildFunctionCall( Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>(), - "this"); + Constants.ThisKeyword); valueTaskCall.Sync.Await = false; valueTaskCall.AsyncTask.Await = false; valueTaskCall.AsyncValueTask.Await = false; @@ -228,7 +228,7 @@ public ContainerResolution Build() { var call = createFunction.BuildFunctionCall( Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>(), - "this"); + Constants.ThisKeyword); call.Sync.Await = false; call.AsyncTask.Await = false; call.AsyncValueTask.Await = false; @@ -249,7 +249,7 @@ public ContainerResolution Build() var wrappedValueTaskReference = RootReferenceGenerator.Generate(_wellKnownTypes.Task); var valueCall = createFunction.BuildFunctionCall( Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>(), - "this"); + Constants.ThisKeyword); valueCall.Sync.Await = false; valueCall.AsyncTask.Await = false; valueCall.AsyncValueTask.Await = false; @@ -276,7 +276,7 @@ public ContainerResolution Build() .FullName(); var call = createFunction.BuildFunctionCall( Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>(), - "this"); + Constants.ThisKeyword); call.Sync.Await = false; call.AsyncTask.Await = false; call.AsyncValueTask.Await = false; @@ -296,7 +296,7 @@ public ContainerResolution Build() var valueCall = createFunction.BuildFunctionCall( Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>(), - "this"); + Constants.ThisKeyword); valueCall.Sync.Await = false; valueCall.AsyncTask.Await = false; valueCall.AsyncValueTask.Await = false; diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs index 89646652..bb669e0a 100644 --- a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs @@ -61,7 +61,7 @@ internal abstract partial class FunctionResolutionBuilder : IFunctionResolutionB protected readonly IReferenceGenerator RootReferenceGenerator; - private readonly IUserProvidedScopeElements _userProvidedScopeElements; + private readonly IUserDefinedElements _userDefinedElements; private readonly FunctionResolutionBuilderHandle _handle; @@ -96,7 +96,7 @@ internal FunctionResolutionBuilder( _wellKnownTypes = wellKnownTypes; _functionCycleTracker = functionCycleTracker; _checkTypeProperties = rangeResolutionBaseBuilder.CheckTypeProperties; - _userProvidedScopeElements = rangeResolutionBaseBuilder.UserProvidedScopeElements; + _userDefinedElements = rangeResolutionBaseBuilder.UserDefinedElements; _handle = new FunctionResolutionBuilderHandle( handleIdentity, $"{OriginalReturnType.FullName()}({string.Join(", ", currentParameters.Select(p => p.Resolution.TypeFullName))})"); @@ -115,7 +115,7 @@ internal FunctionResolutionBuilder( if (currentFuncParameters.FirstOrDefault(t => SymbolEqualityComparer.Default.Equals(t.Type.OriginalDefinition, type.OriginalDefinition)) is { Type: not null, Resolution: not null } funcParameter) return (funcParameter.Resolution, null); - if (_userProvidedScopeElements.GetInstanceFor(type) is { } instance) + if (_userDefinedElements.GetInstanceFor(type) is { } instance) return ( new FieldResolution( RootReferenceGenerator.Generate(instance.Type), @@ -123,7 +123,7 @@ internal FunctionResolutionBuilder( instance.Name), null); - if (_userProvidedScopeElements.GetPropertyFor(type) is { } property) + if (_userDefinedElements.GetPropertyFor(type) is { } property) return ( new FieldResolution( RootReferenceGenerator.Generate(property.Type), @@ -131,7 +131,7 @@ internal FunctionResolutionBuilder( property.Name), null); - if (_userProvidedScopeElements.GetFactoryFor(type) is { } factory) + if (_userDefinedElements.GetFactoryFor(type) is { } factory) return ( new FactoryResolution( RootReferenceGenerator.Generate(factory.ReturnType), @@ -696,7 +696,7 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup var outParameters = ImmutableDictionary.Empty; ConstructorParameterChoiceResolution? constructorParameterChoiceResolution = null; - if (_userProvidedScopeElements.GetCustomConstructorParameterChoiceFor(implementationType) is + if (_userDefinedElements.GetCustomConstructorParameterChoiceFor(implementationType) is { } parameterChoiceMethod) { constructorParameterChoiceResolution = new ConstructorParameterChoiceResolution( diff --git a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs index 69b9089e..031a2222 100644 --- a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs +++ b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs @@ -6,7 +6,7 @@ namespace MrMeeseeks.DIE.ResolutionBuilding; internal interface IRangeResolutionBaseBuilder { ICheckTypeProperties CheckTypeProperties { get; } - IUserProvidedScopeElements UserProvidedScopeElements { get; } + IUserDefinedElements UserDefinedElements { get; } MultiSynchronicityFunctionCallResolution CreateContainerInstanceReferenceResolution( ForConstructorParameter parameter); @@ -37,7 +37,7 @@ IFunctionResolutionBuilder CreateLocalFunctionResolution( internal abstract class RangeResolutionBaseBuilder : IRangeResolutionBaseBuilder { public ICheckTypeProperties CheckTypeProperties { get; } - public IUserProvidedScopeElements UserProvidedScopeElements { get; } + public IUserDefinedElements UserDefinedElements { get; } protected IMethodSymbol? AddForDisposal { get; } protected IMethodSymbol? AddForDisposalAsync { get; } @@ -59,7 +59,7 @@ protected RangeResolutionBaseBuilder( // parameters string name, ICheckTypeProperties checkTypeProperties, - IUserProvidedScopeElements userProvidedScopeElements, + IUserDefinedElements userDefinedElements, // dependencies WellKnownTypes wellKnownTypes, @@ -69,7 +69,7 @@ protected RangeResolutionBaseBuilder( Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) { CheckTypeProperties = checkTypeProperties; - UserProvidedScopeElements = userProvidedScopeElements; + UserDefinedElements = userDefinedElements; _wellKnownTypes = wellKnownTypes; _rangedFunctionGroupResolutionBuilderFactory = rangedFunctionGroupResolutionBuilderFactory; _synchronicityDecisionMakerFactory = synchronicityDecisionMakerFactory; @@ -79,8 +79,8 @@ protected RangeResolutionBaseBuilder( Name = name; - AddForDisposal = userProvidedScopeElements.AddForDisposal; - AddForDisposalAsync = userProvidedScopeElements.AddForDisposalAsync; + AddForDisposal = userDefinedElements.AddForDisposal; + AddForDisposalAsync = userDefinedElements.AddForDisposalAsync; } public abstract MultiSynchronicityFunctionCallResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter); @@ -93,7 +93,7 @@ public MultiSynchronicityFunctionCallResolution CreateScopeInstanceReferenceReso parameter, "Scope", null, - "this", + Constants.ThisKeyword, new (_synchronicityDecisionMakerFactory)); public abstract TransientScopeRootResolution CreateTransientScopeRootResolution( diff --git a/Main/ResolutionBuilding/ScopeManager.cs b/Main/ResolutionBuilding/ScopeManager.cs index e5af1bd3..5038a2f5 100644 --- a/Main/ResolutionBuilding/ScopeManager.cs +++ b/Main/ResolutionBuilding/ScopeManager.cs @@ -26,7 +26,7 @@ private readonly Func< IContainerResolutionBuilder, ITransientScopeInterfaceResolutionBuilder , IScopeManager, - IUserProvidedScopeElements, + IUserDefinedElements, ICheckTypeProperties, IScopeResolutionBuilder> _scopeResolutionBuilderFactory; private readonly Func< @@ -34,12 +34,12 @@ private readonly Func< IContainerResolutionBuilder, ITransientScopeInterfaceResolutionBuilder , IScopeManager, - IUserProvidedScopeElements, + IUserDefinedElements, ICheckTypeProperties, ITransientScopeResolutionBuilder> _transientScopeResolutionBuilderFactory; private readonly Func, ScopeTypesFromAttributes> _scopeTypesFromAttributesFactory; private readonly Func, ICheckTypeProperties> _checkTypePropertiesFactory; - private readonly Func _userProvidedScopeElementsFactory; + private readonly Func _userProvidedScopeElementsFactory; private readonly Lazy _defaultScopeBuilder; private readonly Lazy _defaultTransientScopeBuilder; private readonly IDictionary _customScopeBuilders; @@ -57,7 +57,7 @@ public ScopeManager( IContainerResolutionBuilder, ITransientScopeInterfaceResolutionBuilder , IScopeManager, - IUserProvidedScopeElements, + IUserDefinedElements, ICheckTypeProperties, ITransientScopeResolutionBuilder> transientScopeResolutionBuilderFactory, Func< @@ -65,13 +65,13 @@ public ScopeManager( IContainerResolutionBuilder, ITransientScopeInterfaceResolutionBuilder , IScopeManager, - IUserProvidedScopeElements, + IUserDefinedElements, ICheckTypeProperties, IScopeResolutionBuilder> scopeResolutionBuilderFactory, Func, ScopeTypesFromAttributes> scopeTypesFromAttributesFactory, Func, ICheckTypeProperties> checkTypePropertiesFactory, - Func userProvidedScopeElementsFactory, - IUserProvidedScopeElements emptyUserProvidedScopeElements, + Func userProvidedScopeElementsFactory, + IUserDefinedElements emptyUserDefinedElements, WellKnownTypesMiscellaneous wellKnownTypesMiscellaneous) { _containerResolutionBuilder = containerResolutionBuilder; @@ -94,7 +94,7 @@ public ScopeManager( this, defaultScopeType is {} ? _userProvidedScopeElementsFactory(defaultScopeType) - : emptyUserProvidedScopeElements, + : emptyUserDefinedElements, _checkTypePropertiesFactory(_containerTypesFromAttributesList.Add(defaultScopeTypesFromAttributes))); }, LazyThreadSafetyMode.ExecutionAndPublication); @@ -110,7 +110,7 @@ defaultScopeType is {} this, defaultTransientScopeType is {} ? _userProvidedScopeElementsFactory(defaultTransientScopeType) - : emptyUserProvidedScopeElements, + : emptyUserDefinedElements, _checkTypePropertiesFactory(_containerTypesFromAttributesList.Add(defaultTransientScopeTypesFromAttributes))); _transientScopeInterfaceResolutionBuilder.AddImplementation(ret); return ret; diff --git a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs index b38fff23..2314a710 100644 --- a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs @@ -32,7 +32,7 @@ internal ScopeResolutionBuilder( IContainerResolutionBuilder containerResolutionBuilder, ITransientScopeInterfaceResolutionBuilder transientScopeInterfaceResolutionBuilder, IScopeManager scopeManager, - IUserProvidedScopeElements userProvidedScopeElements, + IUserDefinedElements userDefinedElements, ICheckTypeProperties checkTypeProperties, // dependencies @@ -45,7 +45,7 @@ internal ScopeResolutionBuilder( : base( name, checkTypeProperties, - userProvidedScopeElements, + userDefinedElements, wellKnownTypes, referenceGeneratorFactory, rangedFunctionGroupResolutionBuilderFactory, diff --git a/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs b/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs index dc81e703..04625bde 100644 --- a/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs @@ -29,7 +29,7 @@ internal TransientScopeResolutionBuilder( IContainerResolutionBuilder containerResolutionBuilder, ITransientScopeInterfaceResolutionBuilder transientScopeInterfaceResolutionBuilder, IScopeManager scopeManager, - IUserProvidedScopeElements userProvidedScopeElements, + IUserDefinedElements userDefinedElements, ICheckTypeProperties checkTypeProperties, // dependencies @@ -42,7 +42,7 @@ internal TransientScopeResolutionBuilder( : base( name, checkTypeProperties, - userProvidedScopeElements, + userDefinedElements, wellKnownTypes, referenceGeneratorFactory, rangedFunctionGroupResolutionBuilderFactory, @@ -61,7 +61,7 @@ public override MultiSynchronicityFunctionCallResolution CreateContainerInstance _containerResolutionBuilder.CreateContainerInstanceReferenceResolution(parameter, _containerReference); public override MultiSynchronicityFunctionCallResolution CreateTransientScopeInstanceReferenceResolution(ForConstructorParameter parameter) => - _transientScopeInterfaceResolutionBuilder.CreateTransientScopeInstanceReferenceResolution(parameter, "this"); + _transientScopeInterfaceResolutionBuilder.CreateTransientScopeInstanceReferenceResolution(parameter, Constants.ThisKeyword); public override TransientScopeRootResolution CreateTransientScopeRootResolution( SwitchImplementationParameter parameter, @@ -85,7 +85,7 @@ public override ScopeRootResolution CreateScopeRootResolution( parameter, rootType, _containerReference, - "this", + Constants.ThisKeyword, currentParameters); public override void RegisterDisposalType(DisposalType disposalType) => _containerResolutionBuilder.RegisterDisposalType(disposalType); diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index ecb93f50..05cf4584 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -286,7 +286,7 @@ internal record ContainerResolution( LocalFunctions, DisposalHandling, RangedInstanceFunctionGroups, - "this", + Constants.ThisKeyword, AddForDisposal, AddForDisposalAsync); diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index db0df2ca..31408049 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -2,6 +2,8 @@ using MrMeeseeks.DIE.Configuration; using MrMeeseeks.DIE.ResolutionBuilding; using MrMeeseeks.DIE.ResolutionBuilding.Function; +using MrMeeseeks.DIE.Validation.Range; +using MrMeeseeks.DIE.Validation.Range.UserDefined; namespace MrMeeseeks.DIE; @@ -17,11 +19,45 @@ public void Initialize(GeneratorInitializationContext context) public void Execute(GeneratorExecutionContext context) { - var diagLogger = new DiagLogger(context); var _ = WellKnownTypes.TryCreate(context.Compilation, out var wellKnownTypes); var __ = WellKnownTypesAggregation.TryCreate(context.Compilation, out var wellKnownTypesAggregation); var ___ = WellKnownTypesChoice.TryCreate(context.Compilation, out var wellKnownTypesChoice); var ____ = WellKnownTypesMiscellaneous.TryCreate(context.Compilation, out var wellKnownTypesMiscellaneous); + var errorDescriptionInsteadOfBuildFailure = context.Compilation.Assembly.GetAttributes() + .Any(ad => wellKnownTypesMiscellaneous.ErrorDescriptionInsteadOfBuildFailureAttribute.Equals(ad.AttributeClass, SymbolEqualityComparer.Default)); + var diagLogger = new DiagLogger(errorDescriptionInsteadOfBuildFailure, context); + var validateUserDefinedAddForDisposalSync = new ValidateUserDefinedAddForDisposalSync(wellKnownTypes); + var validateUserDefinedAddForDisposalAsync = new ValidateUserDefinedAddForDisposalAsync(wellKnownTypes); + var validateUserDefinedConstrParam = new ValidateUserDefinedConstrParam(wellKnownTypesChoice); + var validateUserDefinedFactoryField = new ValidateUserDefinedFactoryField(); + var validateUserDefinedFactoryMethod = new ValidateUserDefinedFactoryMethod(); + var validateTransientScope = new ValidateTransientScope( + validateUserDefinedAddForDisposalSync, + validateUserDefinedAddForDisposalAsync, + validateUserDefinedConstrParam, + validateUserDefinedFactoryMethod, + validateUserDefinedFactoryField, + wellKnownTypes, + wellKnownTypesAggregation, + wellKnownTypesMiscellaneous); + var validateScope = new ValidateScope( + validateUserDefinedAddForDisposalSync, + validateUserDefinedAddForDisposalAsync, + validateUserDefinedConstrParam, + validateUserDefinedFactoryMethod, + validateUserDefinedFactoryField, + wellKnownTypes, + wellKnownTypesAggregation, + wellKnownTypesMiscellaneous); + var validateContainer = new ValidateContainer( + validateTransientScope, + validateScope, + validateUserDefinedAddForDisposalSync, + validateUserDefinedAddForDisposalAsync, + validateUserDefinedConstrParam, + validateUserDefinedFactoryMethod, + validateUserDefinedFactoryField, + wellKnownTypes); var attributeTypesFromAttributes = new TypesFromAttributes( context.Compilation.Assembly.GetAttributes(), wellKnownTypesAggregation, @@ -34,11 +70,13 @@ public void Execute(GeneratorExecutionContext context) var resolutionTreeCreationErrorHarvester = new ResolutionTreeCreationErrorHarvester(); var implementationTypeSetCache = new ImplementationTypeSetCache(context, wellKnownTypes); new ExecuteImpl( + errorDescriptionInsteadOfBuildFailure, context, wellKnownTypesMiscellaneous, containerGenerator, containerErrorGenerator, containerDieExceptionGenerator, + validateContainer, ResolutionTreeFactory, resolutionTreeCreationErrorHarvester, ContainerInfoFactory, @@ -68,7 +106,7 @@ IContainerResolutionBuilder ResolutionTreeFactory(IContainerInfo ci) RangedFunctionGroupResolutionBuilderFactory, FunctionResolutionSynchronicityDecisionMakerFactory, LocalFunctionResolutionBuilderFactory, - new UserProvidedScopeElements(ci.ContainerType, wellKnownTypes, wellKnownTypesChoice), + new UserDefinedElements(ci.ContainerType, wellKnownTypes, wellKnownTypesChoice), functionCycleTracker); IScopeManager ScopeManagerFactory( @@ -86,8 +124,8 @@ IScopeManager ScopeManagerFactory( wellKnownTypesChoice, wellKnownTypesMiscellaneous), tfa => new CheckTypeProperties(new CurrentlyConsideredTypes(tfa, implementationTypeSetCache), wellKnownTypes), - st => new UserProvidedScopeElements(st, wellKnownTypes, wellKnownTypesChoice), - new EmptyUserProvidedScopeElements(), + st => new UserDefinedElements(st, wellKnownTypes, wellKnownTypesChoice), + new EmptyUserDefinedElements(), wellKnownTypesMiscellaneous); ITransientScopeResolutionBuilder TransientScopeResolutionBuilderFactory( @@ -95,7 +133,7 @@ ITransientScopeResolutionBuilder TransientScopeResolutionBuilderFactory( IContainerResolutionBuilder containerBuilder, ITransientScopeInterfaceResolutionBuilder transientScopeInterfaceResolutionBuilder, IScopeManager scopeManager, - IUserProvidedScopeElements userProvidedScopeElements, + IUserDefinedElements userProvidedScopeElements, ICheckTypeProperties checkTypeProperties) => new TransientScopeResolutionBuilder( name, containerBuilder, @@ -115,7 +153,7 @@ IScopeResolutionBuilder ScopeResolutionBuilderFactory( IContainerResolutionBuilder containerBuilder, ITransientScopeInterfaceResolutionBuilder transientScopeInterfaceResolutionBuilder, IScopeManager scopeManager, - IUserProvidedScopeElements userProvidedScopeElements, + IUserDefinedElements userProvidedScopeElements, ICheckTypeProperties checkTypeProperties) => new ScopeResolutionBuilder( name, containerBuilder, diff --git a/Main/UserProvidedScopeElements.cs b/Main/UserProvidedScopeElements.cs index 6affeb98..8f90ebee 100644 --- a/Main/UserProvidedScopeElements.cs +++ b/Main/UserProvidedScopeElements.cs @@ -1,6 +1,6 @@ namespace MrMeeseeks.DIE; -internal interface IUserProvidedScopeElements +internal interface IUserDefinedElements { IFieldSymbol? GetInstanceFor(ITypeSymbol type); IPropertySymbol? GetPropertyFor(ITypeSymbol type); @@ -10,7 +10,7 @@ internal interface IUserProvidedScopeElements IMethodSymbol? GetCustomConstructorParameterChoiceFor(INamedTypeSymbol type); } -internal class EmptyUserProvidedScopeElements : IUserProvidedScopeElements +internal class EmptyUserDefinedElements : IUserDefinedElements { public IFieldSymbol? GetInstanceFor(ITypeSymbol type) => null; public IPropertySymbol? GetPropertyFor(ITypeSymbol type) => null; @@ -20,14 +20,14 @@ internal class EmptyUserProvidedScopeElements : IUserProvidedScopeElements public IMethodSymbol? GetCustomConstructorParameterChoiceFor(INamedTypeSymbol type) => null; } -internal class UserProvidedScopeElements : IUserProvidedScopeElements +internal class UserDefinedElements : IUserDefinedElements { private readonly IReadOnlyDictionary _typeToField; private readonly IReadOnlyDictionary _typeToProperty; private readonly IReadOnlyDictionary _typeToMethod; private readonly IReadOnlyDictionary _customConstructorParameterChoiceMethods; - public UserProvidedScopeElements( + public UserDefinedElements( // parameter INamedTypeSymbol scopeType, @@ -36,22 +36,22 @@ public UserProvidedScopeElements( WellKnownTypesChoice wellKnownTypesChoice) { var dieMembers = scopeType.GetMembers() - .Where(s => s.Name.StartsWith("DIE_")) + .Where(s => s.Name.StartsWith($"{Constants.DieAbbreviation}_")) .ToList(); _typeToField = dieMembers - .Where(s => s.Name.StartsWith("DIE_Factory_")) + .Where(s => s.Name.StartsWith(Constants.UserDefinedFactory)) .OfType() .ToDictionary(fs => fs.Type, fs => fs, SymbolEqualityComparer.IncludeNullability); _typeToProperty = dieMembers - .Where(s => s.Name.StartsWith("DIE_Factory_")) + .Where(s => s.Name.StartsWith(Constants.UserDefinedFactory)) .Where(s => s is IPropertySymbol { GetMethod: { } }) .OfType() .ToDictionary(ps => ps.Type, ps => ps, SymbolEqualityComparer.IncludeNullability); _typeToMethod = dieMembers - .Where(s => s.Name.StartsWith("DIE_Factory_")) + .Where(s => s.Name.StartsWith(Constants.UserDefinedFactory)) .Where(s => s is IMethodSymbol { ReturnsVoid: false, Arity: 0, IsConditional: false, MethodKind: MethodKind.Ordinary }) .OfType() .ToDictionary(ps => ps.ReturnType, ps => ps, SymbolEqualityComparer.IncludeNullability); @@ -62,7 +62,7 @@ public UserProvidedScopeElements( DeclaredAccessibility: Accessibility.Private, ReturnsVoid: true, IsPartialDefinition: true, - Name: "DIE_AddForDisposal", + Name: Constants.UserDefinedAddForDisposal, Parameters.Length: 1 } method && SymbolEqualityComparer.Default.Equals(method.Parameters[0].Type, wellKnownTypes.Disposable)) .OfType() @@ -74,14 +74,14 @@ public UserProvidedScopeElements( DeclaredAccessibility: Accessibility.Private, ReturnsVoid: true, IsPartialDefinition: true, - Name: "DIE_AddForDisposalAsync", + Name: Constants.UserDefinedAddForDisposalAsync, Parameters.Length: 1 } method && SymbolEqualityComparer.Default.Equals(method.Parameters[0].Type, wellKnownTypes.AsyncDisposable)) .OfType() .FirstOrDefault(); _customConstructorParameterChoiceMethods = dieMembers - .Where(s => s.Name.StartsWith("DIE_ConstrParam_")) + .Where(s => s.Name.StartsWith(Constants.UserDefinedConstructorParameters)) .Where(s => s is IMethodSymbol { ReturnsVoid: true, Arity: 0, IsConditional: false, MethodKind: MethodKind.Ordinary } method && method.Parameters.Any(p => p.RefKind == RefKind.Out)) .OfType() diff --git a/Main/Validation/Range/UserDefined/ValidateUserDefinedAddForDisposal.cs b/Main/Validation/Range/UserDefined/ValidateUserDefinedAddForDisposal.cs new file mode 100644 index 00000000..9d7d001b --- /dev/null +++ b/Main/Validation/Range/UserDefined/ValidateUserDefinedAddForDisposal.cs @@ -0,0 +1,104 @@ +namespace MrMeeseeks.DIE.Validation.Range.UserDefined; + +internal interface IValidateUserDefinedAddForDisposalSync : IValidateUserDefinedAddForDisposalBase +{ + +} + +internal class ValidateUserDefinedAddForDisposalSync : ValidateUserDefinedAddForDisposalBase, + IValidateUserDefinedAddForDisposalSync +{ + + public ValidateUserDefinedAddForDisposalSync(WellKnownTypes wellKnownTypes) => + DisposableType = wellKnownTypes.Disposable; + + protected override INamedTypeSymbol DisposableType { get; } +} + +internal interface IValidateUserDefinedAddForDisposalAsync : IValidateUserDefinedAddForDisposalBase +{ + +} + +internal class ValidateUserDefinedAddForDisposalAsync : ValidateUserDefinedAddForDisposalBase, + IValidateUserDefinedAddForDisposalAsync +{ + + public ValidateUserDefinedAddForDisposalAsync(WellKnownTypes wellKnownTypes) => + DisposableType = wellKnownTypes.AsyncDisposable; + + protected override INamedTypeSymbol DisposableType { get; } +} + +internal interface IValidateUserDefinedAddForDisposalBase : IValidateUserDefinedMethod +{ + +} + +internal abstract class ValidateUserDefinedAddForDisposalBase : ValidateUserDefinedMethod, IValidateUserDefinedAddForDisposalBase +{ + protected abstract INamedTypeSymbol DisposableType { get; } + + public override IEnumerable Validate(IMethodSymbol method, INamedTypeSymbol rangeType, INamedTypeSymbol containerType) + { + foreach (var diagnostic in base.Validate(method, rangeType, containerType)) + yield return diagnostic; + + if (method is + { + ReturnsVoid: true, + IsPartialDefinition: true, + Parameters.Length: 1, + MethodKind: MethodKind.Ordinary, + CanBeReferencedByName: true + } + && method.Parameters[0] is + { + IsDiscard: false, + IsOptional: false, + IsParams: false, + IsThis: false, + RefKind: RefKind.None, + HasExplicitDefaultValue: false + } + && SymbolEqualityComparer.Default.Equals(method.Parameters[0].Type, DisposableType)) + { + } + + if (!method.ReturnsVoid) + yield return ValidationErrorDiagnostic(method, rangeType, containerType, "Isn't allowed to have a return type."); + + if (!method.IsPartialDefinition) + yield return ValidationErrorDiagnostic(method, rangeType, containerType, "User-defined part has to have the partial definition only."); + + if (method.Parameters.Length != 1 || !SymbolEqualityComparer.Default.Equals(method.Parameters[0].Type.OriginalDefinition, DisposableType.OriginalDefinition)) + yield return ValidationErrorDiagnostic(method, rangeType, containerType, $"Has to have a single parameter which is of type \"{DisposableType.FullName()}\"."); + + if (method.MethodKind != MethodKind.Ordinary) + yield return ValidationErrorDiagnostic(method, rangeType, containerType, "Has to be an ordinary method."); + + if (!method.CanBeReferencedByName) + yield return ValidationErrorDiagnostic(method, rangeType, containerType, "Should be able to be referenced by name."); + + if (method.Parameters.Length == 1 && method.Parameters[0] is {} parameter) + { + if (parameter.IsDiscard) + yield return ValidationErrorDiagnostic(method, rangeType, containerType, "Parameter isn't allowed to be discard parameter."); + + if (parameter.IsOptional) + yield return ValidationErrorDiagnostic(method, rangeType, containerType, "Parameter isn't allowed to be optional."); + + if (parameter.IsParams) + yield return ValidationErrorDiagnostic(method, rangeType, containerType, "Parameter isn't allowed to be params parameter."); + + if (parameter.IsThis) + yield return ValidationErrorDiagnostic(method, rangeType, containerType, "Parameter isn't allowed to be this parameter."); + + if (parameter.RefKind != RefKind.None) + yield return ValidationErrorDiagnostic(method, rangeType, containerType, "Parameter isn't allowed to be of a special ref kind."); + + if (parameter.HasExplicitDefaultValue) + yield return ValidationErrorDiagnostic(method, rangeType, containerType, "Parameter isn't allowed to have explicit default value."); + } + } +} \ No newline at end of file diff --git a/Main/Validation/Range/UserDefined/ValidateUserDefinedConstrParamMethod.cs b/Main/Validation/Range/UserDefined/ValidateUserDefinedConstrParamMethod.cs new file mode 100644 index 00000000..5e9cf1a5 --- /dev/null +++ b/Main/Validation/Range/UserDefined/ValidateUserDefinedConstrParamMethod.cs @@ -0,0 +1,82 @@ +namespace MrMeeseeks.DIE.Validation.Range.UserDefined; + +internal interface IValidateUserDefinedConstrParam : IValidateUserDefinedMethod +{ + +} + +internal class ValidateUserDefinedConstrParam : ValidateUserDefinedMethod, IValidateUserDefinedConstrParam +{ + private readonly WellKnownTypesChoice _wellKnownTypesChoice; + + internal ValidateUserDefinedConstrParam(WellKnownTypesChoice wellKnownTypesChoice) + { + _wellKnownTypesChoice = wellKnownTypesChoice; + } + + public override IEnumerable Validate(IMethodSymbol method, INamedTypeSymbol rangeType, INamedTypeSymbol containerType) + { + foreach (var diagnostic in base.Validate(method, rangeType, containerType)) + yield return diagnostic; + + if (method is + { + Parameters.Length: > 0, + IsPartialDefinition: false, + ReturnsVoid: true, + MethodKind: MethodKind.Ordinary, + CanBeReferencedByName: true + } + && method.Parameters.All(p => p is + { + IsDiscard: false, + IsOptional: false, + IsParams: false, + IsThis: false, + RefKind: RefKind.None or RefKind.Out, + HasExplicitDefaultValue: false + }) + && method.Parameters.Any(p => p.RefKind == RefKind.Out)) + { + } + + if (!method.Parameters.Any(p => p.RefKind == RefKind.Out)) + yield return ValidationErrorDiagnostic(method, rangeType, containerType, "Has to have at least one out parameter."); + + if (method.IsPartialDefinition) + yield return ValidationErrorDiagnostic(method, rangeType, containerType, "Isn't allowed to be partial."); + + if (!method.ReturnsVoid) + yield return ValidationErrorDiagnostic(method, rangeType, containerType, "Isn't allowed to have a return type."); + + if (method.Parameters.Any(p => p.IsDiscard)) + yield return ValidationErrorDiagnostic(method, rangeType, containerType, "Isn't allowed to have a discard parameter."); + + if (method.Parameters.Any(p => p.IsOptional)) + yield return ValidationErrorDiagnostic(method, rangeType, containerType, "Isn't allowed to have a optional parameter."); + + if (method.Parameters.Any(p => p.IsParams)) + yield return ValidationErrorDiagnostic(method, rangeType, containerType, "Isn't allowed to have a params parameter."); + + if (method.Parameters.Any(p => p.IsThis)) + yield return ValidationErrorDiagnostic(method, rangeType, containerType, "Isn't allowed to have a this parameter."); + + if (method.Parameters.Any(p => p.RefKind != RefKind.None && p.RefKind != RefKind.Out)) + yield return ValidationErrorDiagnostic(method, rangeType, containerType, "All parameters should be either ordinary or an out parameter."); + + if (method.Parameters.Any(p => p.HasExplicitDefaultValue)) + yield return ValidationErrorDiagnostic(method, rangeType, containerType, "Isn't allowed to have a parameter which has an explicit default value."); + + if (method.MethodKind != MethodKind.Ordinary) + yield return ValidationErrorDiagnostic(method, rangeType, containerType, "Has to be an ordinary method."); + + if (!method.CanBeReferencedByName) + yield return ValidationErrorDiagnostic(method, rangeType, containerType, "Should be able to be referenced by name."); + + if (method + .GetAttributes() + .Count(ad => SymbolEqualityComparer.Default.Equals(ad.AttributeClass, _wellKnownTypesChoice.CustomConstructorParameterChoiceAttribute)) + != 1) + yield return ValidationErrorDiagnostic(method, rangeType, containerType, $"Has to have exactly one attribute of type \"{_wellKnownTypesChoice.CustomConstructorParameterChoiceAttribute.FullName()}\"."); + } +} \ No newline at end of file diff --git a/Main/Validation/Range/UserDefined/ValidateUserDefinedFactoryField.cs b/Main/Validation/Range/UserDefined/ValidateUserDefinedFactoryField.cs new file mode 100644 index 00000000..9e336dbb --- /dev/null +++ b/Main/Validation/Range/UserDefined/ValidateUserDefinedFactoryField.cs @@ -0,0 +1,33 @@ +namespace MrMeeseeks.DIE.Validation.Range.UserDefined; + +internal interface IValidateUserDefinedFactoryField +{ + IEnumerable Validate(IFieldSymbol field, INamedTypeSymbol rangeType, INamedTypeSymbol containerType); +} + +internal class ValidateUserDefinedFactoryField : IValidateUserDefinedFactoryField +{ + public IEnumerable Validate(IFieldSymbol field, INamedTypeSymbol rangeType, INamedTypeSymbol containerType) + { + if (field is + { + DeclaredAccessibility: Accessibility.Private, + IsStatic: false, + IsImplicitlyDeclared: false + }) + { + } + + if (field.DeclaredAccessibility != Accessibility.Private) + yield return ValidationErrorDiagnostic(field, rangeType, containerType, "Has to be private."); + + if (field.IsStatic) + yield return ValidationErrorDiagnostic(field, rangeType, containerType, "Isn't allowed to be static."); + + if (field.IsImplicitlyDeclared) + yield return ValidationErrorDiagnostic(field, rangeType, containerType, "Isn't allowed to be implicitly declared."); + } + + protected static Diagnostic ValidationErrorDiagnostic(IFieldSymbol field, INamedTypeSymbol rangeType, INamedTypeSymbol container, string specification) => + Diagnostics.ValidationUserDefinedElement(field, rangeType, container, specification); +} \ No newline at end of file diff --git a/Main/Validation/Range/UserDefined/ValidateUserDefinedFactoryMethod.cs b/Main/Validation/Range/UserDefined/ValidateUserDefinedFactoryMethod.cs new file mode 100644 index 00000000..63a23d70 --- /dev/null +++ b/Main/Validation/Range/UserDefined/ValidateUserDefinedFactoryMethod.cs @@ -0,0 +1,60 @@ +namespace MrMeeseeks.DIE.Validation.Range.UserDefined; + +internal interface IValidateUserDefinedFactoryMethod : IValidateUserDefinedMethod +{ + +} + +internal class ValidateUserDefinedFactoryMethod : ValidateUserDefinedMethod, IValidateUserDefinedFactoryMethod +{ + public override IEnumerable Validate(IMethodSymbol method, INamedTypeSymbol rangeType, INamedTypeSymbol containerType) + { + foreach (var diagnostic in base.Validate(method, rangeType, containerType)) + yield return diagnostic; + + if (method is + { + IsPartialDefinition: false, + ReturnsVoid: false, + MethodKind: MethodKind.Ordinary or MethodKind.PropertyGet + } + && method.Parameters.All(p => p is + { + IsDiscard: false, + IsOptional: false, + IsParams: false, + IsThis: false, + RefKind: RefKind.None, + HasExplicitDefaultValue: false + })) + { + } + + if (method.IsPartialDefinition) + yield return ValidationErrorDiagnostic(method, rangeType, containerType, "Isn't allowed to be partial."); + + if (method.ReturnsVoid) + yield return ValidationErrorDiagnostic(method, rangeType, containerType, "Isn't allowed to return void."); + + if (method.Parameters.Any(p => p.IsDiscard)) + yield return ValidationErrorDiagnostic(method, rangeType, containerType, "Isn't allowed to have a discard parameter."); + + if (method.Parameters.Any(p => p.IsOptional)) + yield return ValidationErrorDiagnostic(method, rangeType, containerType, "Isn't allowed to have a optional parameter."); + + if (method.Parameters.Any(p => p.IsParams)) + yield return ValidationErrorDiagnostic(method, rangeType, containerType, "Isn't allowed to have a params parameter."); + + if (method.Parameters.Any(p => p.IsThis)) + yield return ValidationErrorDiagnostic(method, rangeType, containerType, "Isn't allowed to have a this parameter."); + + if (method.Parameters.Any(p => p.RefKind != RefKind.None)) + yield return ValidationErrorDiagnostic(method, rangeType, containerType, "All parameters should be either ordinary or an out parameter."); + + if (method.Parameters.Any(p => p.HasExplicitDefaultValue)) + yield return ValidationErrorDiagnostic(method, rangeType, containerType, "Isn't allowed to have a parameter which has an explicit default value."); + + if (method.MethodKind != MethodKind.Ordinary && method.MethodKind != MethodKind.PropertyGet) + yield return ValidationErrorDiagnostic(method, rangeType, containerType, "Has to be either an ordinary method or a property getter."); + } +} \ No newline at end of file diff --git a/Main/Validation/Range/UserDefined/ValidateUserDefinedMethod.cs b/Main/Validation/Range/UserDefined/ValidateUserDefinedMethod.cs new file mode 100644 index 00000000..1d3695ae --- /dev/null +++ b/Main/Validation/Range/UserDefined/ValidateUserDefinedMethod.cs @@ -0,0 +1,64 @@ +using System.Reflection.Metadata; + +namespace MrMeeseeks.DIE.Validation.Range.UserDefined; + +internal interface IValidateUserDefinedMethod +{ + IEnumerable Validate(IMethodSymbol method, INamedTypeSymbol rangeType, INamedTypeSymbol containerType); +} + +internal abstract class ValidateUserDefinedMethod : IValidateUserDefinedMethod +{ + public virtual IEnumerable Validate(IMethodSymbol method, INamedTypeSymbol rangeType, INamedTypeSymbol containerType) + { + if (method is + { + DeclaredAccessibility: Accessibility.Private, + Arity: 0, + CallingConvention: SignatureCallingConvention.Default, + IsAsync: false, + IsConditional: false, + IsVararg: false, + IsExtensionMethod: false, + IsGenericMethod: false, + IsInitOnly: false, + IsStatic: false, + IsImplicitlyDeclared: false + }) + { + } + + if (method.DeclaredAccessibility != Accessibility.Private) + yield return ValidationErrorDiagnostic(method, rangeType, containerType, "Has to be private."); + + if (method.Arity != 0) + yield return ValidationErrorDiagnostic(method, rangeType, containerType, "Has to have an arity of zero."); + + if (method.CallingConvention != SignatureCallingConvention.Default) + yield return ValidationErrorDiagnostic(method, rangeType, containerType, "Has to have a default calling signature."); + + if (method.IsAsync) + yield return ValidationErrorDiagnostic(method, rangeType, containerType, "Isn't allowed to be async."); + + if (method.IsConditional) + yield return ValidationErrorDiagnostic(method, rangeType, containerType, "Isn't allowed to be marked with the ConditionalAttribute."); + + if (method.IsVararg) + yield return ValidationErrorDiagnostic(method, rangeType, containerType, "Isn't allowed to be CLI VARAG."); + + if (method.IsExtensionMethod) + yield return ValidationErrorDiagnostic(method, rangeType, containerType, "Isn't allowed to be an extension method."); + + if (method.IsInitOnly) + yield return ValidationErrorDiagnostic(method, rangeType, containerType, "Isn't allowed to be an init method."); + + if (method.IsStatic) + yield return ValidationErrorDiagnostic(method, rangeType, containerType, "Isn't allowed to be static."); + + if (method.IsImplicitlyDeclared) + yield return ValidationErrorDiagnostic(method, rangeType, containerType, "Isn't allowed to be implicitly declared."); + } + + protected static Diagnostic ValidationErrorDiagnostic(IMethodSymbol method, INamedTypeSymbol rangeType, INamedTypeSymbol container, string specification) => + Diagnostics.ValidationUserDefinedElement(method, rangeType, container, specification); +} \ No newline at end of file diff --git a/Main/Validation/Range/ValidateContainer.cs b/Main/Validation/Range/ValidateContainer.cs new file mode 100644 index 00000000..3cf87f60 --- /dev/null +++ b/Main/Validation/Range/ValidateContainer.cs @@ -0,0 +1,65 @@ +using MrMeeseeks.DIE.Validation.Range.UserDefined; + +namespace MrMeeseeks.DIE.Validation.Range; + +internal interface IValidateContainer : IValidateRange +{ +} + +internal class ValidateContainer : ValidateRange, IValidateContainer +{ + private readonly IValidateTransientScope _validateTransientScopeFactory; + private readonly IValidateScope _validateScopeFactory; + + internal ValidateContainer( + IValidateTransientScope validateTransientScopeFactory, + IValidateScope validateScopeFactory, + IValidateUserDefinedAddForDisposalSync validateUserDefinedAddForDisposalSync, + IValidateUserDefinedAddForDisposalAsync validateUserDefinedAddForDisposalAsync, + IValidateUserDefinedConstrParam validateUserDefinedConstrParam, + IValidateUserDefinedFactoryMethod validateUserDefinedFactoryMethod, + IValidateUserDefinedFactoryField validateUserDefinedFactoryField, + WellKnownTypes wellKnownTypes) + : base( + validateUserDefinedAddForDisposalSync, + validateUserDefinedAddForDisposalAsync, + validateUserDefinedConstrParam, + validateUserDefinedFactoryMethod, + validateUserDefinedFactoryField, + wellKnownTypes) + { + _validateTransientScopeFactory = validateTransientScopeFactory; + _validateScopeFactory = validateScopeFactory; + } + + public override IEnumerable Validate(INamedTypeSymbol rangeType, INamedTypeSymbol containerType) + { + foreach (var diagnostic in base.Validate(rangeType, containerType)) + yield return diagnostic; + + if (rangeType.GetTypeMembers(Constants.DefaultTransientScopeName, 0).FirstOrDefault() is + { } defaultTransientScope) + foreach (var diagnostic in _validateTransientScopeFactory.Validate(defaultTransientScope, rangeType)) + yield return diagnostic; + + foreach (var customTransientScope in rangeType + .GetTypeMembers() + .Where(nts => nts.Name.StartsWith(Constants.CustomTransientScopeName))) + foreach (var diagnostic in _validateTransientScopeFactory.Validate(customTransientScope, rangeType)) + yield return diagnostic; + + if (rangeType.GetTypeMembers(Constants.DefaultScopeName, 0).FirstOrDefault() is + { } defaultScope) + foreach (var diagnostic in _validateScopeFactory.Validate(defaultScope, rangeType)) + yield return diagnostic; + + foreach (var customScope in rangeType + .GetTypeMembers() + .Where(nts => nts.Name.StartsWith(Constants.CustomScopeName))) + foreach (var diagnostic in _validateScopeFactory.Validate(customScope, rangeType)) + yield return diagnostic; + } + + protected override Diagnostic ValidationErrorDiagnostic(INamedTypeSymbol rangeType, INamedTypeSymbol _, string specification) => + Diagnostics.ValidationContainer(rangeType, specification); +} \ No newline at end of file diff --git a/Main/Validation/Range/ValidateRange.cs b/Main/Validation/Range/ValidateRange.cs new file mode 100644 index 00000000..764b16eb --- /dev/null +++ b/Main/Validation/Range/ValidateRange.cs @@ -0,0 +1,244 @@ +using System.Text.RegularExpressions; +using MrMeeseeks.DIE.Validation.Range.UserDefined; + +namespace MrMeeseeks.DIE.Validation.Range; + +internal interface IValidateRange +{ + IEnumerable Validate(INamedTypeSymbol rangeType, INamedTypeSymbol containerType); +} + +internal abstract class ValidateRange : IValidateRange +{ + private readonly IValidateUserDefinedAddForDisposalSync _validateUserDefinedAddForDisposalSync; + private readonly IValidateUserDefinedAddForDisposalAsync _validateUserDefinedAddForDisposalAsync; + private readonly IValidateUserDefinedConstrParam _validateUserDefinedConstrParam; + private readonly IValidateUserDefinedFactoryMethod _validateUserDefinedFactoryMethod; + private readonly IValidateUserDefinedFactoryField _validateUserDefinedFactoryField; + private readonly WellKnownTypes _wellKnownTypes; + private readonly Regex _generatedMemberNames = new("(_[1-9][0-9]*){2}$"); + + internal ValidateRange( + IValidateUserDefinedAddForDisposalSync validateUserDefinedAddForDisposalSync, + IValidateUserDefinedAddForDisposalAsync validateUserDefinedAddForDisposalAsync, + IValidateUserDefinedConstrParam validateUserDefinedConstrParam, + IValidateUserDefinedFactoryMethod validateUserDefinedFactoryMethod, + IValidateUserDefinedFactoryField validateUserDefinedFactoryField, + WellKnownTypes wellKnownTypes) + { + _validateUserDefinedAddForDisposalSync = validateUserDefinedAddForDisposalSync; + _validateUserDefinedAddForDisposalAsync = validateUserDefinedAddForDisposalAsync; + _validateUserDefinedConstrParam = validateUserDefinedConstrParam; + _validateUserDefinedFactoryMethod = validateUserDefinedFactoryMethod; + _validateUserDefinedFactoryField = validateUserDefinedFactoryField; + _wellKnownTypes = wellKnownTypes; + } + + protected abstract Diagnostic ValidationErrorDiagnostic(INamedTypeSymbol rangeType, INamedTypeSymbol container, string specification); + + public virtual IEnumerable Validate(INamedTypeSymbol rangeType, INamedTypeSymbol containerType) + { + if (rangeType is + { + // What it shouldn't be + IsAbstract: false, + IsExtern: false, + IsComImport: false, + IsImplicitClass: false, + IsUnboundGenericType: false, + IsScriptClass: false, + IsNamespace: false, + IsRecord: false, + IsStatic: false, + IsVirtual: false, + IsAnonymousType: false, + IsTupleType: false, + IsUnmanagedType: false, + IsValueType: false, + IsReadOnly: false, + IsImplicitlyDeclared: false, + IsNativeIntegerType: false, + MightContainExtensionMethods: false, + EnumUnderlyingType: null, + NativeIntegerUnderlyingType: null, + TupleUnderlyingType: null, + + // What it should be + IsType: true, + IsSealed: true, + IsReferenceType: true, + TypeKind: TypeKind.Class, + CanBeReferencedByName: true, + }) + { + if (rangeType + .GetMembers() + .Any(m => _generatedMemberNames.IsMatch(m.Name))) + yield return ValidationErrorDiagnostic(rangeType, containerType, "Isn't allowed to contain user-defined members which match regex \"(_[1-9][0-9]*){2}$\"."); + + if (rangeType + .GetTypeMembers() + .Any(m => _generatedMemberNames.IsMatch(m.Name))) + yield return ValidationErrorDiagnostic(rangeType, containerType, "Isn't allowed to contain user-defined type members which match regex \"(_[1-9][0-9]*){2}$\"."); + + if (rangeType.AllInterfaces.Any(nts => + SymbolEqualityComparer.Default.Equals(nts, _wellKnownTypes.Disposable))) + yield return ValidationErrorDiagnostic(rangeType, containerType, $"Isn't allowed to implement the interface {_wellKnownTypes.Disposable.FullName()}. It'll be generated by DIE."); + + if (rangeType.AllInterfaces.Any(nts => + SymbolEqualityComparer.Default.Equals(nts, _wellKnownTypes.AsyncDisposable))) + yield return ValidationErrorDiagnostic(rangeType, containerType, $"Isn't allowed to implement the interface {_wellKnownTypes.AsyncDisposable.FullName()}. It'll be generated by DIE."); + + foreach (var diagnostic in ValidateAddForDisposal(Constants.UserDefinedAddForDisposal, true)) + yield return diagnostic; + foreach (var diagnostic in ValidateAddForDisposal(Constants.UserDefinedAddForDisposalAsync, false)) + yield return diagnostic; + + var userDefinedConstructorParameters = rangeType + .GetMembers() + .Where(s => s.Name.StartsWith(Constants.UserDefinedConstructorParameters)) + .ToImmutableArray(); + + if (userDefinedConstructorParameters.Any()) + { + foreach (var symbol in userDefinedConstructorParameters + .Where(s => s is not IMethodSymbol)) + yield return ValidationErrorDiagnostic(rangeType, containerType, $"Member \"{symbol.Name}\" should be a method but isn't."); + + foreach (var userDefinedConstructorParameterMethod in userDefinedConstructorParameters + .OfType()) + foreach (var diagnostic in _validateUserDefinedConstrParam.Validate(userDefinedConstructorParameterMethod, rangeType, containerType)) + yield return diagnostic; + } + + var userDefinedFactories = rangeType + .GetMembers() + .Where(s => s.Name.StartsWith(Constants.UserDefinedFactory)) + .ToImmutableArray(); + + if (userDefinedFactories.Any()) + { + foreach (var symbol in userDefinedFactories + .Where(s => s is not (IFieldSymbol or IMethodSymbol or IPropertySymbol))) + yield return ValidationErrorDiagnostic(rangeType, containerType, $"Member \"{symbol.Name}\" should be a field variable, a property, or a method but isn't."); + + foreach (var userDefinedFactoryMethod in userDefinedFactories + .OfType()) + foreach (var diagnostic in _validateUserDefinedFactoryMethod.Validate(userDefinedFactoryMethod, rangeType, containerType)) + yield return diagnostic; + + foreach (var userDefinedFactoryProperty in userDefinedFactories + .OfType()) + { + if (userDefinedFactoryProperty.GetMethod is { } getter) + foreach (var diagnostic in _validateUserDefinedFactoryMethod.Validate(getter, rangeType, containerType)) + yield return diagnostic; + else + yield return ValidationErrorDiagnostic(rangeType, containerType, $"Factory property \"{userDefinedFactoryProperty.Name}\" has to have a getter method."); + } + + foreach (var userDefinedFactoryField in userDefinedFactories + .OfType()) + foreach (var diagnostic in _validateUserDefinedFactoryField.Validate(userDefinedFactoryField, rangeType, containerType)) + yield return diagnostic; + } + + IEnumerable ValidateAddForDisposal(string addForDisposalName, bool isSync) + { + var addForDisposalMembers = rangeType + .GetMembers() + .Where(s => s.Name == addForDisposalName) + .ToImmutableArray(); + + if (addForDisposalMembers.Length > 1) + yield return ValidationErrorDiagnostic(rangeType, containerType, $"Only a single \"{addForDisposalName}\"-member is allowed."); + else if (addForDisposalMembers.Length == 1) + { + if (addForDisposalMembers[0] is not IMethodSymbol) + yield return ValidationErrorDiagnostic(rangeType, containerType, $"The \"{addForDisposalName}\"-member is required to be a method."); + else if (addForDisposalMembers[0] is IMethodSymbol addForDisposalMember) + { + if (isSync) + foreach (var diagnostic in _validateUserDefinedAddForDisposalSync.Validate(addForDisposalMember, rangeType, containerType)) + yield return diagnostic; + else + foreach (var diagnostic in _validateUserDefinedAddForDisposalAsync.Validate(addForDisposalMember, rangeType, containerType)) + yield return diagnostic; + } + } + } + } + + if (rangeType.IsAbstract) + yield return ValidationErrorDiagnostic(rangeType, containerType, "Has to be non-abstract."); + + if (rangeType.IsExtern) + yield return ValidationErrorDiagnostic(rangeType, containerType, "Has to be non-extern."); + + if (rangeType.IsComImport) + yield return ValidationErrorDiagnostic(rangeType, containerType, "Has to be no COM import."); + + if (rangeType.IsImplicitClass) + yield return ValidationErrorDiagnostic(rangeType, containerType, "Has to be non-implicit."); + + if (rangeType.IsUnboundGenericType) + yield return ValidationErrorDiagnostic(rangeType, containerType, "Has to be no unbound generic type."); + + if (rangeType.IsScriptClass) + yield return ValidationErrorDiagnostic(rangeType, containerType, "Has to be no script class."); + + if (rangeType.IsNamespace) + yield return ValidationErrorDiagnostic(rangeType, containerType, "Has to be no namespace."); + + if (rangeType.IsRecord) + yield return ValidationErrorDiagnostic(rangeType, containerType, "Has to be no record."); + + if (rangeType.IsStatic) + yield return ValidationErrorDiagnostic(rangeType, containerType, "Has to be non-static."); + + if (rangeType.IsVirtual) + yield return ValidationErrorDiagnostic(rangeType, containerType, "Has to be non-virtual."); + + if (rangeType.IsAnonymousType) + yield return ValidationErrorDiagnostic(rangeType, containerType, "Has to be non-anonymous."); + + if (rangeType.IsTupleType) + yield return ValidationErrorDiagnostic(rangeType, containerType, "Has to be no tuple type."); + + if (rangeType.IsReadOnly) + yield return ValidationErrorDiagnostic(rangeType, containerType, "Has to be non-read-only."); + + if (rangeType.IsImplicitlyDeclared) + yield return ValidationErrorDiagnostic(rangeType, containerType, "Has to be non-implicitly-declared."); + + if (rangeType.IsNativeIntegerType) + yield return ValidationErrorDiagnostic(rangeType, containerType, "Has to be no native integer type."); + + if (rangeType.MightContainExtensionMethods) + yield return ValidationErrorDiagnostic(rangeType, containerType, "Isn't allowed to contain extension types."); + + if (rangeType.EnumUnderlyingType is {}) + yield return ValidationErrorDiagnostic(rangeType, containerType, "Isn't allowed to have an underlying enum type."); + + if (rangeType.NativeIntegerUnderlyingType is {}) + yield return ValidationErrorDiagnostic(rangeType, containerType, "Isn't allowed to have an underlying native integer type."); + + if (rangeType.TupleUnderlyingType is {}) + yield return ValidationErrorDiagnostic(rangeType, containerType, "Isn't allowed to have an underlying tuple type."); + + if (!rangeType.IsType) + yield return ValidationErrorDiagnostic(rangeType, containerType, "Has to be a type."); + + if (!rangeType.IsSealed) + yield return ValidationErrorDiagnostic(rangeType, containerType, "Has to be sealed."); + + if (!rangeType.IsReferenceType) + yield return ValidationErrorDiagnostic(rangeType, containerType, "Has to be a reference type."); + + if (!rangeType.CanBeReferencedByName) + yield return ValidationErrorDiagnostic(rangeType, containerType, "Has to be referable by name."); + + if (rangeType.TypeKind != TypeKind.Class) + yield return ValidationErrorDiagnostic(rangeType, containerType, "Has to be a class."); + } +} \ No newline at end of file diff --git a/Main/Validation/Range/ValidateScope.cs b/Main/Validation/Range/ValidateScope.cs new file mode 100644 index 00000000..845f5f1b --- /dev/null +++ b/Main/Validation/Range/ValidateScope.cs @@ -0,0 +1,39 @@ +using MrMeeseeks.DIE.Validation.Range.UserDefined; + +namespace MrMeeseeks.DIE.Validation.Range; + +internal interface IValidateScope : IValidateScopeBase +{ +} + +internal class ValidateScope : ValidateScopeBase, IValidateScope +{ + internal ValidateScope( + IValidateUserDefinedAddForDisposalSync validateUserDefinedAddForDisposalSync, + IValidateUserDefinedAddForDisposalAsync validateUserDefinedAddForDisposalAsync, + IValidateUserDefinedConstrParam validateUserDefinedConstrParam, + IValidateUserDefinedFactoryMethod validateUserDefinedFactoryMethod, + IValidateUserDefinedFactoryField validateUserDefinedFactoryField, + WellKnownTypes wellKnownTypes, + WellKnownTypesAggregation wellKnownTypesAggregation, + WellKnownTypesMiscellaneous wellKnownTypesMiscellaneous) + : base( + validateUserDefinedAddForDisposalSync, + validateUserDefinedAddForDisposalAsync, + validateUserDefinedConstrParam, + validateUserDefinedFactoryMethod, + validateUserDefinedFactoryField, + wellKnownTypes, + wellKnownTypesAggregation, + wellKnownTypesMiscellaneous) + { + + } + + protected override string DefaultScopeName => Constants.DefaultScopeName; + protected override string CustomScopeName => Constants.CustomScopeName; + protected override string ScopeName => Constants.ScopeName; + + protected override Diagnostic ValidationErrorDiagnostic(INamedTypeSymbol rangeType, INamedTypeSymbol containerType, string specification) => + Diagnostics.ValidationScope(rangeType, containerType, specification); +} \ No newline at end of file diff --git a/Main/Validation/Range/ValidateScopeBase.cs b/Main/Validation/Range/ValidateScopeBase.cs new file mode 100644 index 00000000..236a13a0 --- /dev/null +++ b/Main/Validation/Range/ValidateScopeBase.cs @@ -0,0 +1,100 @@ +using MrMeeseeks.DIE.Validation.Range.UserDefined; + +namespace MrMeeseeks.DIE.Validation.Range; + +internal interface IValidateScopeBase : IValidateRange +{ +} + +internal abstract class ValidateScopeBase : ValidateRange, IValidateScopeBase +{ + private readonly WellKnownTypesMiscellaneous _wellKnownTypesMiscellaneous; + private readonly IImmutableSet _notAllowedAttributeTypes; + + internal ValidateScopeBase( + IValidateUserDefinedAddForDisposalSync validateUserDefinedAddForDisposalSync, + IValidateUserDefinedAddForDisposalAsync validateUserDefinedAddForDisposalAsync, + IValidateUserDefinedConstrParam validateUserDefinedConstrParam, + IValidateUserDefinedFactoryMethod validateUserDefinedFactoryMethod, + IValidateUserDefinedFactoryField validateUserDefinedFactoryField, + WellKnownTypes wellKnownTypes, + WellKnownTypesAggregation wellKnownTypesAggregation, + WellKnownTypesMiscellaneous wellKnownTypesMiscellaneous) + : base( + validateUserDefinedAddForDisposalSync, + validateUserDefinedAddForDisposalAsync, + validateUserDefinedConstrParam, + validateUserDefinedFactoryMethod, + validateUserDefinedFactoryField, + wellKnownTypes) + { + _wellKnownTypesMiscellaneous = wellKnownTypesMiscellaneous; + + _notAllowedAttributeTypes = ImmutableHashSet.Create( + wellKnownTypesAggregation.ContainerInstanceAbstractionAggregationAttribute, + wellKnownTypesAggregation.ContainerInstanceImplementationAggregationAttribute, + wellKnownTypesAggregation.FilterContainerInstanceAbstractionAggregationAttribute, + wellKnownTypesAggregation.FilterContainerInstanceImplementationAggregationAttribute, + wellKnownTypesAggregation.TransientScopeInstanceAbstractionAggregationAttribute, + wellKnownTypesAggregation.TransientScopeInstanceImplementationAggregationAttribute, + wellKnownTypesAggregation.FilterTransientScopeInstanceAbstractionAggregationAttribute, + wellKnownTypesAggregation.FilterTransientScopeInstanceImplementationAggregationAttribute, + wellKnownTypesAggregation.TransientScopeRootAbstractionAggregationAttribute, + wellKnownTypesAggregation.TransientScopeRootImplementationAggregationAttribute, + wellKnownTypesAggregation.FilterTransientScopeRootAbstractionAggregationAttribute, + wellKnownTypesAggregation.FilterTransientScopeRootImplementationAggregationAttribute, + wellKnownTypesAggregation.ScopeRootAbstractionAggregationAttribute, + wellKnownTypesAggregation.ScopeRootImplementationAggregationAttribute, + wellKnownTypesAggregation.FilterScopeRootAbstractionAggregationAttribute, + wellKnownTypesAggregation.FilterScopeRootImplementationAggregationAttribute); + } + + protected abstract string DefaultScopeName { get; } + + protected abstract string CustomScopeName { get; } + + protected abstract string ScopeName { get; } + + public override IEnumerable Validate(INamedTypeSymbol rangeType, INamedTypeSymbol containerType) + { + foreach (var diagnostic in base.Validate(rangeType, containerType)) + yield return diagnostic; + + if (rangeType.DeclaredAccessibility != Accessibility.Private) + yield return ValidationErrorDiagnostic(rangeType, containerType, "Has to be declared private."); + + if (rangeType.Name != DefaultScopeName && !rangeType.Name.StartsWith(CustomScopeName)) + yield return ValidationErrorDiagnostic(rangeType, containerType, $"{ScopeName}'s name hast to be either \"{DefaultScopeName}\" if it is the default {ScopeName} or start with \"{CustomScopeName}\" if it is a custom {ScopeName}."); + + foreach (var notAllowedAttributeType in rangeType + .GetAttributes() + .Select(ad => ad.AttributeClass) + .Distinct(SymbolEqualityComparer.Default) + .OfType() + .Where(nts => _notAllowedAttributeTypes.Contains(nts, SymbolEqualityComparer.Default))) + yield return ValidationErrorDiagnostic(rangeType, containerType, $"{ScopeName}s aren't allowed to have attributes of type \"{notAllowedAttributeType.FullName()}\"."); + + var isDefault = rangeType.Name == DefaultScopeName; + var isCustom = rangeType.Name.StartsWith(CustomScopeName); + + if (isDefault) + { + if (rangeType + .GetAttributes() + .Any(ad => SymbolEqualityComparer.Default.Equals( + ad.AttributeClass, + _wellKnownTypesMiscellaneous.CustomScopeForRootTypesAttribute))) + yield return ValidationErrorDiagnostic(rangeType, containerType, $"A default (Transient)Scope isn't allowed to have the attribute of type \"{_wellKnownTypesMiscellaneous.CustomScopeForRootTypesAttribute.FullName()}\"."); + } + + if (isCustom) + { + if (rangeType + .GetAttributes() + .Count(ad => SymbolEqualityComparer.Default.Equals( + ad.AttributeClass, + _wellKnownTypesMiscellaneous.CustomScopeForRootTypesAttribute)) != 1) + yield return ValidationErrorDiagnostic(rangeType, containerType, $"A custom (Transient)Scope has to have exactly one attribute of type \"{_wellKnownTypesMiscellaneous.CustomScopeForRootTypesAttribute.FullName()}\"."); + } + } +} \ No newline at end of file diff --git a/Main/Validation/Range/ValidateTransientScope.cs b/Main/Validation/Range/ValidateTransientScope.cs new file mode 100644 index 00000000..ea38cf47 --- /dev/null +++ b/Main/Validation/Range/ValidateTransientScope.cs @@ -0,0 +1,39 @@ +using MrMeeseeks.DIE.Validation.Range.UserDefined; + +namespace MrMeeseeks.DIE.Validation.Range; + +internal interface IValidateTransientScope : IValidateScopeBase +{ +} + +internal class ValidateTransientScope : ValidateScopeBase, IValidateTransientScope +{ + internal ValidateTransientScope( + IValidateUserDefinedAddForDisposalSync validateUserDefinedAddForDisposalSync, + IValidateUserDefinedAddForDisposalAsync validateUserDefinedAddForDisposalAsync, + IValidateUserDefinedConstrParam validateUserDefinedConstrParam, + IValidateUserDefinedFactoryMethod validateUserDefinedFactoryMethod, + IValidateUserDefinedFactoryField validateUserDefinedFactoryField, + WellKnownTypes wellKnownTypes, + WellKnownTypesAggregation wellKnownTypesAggregation, + WellKnownTypesMiscellaneous wellKnownTypesMiscellaneous) + : base( + validateUserDefinedAddForDisposalSync, + validateUserDefinedAddForDisposalAsync, + validateUserDefinedConstrParam, + validateUserDefinedFactoryMethod, + validateUserDefinedFactoryField, + wellKnownTypes, + wellKnownTypesAggregation, + wellKnownTypesMiscellaneous) + { + + } + + protected override string DefaultScopeName => Constants.DefaultTransientScopeName; + protected override string CustomScopeName => Constants.CustomTransientScopeName; + protected override string ScopeName => Constants.TransientScopeName; + + protected override Diagnostic ValidationErrorDiagnostic(INamedTypeSymbol rangeType, INamedTypeSymbol containerType, string specification) => + Diagnostics.ValidationTransientScope(rangeType, containerType, specification); +} \ No newline at end of file diff --git a/Sample/Context.cs b/Sample/Context.cs index e36bafb5..a8e6782a 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -1,4 +1,5 @@ -using MrMeeseeks.DIE.Configuration.Attributes; +using System; +using MrMeeseeks.DIE.Configuration.Attributes; using MrMeeseeks.DIE.Sample; namespace MrMeeseeks.DIE.Test.CustomEmbedding.ConstructorParameterWithDependencyInScope; @@ -24,9 +25,11 @@ internal ScopeRoot( } [CreateFunction(typeof(ScopeRoot), "Create")] -internal partial class Container +internal sealed partial class Container { - partial class DIE_DefaultScope + private partial void DIE_AddForDisposal(IDisposable disposable); + + sealed partial class DIE_DefaultScope { [CustomConstructorParameterChoice(typeof(Dependency))] private void DIE_ConstrParam_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; diff --git a/Test/Async/Awaited/AsyncScopeRootCallAsTask.cs b/Test/Async/Awaited/AsyncScopeRootCallAsTask.cs index 7d27a84d..1aedd920 100644 --- a/Test/Async/Awaited/AsyncScopeRootCallAsTask.cs +++ b/Test/Async/Awaited/AsyncScopeRootCallAsTask.cs @@ -26,7 +26,7 @@ internal ScopeRoot(Dependency dep) } [CreateFunction(typeof(Task), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Async/Awaited/AsyncScopeRootCallAsValueTask.cs b/Test/Async/Awaited/AsyncScopeRootCallAsValueTask.cs index 0096a53f..ca6a84b5 100644 --- a/Test/Async/Awaited/AsyncScopeRootCallAsValueTask.cs +++ b/Test/Async/Awaited/AsyncScopeRootCallAsValueTask.cs @@ -26,7 +26,7 @@ internal ScopeRoot(Dependency dep) } [CreateFunction(typeof(ValueTask), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Async/Awaited/AsyncScopeRootCallAwaited.cs b/Test/Async/Awaited/AsyncScopeRootCallAwaited.cs index c01ad175..4b0869fd 100644 --- a/Test/Async/Awaited/AsyncScopeRootCallAwaited.cs +++ b/Test/Async/Awaited/AsyncScopeRootCallAwaited.cs @@ -26,7 +26,7 @@ internal ScopeRoot(Dependency dep) } [CreateFunction(typeof(ScopeRoot), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Async/Awaited/ContainerInstanceFunctionAsTask.cs b/Test/Async/Awaited/ContainerInstanceFunctionAsTask.cs index 5faf90ce..344ab2db 100644 --- a/Test/Async/Awaited/ContainerInstanceFunctionAsTask.cs +++ b/Test/Async/Awaited/ContainerInstanceFunctionAsTask.cs @@ -17,7 +17,7 @@ async Task ITaskTypeInitializer.InitializeAsync() } [CreateFunction(typeof(Dependency), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Async/Awaited/ContainerInstanceFunctionAsValueTask.cs b/Test/Async/Awaited/ContainerInstanceFunctionAsValueTask.cs index f788292b..039d1fa0 100644 --- a/Test/Async/Awaited/ContainerInstanceFunctionAsValueTask.cs +++ b/Test/Async/Awaited/ContainerInstanceFunctionAsValueTask.cs @@ -17,7 +17,7 @@ async Task ITaskTypeInitializer.InitializeAsync() } [CreateFunction(typeof(Dependency), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Async/Awaited/ScopeInstanceFunctionAsTask.cs b/Test/Async/Awaited/ScopeInstanceFunctionAsTask.cs index 888eb2cc..14019d0b 100644 --- a/Test/Async/Awaited/ScopeInstanceFunctionAsTask.cs +++ b/Test/Async/Awaited/ScopeInstanceFunctionAsTask.cs @@ -17,7 +17,7 @@ async Task ITaskTypeInitializer.InitializeAsync() } [CreateFunction(typeof(Dependency), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Async/Awaited/ScopeInstanceFunctionAsValueTask.cs b/Test/Async/Awaited/ScopeInstanceFunctionAsValueTask.cs index b2af2bae..c1be18af 100644 --- a/Test/Async/Awaited/ScopeInstanceFunctionAsValueTask.cs +++ b/Test/Async/Awaited/ScopeInstanceFunctionAsValueTask.cs @@ -17,7 +17,7 @@ async Task ITaskTypeInitializer.InitializeAsync() } [CreateFunction(typeof(Dependency), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Async/Awaited/TaskTypeInitializerTask.cs b/Test/Async/Awaited/TaskTypeInitializerTask.cs index b469ce98..88c19b03 100644 --- a/Test/Async/Awaited/TaskTypeInitializerTask.cs +++ b/Test/Async/Awaited/TaskTypeInitializerTask.cs @@ -17,7 +17,7 @@ async Task ITaskTypeInitializer.InitializeAsync() } [CreateFunction(typeof(Dependency), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Async/Awaited/TaskTypeInitializerValueTask.cs b/Test/Async/Awaited/TaskTypeInitializerValueTask.cs index 73f06922..e42b8c33 100644 --- a/Test/Async/Awaited/TaskTypeInitializerValueTask.cs +++ b/Test/Async/Awaited/TaskTypeInitializerValueTask.cs @@ -17,7 +17,7 @@ async ValueTask IValueTaskTypeInitializer.InitializeAsync() } [CreateFunction(typeof(Dependency), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Async/Awaited/TransientScopeInstanceFunctionAsTask.cs b/Test/Async/Awaited/TransientScopeInstanceFunctionAsTask.cs index 3853f2c0..4206385e 100644 --- a/Test/Async/Awaited/TransientScopeInstanceFunctionAsTask.cs +++ b/Test/Async/Awaited/TransientScopeInstanceFunctionAsTask.cs @@ -16,7 +16,7 @@ async Task ITaskTypeInitializer.InitializeAsync() } [CreateFunction(typeof(Dependency), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Async/Awaited/TransientScopeInstanceFunctionAsValueTask.cs b/Test/Async/Awaited/TransientScopeInstanceFunctionAsValueTask.cs index 9af46780..95bc2099 100644 --- a/Test/Async/Awaited/TransientScopeInstanceFunctionAsValueTask.cs +++ b/Test/Async/Awaited/TransientScopeInstanceFunctionAsValueTask.cs @@ -16,7 +16,7 @@ async Task ITaskTypeInitializer.InitializeAsync() } [CreateFunction(typeof(Dependency), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Async/Awaited/TransientScopeInstanceFunction_DifferentSynchronicity.cs b/Test/Async/Awaited/TransientScopeInstanceFunction_DifferentSynchronicity.cs index 7f760317..7ae29a00 100644 --- a/Test/Async/Awaited/TransientScopeInstanceFunction_DifferentSynchronicity.cs +++ b/Test/Async/Awaited/TransientScopeInstanceFunction_DifferentSynchronicity.cs @@ -52,10 +52,10 @@ internal TransientScopeRoot1(Instance dependency) [FilterImplementationAggregation(typeof(DependencyB))] [CreateFunction(typeof(TransientScopeRoot0), "Create0")] [CreateFunction(typeof(TransientScopeRoot1), "Create1")] -internal partial class Container +internal sealed partial class Container { [CustomScopeForRootTypes(typeof(TransientScopeRoot0))] - private partial class DIE_TransientScope0 + private sealed partial class DIE_TransientScope0 { } @@ -63,7 +63,7 @@ private partial class DIE_TransientScope0 [FilterImplementationAggregation(typeof(DependencyA))] [ImplementationAggregation(typeof(DependencyB))] [CustomScopeForRootTypes(typeof(TransientScopeRoot1))] - private partial class DIE_TransientScope1 + private sealed partial class DIE_TransientScope1 { } diff --git a/Test/Async/Wrapped/ContainerInstanceFunctionAsTask.cs b/Test/Async/Wrapped/ContainerInstanceFunctionAsTask.cs index ae1bb670..80bbf889 100644 --- a/Test/Async/Wrapped/ContainerInstanceFunctionAsTask.cs +++ b/Test/Async/Wrapped/ContainerInstanceFunctionAsTask.cs @@ -17,7 +17,7 @@ async Task ITaskTypeInitializer.InitializeAsync() } [CreateFunction(typeof(Task), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Async/Wrapped/ContainerInstanceFunctionAsValueTask.cs b/Test/Async/Wrapped/ContainerInstanceFunctionAsValueTask.cs index fee85c60..b9b25f62 100644 --- a/Test/Async/Wrapped/ContainerInstanceFunctionAsValueTask.cs +++ b/Test/Async/Wrapped/ContainerInstanceFunctionAsValueTask.cs @@ -17,7 +17,7 @@ async Task ITaskTypeInitializer.InitializeAsync() } [CreateFunction(typeof(ValueTask), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Async/Wrapped/DecorationChaining.cs b/Test/Async/Wrapped/DecorationChaining.cs index fd5a9241..a13f9b40 100644 --- a/Test/Async/Wrapped/DecorationChaining.cs +++ b/Test/Async/Wrapped/DecorationChaining.cs @@ -49,7 +49,7 @@ async ValueTask IValueTaskTypeInitializer.InitializeAsync() [CreateFunction(typeof(Task), "Create")] [DecoratorSequenceChoice(typeof(IInterface), typeof(DecoratorA), typeof(DecoratorB))] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Async/Wrapped/Func.cs b/Test/Async/Wrapped/Func.cs index 300189e7..f030f630 100644 --- a/Test/Async/Wrapped/Func.cs +++ b/Test/Async/Wrapped/Func.cs @@ -18,7 +18,7 @@ async Task ITaskTypeInitializer.InitializeAsync() } [CreateFunction(typeof(Func>), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Async/Wrapped/Lazy.cs b/Test/Async/Wrapped/Lazy.cs index 991dabb2..216f5536 100644 --- a/Test/Async/Wrapped/Lazy.cs +++ b/Test/Async/Wrapped/Lazy.cs @@ -18,7 +18,7 @@ async Task ITaskTypeInitializer.InitializeAsync() } [CreateFunction(typeof(Lazy>), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Async/Wrapped/ScopeInstanceFunctionAsTask.cs b/Test/Async/Wrapped/ScopeInstanceFunctionAsTask.cs index d38d2c40..69ba44a6 100644 --- a/Test/Async/Wrapped/ScopeInstanceFunctionAsTask.cs +++ b/Test/Async/Wrapped/ScopeInstanceFunctionAsTask.cs @@ -17,7 +17,7 @@ async Task ITaskTypeInitializer.InitializeAsync() } [CreateFunction(typeof(Task), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Async/Wrapped/ScopeInstanceFunctionAsValueTask.cs b/Test/Async/Wrapped/ScopeInstanceFunctionAsValueTask.cs index 3f45836c..391bdb20 100644 --- a/Test/Async/Wrapped/ScopeInstanceFunctionAsValueTask.cs +++ b/Test/Async/Wrapped/ScopeInstanceFunctionAsValueTask.cs @@ -17,7 +17,7 @@ async Task ITaskTypeInitializer.InitializeAsync() } [CreateFunction(typeof(ValueTask), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Async/Wrapped/SyncToTask.cs b/Test/Async/Wrapped/SyncToTask.cs index 63c2d239..ae73ac4e 100644 --- a/Test/Async/Wrapped/SyncToTask.cs +++ b/Test/Async/Wrapped/SyncToTask.cs @@ -15,7 +15,7 @@ void ITypeInitializer.Initialize() } [CreateFunction(typeof(Task), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Async/Wrapped/SyncToValueTask.cs b/Test/Async/Wrapped/SyncToValueTask.cs index 3facc58a..554b8e70 100644 --- a/Test/Async/Wrapped/SyncToValueTask.cs +++ b/Test/Async/Wrapped/SyncToValueTask.cs @@ -15,7 +15,7 @@ void ITypeInitializer.Initialize() } [CreateFunction(typeof(ValueTask), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Async/Wrapped/TaskCollection.cs b/Test/Async/Wrapped/TaskCollection.cs index 12fa1330..f5a72328 100644 --- a/Test/Async/Wrapped/TaskCollection.cs +++ b/Test/Async/Wrapped/TaskCollection.cs @@ -48,7 +48,7 @@ internal class DependencyD : IInterface } [CreateFunction(typeof(IReadOnlyList>), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Async/Wrapped/TaskComposition.cs b/Test/Async/Wrapped/TaskComposition.cs index 57c241f5..360f5a22 100644 --- a/Test/Async/Wrapped/TaskComposition.cs +++ b/Test/Async/Wrapped/TaskComposition.cs @@ -67,7 +67,7 @@ public async Task InitializeAsync() public int Count => _composition.Count; } [CreateFunction(typeof(Task), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Async/Wrapped/TaskToTask.cs b/Test/Async/Wrapped/TaskToTask.cs index bd62d661..35489231 100644 --- a/Test/Async/Wrapped/TaskToTask.cs +++ b/Test/Async/Wrapped/TaskToTask.cs @@ -16,7 +16,7 @@ async Task ITaskTypeInitializer.InitializeAsync() } } [CreateFunction(typeof(Task), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Async/Wrapped/TaskToValueTask.cs b/Test/Async/Wrapped/TaskToValueTask.cs index 6d32956a..0aa3d943 100644 --- a/Test/Async/Wrapped/TaskToValueTask.cs +++ b/Test/Async/Wrapped/TaskToValueTask.cs @@ -17,7 +17,7 @@ async Task ITaskTypeInitializer.InitializeAsync() } [CreateFunction(typeof(ValueTask), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask.cs b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask.cs index 70ed3921..a1e59467 100644 --- a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask.cs +++ b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask.cs @@ -16,7 +16,7 @@ async Task ITaskTypeInitializer.InitializeAsync() } [CreateFunction(typeof(Task), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask_DifferentSynchronicity.cs b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask_DifferentSynchronicity.cs index 68ee7bb0..ab99d8fe 100644 --- a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask_DifferentSynchronicity.cs +++ b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask_DifferentSynchronicity.cs @@ -52,10 +52,10 @@ internal TransientScopeRoot1(Task dependency) [FilterImplementationAggregation(typeof(DependencyB))] [CreateFunction(typeof(TransientScopeRoot0), "Create0")] [CreateFunction(typeof(TransientScopeRoot1), "Create1")] -internal partial class Container +internal sealed partial class Container { [CustomScopeForRootTypes(typeof(TransientScopeRoot0))] - private partial class DIE_TransientScope0 + private sealed partial class DIE_TransientScope0 { } @@ -63,7 +63,7 @@ private partial class DIE_TransientScope0 [FilterImplementationAggregation(typeof(DependencyA))] [ImplementationAggregation(typeof(DependencyB))] [CustomScopeForRootTypes(typeof(TransientScopeRoot1))] - private partial class DIE_TransientScope1 + private sealed partial class DIE_TransientScope1 { } diff --git a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask.cs b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask.cs index 5662020d..2726c4ab 100644 --- a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask.cs +++ b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask.cs @@ -16,7 +16,7 @@ async Task ITaskTypeInitializer.InitializeAsync() } [CreateFunction(typeof(ValueTask), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask_DifferentSynchronicity.cs b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask_DifferentSynchronicity.cs index c43cdac1..71ff96da 100644 --- a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask_DifferentSynchronicity.cs +++ b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask_DifferentSynchronicity.cs @@ -52,10 +52,10 @@ internal TransientScopeRoot1(ValueTask dependency) [FilterImplementationAggregation(typeof(DependencyB))] [CreateFunction(typeof(TransientScopeRoot0), "Create0")] [CreateFunction(typeof(TransientScopeRoot1), "Create1")] -internal partial class Container +internal sealed partial class Container { [CustomScopeForRootTypes(typeof(TransientScopeRoot0))] - private partial class DIE_TransientScope0 + private sealed partial class DIE_TransientScope0 { } @@ -63,7 +63,7 @@ private partial class DIE_TransientScope0 [FilterImplementationAggregation(typeof(DependencyA))] [ImplementationAggregation(typeof(DependencyB))] [CustomScopeForRootTypes(typeof(TransientScopeRoot1))] - private partial class DIE_TransientScope1 + private sealed partial class DIE_TransientScope1 { } diff --git a/Test/Async/Wrapped/ValueTaskCollection.cs b/Test/Async/Wrapped/ValueTaskCollection.cs index deee8b90..be98c69a 100644 --- a/Test/Async/Wrapped/ValueTaskCollection.cs +++ b/Test/Async/Wrapped/ValueTaskCollection.cs @@ -48,7 +48,7 @@ internal class DependencyD : IInterface } [CreateFunction(typeof(IReadOnlyList>), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Async/Wrapped/ValueTaskComposition.cs b/Test/Async/Wrapped/ValueTaskComposition.cs index 52b4bac5..2ec567eb 100644 --- a/Test/Async/Wrapped/ValueTaskComposition.cs +++ b/Test/Async/Wrapped/ValueTaskComposition.cs @@ -68,7 +68,7 @@ public async Task InitializeAsync() } [CreateFunction(typeof(ValueTask), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Async/Wrapped/ValueTaskToTask.cs b/Test/Async/Wrapped/ValueTaskToTask.cs index 259fd986..bf6023db 100644 --- a/Test/Async/Wrapped/ValueTaskToTask.cs +++ b/Test/Async/Wrapped/ValueTaskToTask.cs @@ -17,7 +17,7 @@ async ValueTask IValueTaskTypeInitializer.InitializeAsync() } [CreateFunction(typeof(Task), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Async/Wrapped/ValueTaskToValueTask.cs b/Test/Async/Wrapped/ValueTaskToValueTask.cs index 79e53cf5..20283842 100644 --- a/Test/Async/Wrapped/ValueTaskToValueTask.cs +++ b/Test/Async/Wrapped/ValueTaskToValueTask.cs @@ -17,7 +17,7 @@ async ValueTask IValueTaskTypeInitializer.InitializeAsync() } [CreateFunction(typeof(ValueTask), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Composite/Container.cs b/Test/Composite/Container.cs index 517bb427..0eba84da 100644 --- a/Test/Composite/Container.cs +++ b/Test/Composite/Container.cs @@ -30,7 +30,7 @@ public Composite(IReadOnlyList composites) => [CreateFunction(typeof(IInterface), "CreateDep")] [CreateFunction(typeof(IReadOnlyList), "CreateCollection")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Composite/Decorated.cs b/Test/Composite/Decorated.cs index b5c8279f..8394aa0c 100644 --- a/Test/Composite/Decorated.cs +++ b/Test/Composite/Decorated.cs @@ -56,7 +56,7 @@ public Composite(IReadOnlyList composites) => [DecoratorSequenceChoice(typeof(Composite), typeof(DecoratorB))] [CreateFunction(typeof(IInterface), "CreateDep")] [CreateFunction(typeof(IReadOnlyList), "CreateCollection")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Composite/MixedScoping.cs b/Test/Composite/MixedScoping.cs index 2517804f..690f83cd 100644 --- a/Test/Composite/MixedScoping.cs +++ b/Test/Composite/MixedScoping.cs @@ -30,7 +30,7 @@ public Composite(IReadOnlyList composites) => [CreateFunction(typeof(IInterface), "CreateDep")] [CreateFunction(typeof(IReadOnlyList), "CreateCollection")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Composite/Normal.cs b/Test/Composite/Normal.cs index 673d6339..26421e68 100644 --- a/Test/Composite/Normal.cs +++ b/Test/Composite/Normal.cs @@ -30,7 +30,7 @@ public Composite(IReadOnlyList composites) => [CreateFunction(typeof(IInterface), "CreateDep")] [CreateFunction(typeof(IReadOnlyList), "CreateCollection")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Composite/ScopeRoot.cs b/Test/Composite/ScopeRoot.cs index 95023e4c..cbb02063 100644 --- a/Test/Composite/ScopeRoot.cs +++ b/Test/Composite/ScopeRoot.cs @@ -45,7 +45,7 @@ public Composite(IReadOnlyList composites, IDependency dependency) [CreateFunction(typeof(IInterface), "CreateDep")] [CreateFunction(typeof(IReadOnlyList), "CreateCollection")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/ConstructorChoice/Parameterless.cs b/Test/ConstructorChoice/Parameterless.cs index 1077f734..24a8ff0e 100644 --- a/Test/ConstructorChoice/Parameterless.cs +++ b/Test/ConstructorChoice/Parameterless.cs @@ -8,7 +8,7 @@ namespace MrMeeseeks.DIE.Test.ConstructorChoice.Parameterless; [ImplementationAggregation(typeof(DateTime))] [ConstructorChoice(typeof(DateTime))] [CreateFunction(typeof(DateTime), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/ConstructorChoice/WithParameter.cs b/Test/ConstructorChoice/WithParameter.cs index 9be2e6a5..d294d8ed 100644 --- a/Test/ConstructorChoice/WithParameter.cs +++ b/Test/ConstructorChoice/WithParameter.cs @@ -9,7 +9,7 @@ namespace MrMeeseeks.DIE.Test.ConstructorChoice.WithParameter; [ImplementationAggregation(typeof(FileInfo))] [ConstructorChoice(typeof(FileInfo), typeof(string))] [CreateFunction(typeof(Func), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/CustomEmbedding/ConstructorParameter.cs b/Test/CustomEmbedding/ConstructorParameter.cs index e6eeb21f..98eabd49 100644 --- a/Test/CustomEmbedding/ConstructorParameter.cs +++ b/Test/CustomEmbedding/ConstructorParameter.cs @@ -12,7 +12,7 @@ internal class Dependency } [CreateFunction(typeof(Dependency), "Create")] -internal partial class Container +internal sealed partial class Container { [CustomConstructorParameterChoice(typeof(Dependency))] private void DIE_ConstrParam_Dependency(out int number) => number = 69; diff --git a/Test/CustomEmbedding/ConstructorParameterInScope.cs b/Test/CustomEmbedding/ConstructorParameterInScope.cs index 827186a3..3eeac8ee 100644 --- a/Test/CustomEmbedding/ConstructorParameterInScope.cs +++ b/Test/CustomEmbedding/ConstructorParameterInScope.cs @@ -20,9 +20,9 @@ internal ScopeRoot( } [CreateFunction(typeof(ScopeRoot), "Create")] -internal partial class Container +internal sealed partial class Container { - partial class DIE_DefaultScope + private sealed partial class DIE_DefaultScope { [CustomConstructorParameterChoice(typeof(Dependency))] private void DIE_ConstrParam_Dependency(out int number) => number = 69; diff --git a/Test/CustomEmbedding/ConstructorParameterInTransientScope.cs b/Test/CustomEmbedding/ConstructorParameterInTransientScope.cs index faf67298..eb2fc072 100644 --- a/Test/CustomEmbedding/ConstructorParameterInTransientScope.cs +++ b/Test/CustomEmbedding/ConstructorParameterInTransientScope.cs @@ -20,9 +20,9 @@ internal TransientScopeRoot( } [CreateFunction(typeof(TransientScopeRoot), "Create")] -internal partial class Container +internal sealed partial class Container { - partial class DIE_DefaultTransientScope + private sealed partial class DIE_DefaultTransientScope { [CustomConstructorParameterChoice(typeof(Dependency))] private void DIE_ConstrParam_Dependency(out int number) => number = 69; diff --git a/Test/CustomEmbedding/ConstructorParameterWithAsyncDependency.cs b/Test/CustomEmbedding/ConstructorParameterWithAsyncDependency.cs index ca17b6e9..fdc5a499 100644 --- a/Test/CustomEmbedding/ConstructorParameterWithAsyncDependency.cs +++ b/Test/CustomEmbedding/ConstructorParameterWithAsyncDependency.cs @@ -18,7 +18,7 @@ internal class OtherDependency : IValueTaskTypeInitializer } [CreateFunction(typeof(Dependency), "Create")] -internal partial class Container +internal sealed partial class Container { [CustomConstructorParameterChoice(typeof(Dependency))] private void DIE_ConstrParam_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; diff --git a/Test/CustomEmbedding/ConstructorParameterWithAsyncDependencyInScope.cs b/Test/CustomEmbedding/ConstructorParameterWithAsyncDependencyInScope.cs index 51be0bd8..1e8b0813 100644 --- a/Test/CustomEmbedding/ConstructorParameterWithAsyncDependencyInScope.cs +++ b/Test/CustomEmbedding/ConstructorParameterWithAsyncDependencyInScope.cs @@ -26,9 +26,9 @@ internal ScopeRoot( } [CreateFunction(typeof(ScopeRoot), "Create")] -internal partial class Container +internal sealed partial class Container { - partial class DIE_DefaultScope + private sealed partial class DIE_DefaultScope { [CustomConstructorParameterChoice(typeof(Dependency))] private void DIE_ConstrParam_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; diff --git a/Test/CustomEmbedding/ConstructorParameterWithAsyncDependencyInTransientScope.cs b/Test/CustomEmbedding/ConstructorParameterWithAsyncDependencyInTransientScope.cs index fea68d86..0470c9fd 100644 --- a/Test/CustomEmbedding/ConstructorParameterWithAsyncDependencyInTransientScope.cs +++ b/Test/CustomEmbedding/ConstructorParameterWithAsyncDependencyInTransientScope.cs @@ -26,9 +26,9 @@ internal TransientScopeRoot( } [CreateFunction(typeof(TransientScopeRoot), "Create")] -internal partial class Container +internal sealed partial class Container { - partial class DIE_DefaultTransientScope + private sealed partial class DIE_DefaultTransientScope { [CustomConstructorParameterChoice(typeof(Dependency))] private void DIE_ConstrParam_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; diff --git a/Test/CustomEmbedding/ConstructorParameterWithDependency.cs b/Test/CustomEmbedding/ConstructorParameterWithDependency.cs index 3decb8a9..64234a6e 100644 --- a/Test/CustomEmbedding/ConstructorParameterWithDependency.cs +++ b/Test/CustomEmbedding/ConstructorParameterWithDependency.cs @@ -17,7 +17,7 @@ internal class OtherDependency } [CreateFunction(typeof(Dependency), "Create")] -internal partial class Container +internal sealed partial class Container { [CustomConstructorParameterChoice(typeof(Dependency))] private void DIE_ConstrParam_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; diff --git a/Test/CustomEmbedding/ConstructorParameterWithDependencyInScope.cs b/Test/CustomEmbedding/ConstructorParameterWithDependencyInScope.cs index 633e551e..1aabdbd5 100644 --- a/Test/CustomEmbedding/ConstructorParameterWithDependencyInScope.cs +++ b/Test/CustomEmbedding/ConstructorParameterWithDependencyInScope.cs @@ -25,9 +25,9 @@ internal ScopeRoot( } [CreateFunction(typeof(ScopeRoot), "Create")] -internal partial class Container +internal sealed partial class Container { - partial class DIE_DefaultScope + private sealed partial class DIE_DefaultScope { [CustomConstructorParameterChoice(typeof(Dependency))] private void DIE_ConstrParam_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; diff --git a/Test/CustomEmbedding/ConstructorParameterWithDependencyInTransientScope.cs b/Test/CustomEmbedding/ConstructorParameterWithDependencyInTransientScope.cs index 4d54641d..55a55981 100644 --- a/Test/CustomEmbedding/ConstructorParameterWithDependencyInTransientScope.cs +++ b/Test/CustomEmbedding/ConstructorParameterWithDependencyInTransientScope.cs @@ -25,9 +25,9 @@ internal TransientScopeRoot( } [CreateFunction(typeof(TransientScopeRoot), "Create")] -internal partial class Container +internal sealed partial class Container { - partial class DIE_DefaultTransientScope + private sealed partial class DIE_DefaultTransientScope { [CustomConstructorParameterChoice(typeof(Dependency))] private void DIE_ConstrParam_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; diff --git a/Test/CustomEmbedding/FactoryInContainercs.cs b/Test/CustomEmbedding/FactoryInContainercs.cs index 67e67856..2ccf99cd 100644 --- a/Test/CustomEmbedding/FactoryInContainercs.cs +++ b/Test/CustomEmbedding/FactoryInContainercs.cs @@ -12,7 +12,7 @@ internal class Wrapper } [CreateFunction(typeof(Wrapper), "Create")] -internal partial class Container +internal sealed partial class Container { private string DIE_Factory_Yeah() => "Yeah"; } diff --git a/Test/CustomEmbedding/FactoryInScope.cs b/Test/CustomEmbedding/FactoryInScope.cs index f834a6a7..0a46554a 100644 --- a/Test/CustomEmbedding/FactoryInScope.cs +++ b/Test/CustomEmbedding/FactoryInScope.cs @@ -12,9 +12,9 @@ internal class ScopeRoot : IScopeRoot } [CreateFunction(typeof(ScopeRoot), "Create")] -internal partial class Container +internal sealed partial class Container { - partial class DIE_DefaultScope + private sealed partial class DIE_DefaultScope { private string DIE_Factory_Yeah() => "Yeah"; } diff --git a/Test/CustomEmbedding/FactoryInTransientScope.cs b/Test/CustomEmbedding/FactoryInTransientScope.cs index 4cd08ca5..eaee5bab 100644 --- a/Test/CustomEmbedding/FactoryInTransientScope.cs +++ b/Test/CustomEmbedding/FactoryInTransientScope.cs @@ -12,9 +12,9 @@ internal class TransientScopeRoot : ITransientScopeRoot } [CreateFunction(typeof(TransientScopeRoot), "Create")] -internal partial class Container +internal sealed partial class Container { - partial class DIE_DefaultTransientScope + private sealed partial class DIE_DefaultTransientScope { private string DIE_Factory_Yeah() => "Yeah"; } diff --git a/Test/CustomEmbedding/FactoryWithParameterInContainercs.cs b/Test/CustomEmbedding/FactoryWithParameterInContainercs.cs index 5b6e53e3..bcf8bad0 100644 --- a/Test/CustomEmbedding/FactoryWithParameterInContainercs.cs +++ b/Test/CustomEmbedding/FactoryWithParameterInContainercs.cs @@ -7,7 +7,7 @@ namespace MrMeeseeks.DIE.Test.CustomEmbedding.FactoryWithParameterInContainer; [ImplementationAggregation(typeof(FileInfo))] [CreateFunction(typeof(FileInfo), "Create")] -internal partial class Container +internal sealed partial class Container { private string DIE_Factory_Path => "C:\\Yeah.txt"; private FileInfo DIE_Factory(string path) => new (path); diff --git a/Test/CustomEmbedding/FactoryWithParameterInScope.cs b/Test/CustomEmbedding/FactoryWithParameterInScope.cs index 683d9096..b4e0188d 100644 --- a/Test/CustomEmbedding/FactoryWithParameterInScope.cs +++ b/Test/CustomEmbedding/FactoryWithParameterInScope.cs @@ -13,9 +13,9 @@ internal class ScopeRoot : IScopeRoot } [CreateFunction(typeof(ScopeRoot), "Create")] -internal partial class Container +internal sealed partial class Container { - partial class DIE_DefaultScope + private sealed partial class DIE_DefaultScope { private string DIE_Factory_Path => "C:\\Yeah.txt"; private FileInfo DIE_Factory(string path) => new (path); diff --git a/Test/CustomEmbedding/FactoryWithParameterInTransientScope.cs b/Test/CustomEmbedding/FactoryWithParameterInTransientScope.cs index 7e92ca2f..5810abf7 100644 --- a/Test/CustomEmbedding/FactoryWithParameterInTransientScope.cs +++ b/Test/CustomEmbedding/FactoryWithParameterInTransientScope.cs @@ -13,9 +13,9 @@ internal class TransientScopeRoot : ITransientScopeRoot } [CreateFunction(typeof(TransientScopeRoot), "Create")] -internal partial class Container +internal sealed partial class Container { - partial class DIE_DefaultTransientScope + private sealed partial class DIE_DefaultTransientScope { private string DIE_Factory_Path => "C:\\Yeah.txt"; private FileInfo DIE_Factory(string path) => new (path); diff --git a/Test/CustomEmbedding/FieldInContainercs.cs b/Test/CustomEmbedding/FieldInContainercs.cs index 7413d8b3..c3f8db4d 100644 --- a/Test/CustomEmbedding/FieldInContainercs.cs +++ b/Test/CustomEmbedding/FieldInContainercs.cs @@ -12,7 +12,7 @@ internal class Wrapper } [CreateFunction(typeof(Wrapper), "Create")] -internal partial class Container +internal sealed partial class Container { private readonly string DIE_Factory_Yeah = "Yeah"; } diff --git a/Test/CustomEmbedding/FieldInScope.cs b/Test/CustomEmbedding/FieldInScope.cs index 934faa58..adef6687 100644 --- a/Test/CustomEmbedding/FieldInScope.cs +++ b/Test/CustomEmbedding/FieldInScope.cs @@ -12,9 +12,9 @@ internal class ScopeRoot : IScopeRoot } [CreateFunction(typeof(ScopeRoot), "Create")] -internal partial class Container +internal sealed partial class Container { - partial class DIE_DefaultScope + private sealed partial class DIE_DefaultScope { private readonly string DIE_Factory_Yeah = "Yeah"; } diff --git a/Test/CustomEmbedding/FieldInTransientScope.cs b/Test/CustomEmbedding/FieldInTransientScope.cs index 3e615070..52f481c3 100644 --- a/Test/CustomEmbedding/FieldInTransientScope.cs +++ b/Test/CustomEmbedding/FieldInTransientScope.cs @@ -12,9 +12,9 @@ internal class TransientScopeRoot : ITransientScopeRoot } [CreateFunction(typeof(TransientScopeRoot), "Create")] -internal partial class Container +internal sealed partial class Container { - partial class DIE_DefaultTransientScope + private sealed partial class DIE_DefaultTransientScope { private readonly string DIE_Factory_Yeah = "Yeah"; } diff --git a/Test/CustomEmbedding/PropertyInContainercs.cs b/Test/CustomEmbedding/PropertyInContainercs.cs index 0f26d356..de4ece38 100644 --- a/Test/CustomEmbedding/PropertyInContainercs.cs +++ b/Test/CustomEmbedding/PropertyInContainercs.cs @@ -12,7 +12,7 @@ internal class Wrapper } [CreateFunction(typeof(Wrapper), "Create")] -internal partial class Container +internal sealed partial class Container { private string DIE_Factory_Yeah => "Yeah"; } diff --git a/Test/CustomEmbedding/PropertyInScope.cs b/Test/CustomEmbedding/PropertyInScope.cs index d093e7cb..24b10f01 100644 --- a/Test/CustomEmbedding/PropertyInScope.cs +++ b/Test/CustomEmbedding/PropertyInScope.cs @@ -12,9 +12,9 @@ internal class ScopeRoot : IScopeRoot } [CreateFunction(typeof(ScopeRoot), "Create")] -internal partial class Container +internal sealed partial class Container { - partial class DIE_DefaultScope + private sealed partial class DIE_DefaultScope { private string DIE_Factory_Yeah => "Yeah"; } diff --git a/Test/CustomEmbedding/PropertyInTransientScope.cs b/Test/CustomEmbedding/PropertyInTransientScope.cs index 606dbab0..3195bd58 100644 --- a/Test/CustomEmbedding/PropertyInTransientScope.cs +++ b/Test/CustomEmbedding/PropertyInTransientScope.cs @@ -12,9 +12,9 @@ internal class TransientScopeRoot : ITransientScopeRoot } [CreateFunction(typeof(TransientScopeRoot), "Create")] -internal partial class Container +internal sealed partial class Container { - partial class DIE_DefaultTransientScope + private sealed partial class DIE_DefaultTransientScope { private string DIE_Factory_Yeah => "Yeah"; } diff --git a/Test/CycleDetection/Function/Cycle/DirectRecursionContainer.cs b/Test/CycleDetection/Function/Cycle/DirectRecursionContainer.cs index 8ed06963..a0f73deb 100644 --- a/Test/CycleDetection/Function/Cycle/DirectRecursionContainer.cs +++ b/Test/CycleDetection/Function/Cycle/DirectRecursionContainer.cs @@ -9,7 +9,7 @@ internal Dependency(Dependency inner) {} } [CreateFunction(typeof(Dependency), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/CycleDetection/Function/Cycle/DirectRecursionScope.cs b/Test/CycleDetection/Function/Cycle/DirectRecursionScope.cs index 0e57f7d2..49e0ffe7 100644 --- a/Test/CycleDetection/Function/Cycle/DirectRecursionScope.cs +++ b/Test/CycleDetection/Function/Cycle/DirectRecursionScope.cs @@ -9,7 +9,7 @@ internal Dependency(Dependency inner) {} } [CreateFunction(typeof(Dependency), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/CycleDetection/Function/Cycle/DirectRecursionTransientScope.cs b/Test/CycleDetection/Function/Cycle/DirectRecursionTransientScope.cs index 06e1f61a..43f1f821 100644 --- a/Test/CycleDetection/Function/Cycle/DirectRecursionTransientScope.cs +++ b/Test/CycleDetection/Function/Cycle/DirectRecursionTransientScope.cs @@ -9,7 +9,7 @@ internal Dependency(Dependency inner) {} } [CreateFunction(typeof(Dependency), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/CycleDetection/Function/NoCycle/DirectRecursionContainerFunc.cs b/Test/CycleDetection/Function/NoCycle/DirectRecursionContainerFunc.cs index 0f1301a2..2b559dfe 100644 --- a/Test/CycleDetection/Function/NoCycle/DirectRecursionContainerFunc.cs +++ b/Test/CycleDetection/Function/NoCycle/DirectRecursionContainerFunc.cs @@ -11,7 +11,7 @@ internal Dependency(Func inner) {} } [CreateFunction(typeof(Dependency), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/CycleDetection/Function/NoCycle/DirectRecursionContainerLazy.cs b/Test/CycleDetection/Function/NoCycle/DirectRecursionContainerLazy.cs index e57f16e5..7b7b9b1a 100644 --- a/Test/CycleDetection/Function/NoCycle/DirectRecursionContainerLazy.cs +++ b/Test/CycleDetection/Function/NoCycle/DirectRecursionContainerLazy.cs @@ -11,7 +11,7 @@ internal Dependency(Lazy inner) {} } [CreateFunction(typeof(Dependency), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/CycleDetection/Function/NoCycle/DirectRecursionScopeFunc.cs b/Test/CycleDetection/Function/NoCycle/DirectRecursionScopeFunc.cs index c831d0d8..0362890d 100644 --- a/Test/CycleDetection/Function/NoCycle/DirectRecursionScopeFunc.cs +++ b/Test/CycleDetection/Function/NoCycle/DirectRecursionScopeFunc.cs @@ -11,7 +11,7 @@ internal Dependency(Func inner) {} } [CreateFunction(typeof(Dependency), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/CycleDetection/Function/NoCycle/DirectRecursionScopeLazy.cs b/Test/CycleDetection/Function/NoCycle/DirectRecursionScopeLazy.cs index 18c6a66c..bcb1e78a 100644 --- a/Test/CycleDetection/Function/NoCycle/DirectRecursionScopeLazy.cs +++ b/Test/CycleDetection/Function/NoCycle/DirectRecursionScopeLazy.cs @@ -11,7 +11,7 @@ internal Dependency(Lazy inner) {} } [CreateFunction(typeof(Dependency), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/CycleDetection/Function/NoCycle/DirectRecursionTransientScopeFunc.cs b/Test/CycleDetection/Function/NoCycle/DirectRecursionTransientScopeFunc.cs index fbe9fd58..7bdc11d3 100644 --- a/Test/CycleDetection/Function/NoCycle/DirectRecursionTransientScopeFunc.cs +++ b/Test/CycleDetection/Function/NoCycle/DirectRecursionTransientScopeFunc.cs @@ -11,7 +11,7 @@ internal Dependency(Func inner) {} } [CreateFunction(typeof(Dependency), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/CycleDetection/Function/NoCycle/DirectRecursionTransientScopeLazy.cs b/Test/CycleDetection/Function/NoCycle/DirectRecursionTransientScopeLazy.cs index 8b61b2cb..3f118d96 100644 --- a/Test/CycleDetection/Function/NoCycle/DirectRecursionTransientScopeLazy.cs +++ b/Test/CycleDetection/Function/NoCycle/DirectRecursionTransientScopeLazy.cs @@ -11,7 +11,7 @@ internal Dependency(Lazy inner) {} } [CreateFunction(typeof(Dependency), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/CycleDetection/Implementation/Cycle/DirectRecursion.cs b/Test/CycleDetection/Implementation/Cycle/DirectRecursion.cs index 0ee25ce7..2628eecd 100644 --- a/Test/CycleDetection/Implementation/Cycle/DirectRecursion.cs +++ b/Test/CycleDetection/Implementation/Cycle/DirectRecursion.cs @@ -9,7 +9,7 @@ internal Dependency(Dependency inner) {} } [CreateFunction(typeof(Dependency), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/CycleDetection/Implementation/Cycle/ImplementationProxied.cs b/Test/CycleDetection/Implementation/Cycle/ImplementationProxied.cs index 11257ea7..edef5710 100644 --- a/Test/CycleDetection/Implementation/Cycle/ImplementationProxied.cs +++ b/Test/CycleDetection/Implementation/Cycle/ImplementationProxied.cs @@ -15,7 +15,7 @@ internal Dependency(Proxy inner) {} } [CreateFunction(typeof(Dependency), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/CycleDetection/Implementation/NoCycle/NoCycleInParallel.cs b/Test/CycleDetection/Implementation/NoCycle/NoCycleInParallel.cs index c72c8dea..75b1636e 100644 --- a/Test/CycleDetection/Implementation/NoCycle/NoCycleInParallel.cs +++ b/Test/CycleDetection/Implementation/NoCycle/NoCycleInParallel.cs @@ -19,7 +19,7 @@ internal Parent( } [CreateFunction(typeof(Parent), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Decorator/ContainerInstance.cs b/Test/Decorator/ContainerInstance.cs index 8d730787..d07b3f7f 100644 --- a/Test/Decorator/ContainerInstance.cs +++ b/Test/Decorator/ContainerInstance.cs @@ -23,7 +23,7 @@ public Decorator(IInterface decoratedContainerInstance) => } [CreateFunction(typeof(IInterface), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Decorator/List.cs b/Test/Decorator/List.cs index e73198eb..6fc3989b 100644 --- a/Test/Decorator/List.cs +++ b/Test/Decorator/List.cs @@ -29,7 +29,7 @@ public Decorator(IInterface decorated) => } [CreateFunction(typeof(IReadOnlyList), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Decorator/Multi.cs b/Test/Decorator/Multi.cs index c189887e..e481449e 100644 --- a/Test/Decorator/Multi.cs +++ b/Test/Decorator/Multi.cs @@ -32,7 +32,7 @@ public DecoratorB(IInterface decorated) => [CreateFunction(typeof(IInterface), "Create")] [DecoratorSequenceChoice(typeof(IInterface), typeof(DecoratorA), typeof(DecoratorB))] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Decorator/Normal.cs b/Test/Decorator/Normal.cs index ff238e4c..98751a17 100644 --- a/Test/Decorator/Normal.cs +++ b/Test/Decorator/Normal.cs @@ -23,7 +23,7 @@ public Decorator(IInterface decoratedNormal) => } [CreateFunction(typeof(IInterface), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Decorator/ScopeDecoratorForContainerDependency.cs b/Test/Decorator/ScopeDecoratorForContainerDependency.cs index 8bd1ce83..a6f0bad4 100644 --- a/Test/Decorator/ScopeDecoratorForContainerDependency.cs +++ b/Test/Decorator/ScopeDecoratorForContainerDependency.cs @@ -34,7 +34,7 @@ internal ScopeRoot(IInterface decorated, IInterface secondDecorator) } [CreateFunction(typeof(ScopeRoot), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Decorator/ScopeDecoratorForTransientScopeDependency.cs b/Test/Decorator/ScopeDecoratorForTransientScopeDependency.cs index 03a97318..41543545 100644 --- a/Test/Decorator/ScopeDecoratorForTransientScopeDependency.cs +++ b/Test/Decorator/ScopeDecoratorForTransientScopeDependency.cs @@ -34,7 +34,7 @@ internal ScopeRoot(IInterface decorated, IInterface secondDecorator) } [CreateFunction(typeof(ScopeRoot), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Decorator/SequenceEdgeCase.cs b/Test/Decorator/SequenceEdgeCase.cs index b686748a..f62bedb0 100644 --- a/Test/Decorator/SequenceEdgeCase.cs +++ b/Test/Decorator/SequenceEdgeCase.cs @@ -46,18 +46,18 @@ internal class ScopeRoot1 : IScopeRoot [CreateFunction(typeof(ScopeRoot1), "Create1")] [CreateFunction(typeof(IInterface), "CreateFromContainerAsSanityCheck")] [DecoratorSequenceChoice(typeof(IInterface))] -internal partial class Container +internal sealed partial class Container { [DecoratorSequenceChoice(typeof(IInterface), typeof(DecoratorA), typeof(DecoratorB))] [CustomScopeForRootTypes(typeof(ScopeRoot0))] - private partial class DIE_Scope_0 + private sealed partial class DIE_Scope_0 { } [DecoratorSequenceChoice(typeof(IInterface), typeof(DecoratorA))] [CustomScopeForRootTypes(typeof(ScopeRoot1))] - private partial class DIE_Scope_1 + private sealed partial class DIE_Scope_1 { } diff --git a/Test/Disposal/Async/InContainer.cs b/Test/Disposal/Async/InContainer.cs index e013fd1c..b67497f7 100644 --- a/Test/Disposal/Async/InContainer.cs +++ b/Test/Disposal/Async/InContainer.cs @@ -17,7 +17,7 @@ public async ValueTask DisposeAsync() } [CreateFunction(typeof(Dependency), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Disposal/Async/InScope.cs b/Test/Disposal/Async/InScope.cs index c136d8dc..b0c8b5e2 100644 --- a/Test/Disposal/Async/InScope.cs +++ b/Test/Disposal/Async/InScope.cs @@ -24,7 +24,7 @@ internal class ScopeRoot : IScopeRoot } [CreateFunction(typeof(ScopeRoot), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Disposal/Async/InScopeInTransientScope.cs b/Test/Disposal/Async/InScopeInTransientScope.cs index 345e611a..9c88feef 100644 --- a/Test/Disposal/Async/InScopeInTransientScope.cs +++ b/Test/Disposal/Async/InScopeInTransientScope.cs @@ -40,7 +40,7 @@ internal TransientScopeRoot( } [CreateFunction(typeof(TransientScopeRoot), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Disposal/Async/InTransientScope.cs b/Test/Disposal/Async/InTransientScope.cs index f70296bc..820ef323 100644 --- a/Test/Disposal/Async/InTransientScope.cs +++ b/Test/Disposal/Async/InTransientScope.cs @@ -24,7 +24,7 @@ internal class TransientScopeRoot : ITransientScopeRoot } [CreateFunction(typeof(TransientScopeRoot), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Disposal/Async/InTransientScopeInTransientScope.cs b/Test/Disposal/Async/InTransientScopeInTransientScope.cs index 9cbabbef..dae27a0a 100644 --- a/Test/Disposal/Async/InTransientScopeInTransientScope.cs +++ b/Test/Disposal/Async/InTransientScopeInTransientScope.cs @@ -43,7 +43,7 @@ internal TransientScopeRoot( } [CreateFunction(typeof(TransientScopeRoot), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Disposal/ContainerUserDefinedAddForDisposal.cs b/Test/Disposal/ContainerUserDefinedAddForDisposal.cs index e10c04bc..e297fe05 100644 --- a/Test/Disposal/ContainerUserDefinedAddForDisposal.cs +++ b/Test/Disposal/ContainerUserDefinedAddForDisposal.cs @@ -13,7 +13,7 @@ internal class Dependency : IDisposable } [CreateFunction(typeof(Dependency), "Create")] -internal partial class Container +internal sealed partial class Container { private Dependency DIE_Factory_Dependency { diff --git a/Test/Disposal/ContainerUserDefinedAddForDisposalAsync.cs b/Test/Disposal/ContainerUserDefinedAddForDisposalAsync.cs index 106e646b..bfacd5b2 100644 --- a/Test/Disposal/ContainerUserDefinedAddForDisposalAsync.cs +++ b/Test/Disposal/ContainerUserDefinedAddForDisposalAsync.cs @@ -17,7 +17,7 @@ public ValueTask DisposeAsync() } [CreateFunction(typeof(Dependency), "Create")] -internal partial class Container +internal sealed partial class Container { private Dependency DIE_Factory_Dependency { diff --git a/Test/Disposal/ScopeUserDefinedAddForDisposal.cs b/Test/Disposal/ScopeUserDefinedAddForDisposal.cs index df4b7690..1f63d7d9 100644 --- a/Test/Disposal/ScopeUserDefinedAddForDisposal.cs +++ b/Test/Disposal/ScopeUserDefinedAddForDisposal.cs @@ -23,9 +23,9 @@ internal ScopeRoot(Dependency dependency) } [CreateFunction(typeof(ScopeRoot), "Create")] -internal partial class Container +internal sealed partial class Container { - private partial class DIE_DefaultScope + private sealed partial class DIE_DefaultScope { private Dependency DIE_Factory_Dependency { diff --git a/Test/Disposal/ScopeUserDefinedAddForDisposalAsync.cs b/Test/Disposal/ScopeUserDefinedAddForDisposalAsync.cs index 3c5b6352..8313eb35 100644 --- a/Test/Disposal/ScopeUserDefinedAddForDisposalAsync.cs +++ b/Test/Disposal/ScopeUserDefinedAddForDisposalAsync.cs @@ -27,9 +27,9 @@ internal ScopeRoot(Dependency dependency) } [CreateFunction(typeof(ScopeRoot), "Create")] -internal partial class Container +internal sealed partial class Container { - private partial class DIE_DefaultScope + private sealed partial class DIE_DefaultScope { private Dependency DIE_Factory_Dependency { @@ -41,7 +41,7 @@ private Dependency DIE_Factory_Dependency } } - private partial void DIE_AddForDisposalAsync(IAsyncDisposable disposable); + private partial void DIE_AddForDisposalAsync(IAsyncDisposable asyncDisposable); } } diff --git a/Test/Disposal/Sync/InContainer.cs b/Test/Disposal/Sync/InContainer.cs index 919c4672..bf927eb4 100644 --- a/Test/Disposal/Sync/InContainer.cs +++ b/Test/Disposal/Sync/InContainer.cs @@ -15,7 +15,7 @@ public void Dispose() } [CreateFunction(typeof(Dependency), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Disposal/Sync/InScope.cs b/Test/Disposal/Sync/InScope.cs index 4f52d3d0..3855b930 100644 --- a/Test/Disposal/Sync/InScope.cs +++ b/Test/Disposal/Sync/InScope.cs @@ -19,7 +19,7 @@ internal class ScopeRoot : IScopeRoot } [CreateFunction(typeof(ScopeRoot), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Disposal/Sync/InScopeInTransientScope.cs b/Test/Disposal/Sync/InScopeInTransientScope.cs index b03f0cc6..c734a78c 100644 --- a/Test/Disposal/Sync/InScopeInTransientScope.cs +++ b/Test/Disposal/Sync/InScopeInTransientScope.cs @@ -35,7 +35,7 @@ internal TransientScopeRoot( } [CreateFunction(typeof(TransientScopeRoot), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Disposal/Sync/InTransientScope.cs b/Test/Disposal/Sync/InTransientScope.cs index 399eae74..b38a6c27 100644 --- a/Test/Disposal/Sync/InTransientScope.cs +++ b/Test/Disposal/Sync/InTransientScope.cs @@ -19,7 +19,7 @@ internal class TransientScopeRoot : ITransientScopeRoot } [CreateFunction(typeof(TransientScopeRoot), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Disposal/Sync/InTransientScopeInTransientScope.cs b/Test/Disposal/Sync/InTransientScopeInTransientScope.cs index 0f9f2d65..2907d416 100644 --- a/Test/Disposal/Sync/InTransientScopeInTransientScope.cs +++ b/Test/Disposal/Sync/InTransientScopeInTransientScope.cs @@ -38,7 +38,7 @@ internal TransientScopeRoot( } [CreateFunction(typeof(TransientScopeRoot), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Disposal/TransientScopeDisposalHandle/AsyncContainerToAsyncDisposalHandle.cs b/Test/Disposal/TransientScopeDisposalHandle/AsyncContainerToAsyncDisposalHandle.cs index b364468b..39956b8a 100644 --- a/Test/Disposal/TransientScopeDisposalHandle/AsyncContainerToAsyncDisposalHandle.cs +++ b/Test/Disposal/TransientScopeDisposalHandle/AsyncContainerToAsyncDisposalHandle.cs @@ -33,7 +33,7 @@ internal TransientScopeRoot( } [CreateFunction(typeof(TransientScopeRoot), "Create")] -internal partial class Container {} +internal sealed partial class Container {} public class Tests { diff --git a/Test/Disposal/TransientScopeDisposalHandle/NoneContainerToAsyncDisposalHandle.cs b/Test/Disposal/TransientScopeDisposalHandle/NoneContainerToAsyncDisposalHandle.cs index 42931f5b..27713fe4 100644 --- a/Test/Disposal/TransientScopeDisposalHandle/NoneContainerToAsyncDisposalHandle.cs +++ b/Test/Disposal/TransientScopeDisposalHandle/NoneContainerToAsyncDisposalHandle.cs @@ -27,7 +27,7 @@ internal TransientScopeRoot( } [CreateFunction(typeof(TransientScopeRoot), "Create")] -internal partial class Container {} +internal sealed partial class Container {} public class Tests { diff --git a/Test/Disposal/TransientScopeDisposalHandle/NoneContainerToSyncDisposalHandle.cs b/Test/Disposal/TransientScopeDisposalHandle/NoneContainerToSyncDisposalHandle.cs index f8cba235..ac0d95e9 100644 --- a/Test/Disposal/TransientScopeDisposalHandle/NoneContainerToSyncDisposalHandle.cs +++ b/Test/Disposal/TransientScopeDisposalHandle/NoneContainerToSyncDisposalHandle.cs @@ -26,7 +26,7 @@ internal TransientScopeRoot( } [CreateFunction(typeof(TransientScopeRoot), "Create")] -internal partial class Container {} +internal sealed partial class Container {} public class Tests { diff --git a/Test/Disposal/TransientScopeDisposalHandle/SyncContainerToAsyncDisposalHandle.cs b/Test/Disposal/TransientScopeDisposalHandle/SyncContainerToAsyncDisposalHandle.cs index 46866d02..34c72bfb 100644 --- a/Test/Disposal/TransientScopeDisposalHandle/SyncContainerToAsyncDisposalHandle.cs +++ b/Test/Disposal/TransientScopeDisposalHandle/SyncContainerToAsyncDisposalHandle.cs @@ -29,7 +29,7 @@ internal TransientScopeRoot( } [CreateFunction(typeof(TransientScopeRoot), "Create")] -internal partial class Container {} +internal sealed partial class Container {} public class Tests { diff --git a/Test/Disposal/TransientScopeDisposalHandle/SyncContainerToSyncDisposalHandle.cs b/Test/Disposal/TransientScopeDisposalHandle/SyncContainerToSyncDisposalHandle.cs index 7b63208b..686f4669 100644 --- a/Test/Disposal/TransientScopeDisposalHandle/SyncContainerToSyncDisposalHandle.cs +++ b/Test/Disposal/TransientScopeDisposalHandle/SyncContainerToSyncDisposalHandle.cs @@ -28,7 +28,7 @@ internal TransientScopeRoot( } [CreateFunction(typeof(TransientScopeRoot), "Create")] -internal partial class Container {} +internal sealed partial class Container {} public class Tests { diff --git a/Test/Disposal/TransientScopeUserDefinedAddForDisposal.cs b/Test/Disposal/TransientScopeUserDefinedAddForDisposal.cs index a3f1a94e..394673de 100644 --- a/Test/Disposal/TransientScopeUserDefinedAddForDisposal.cs +++ b/Test/Disposal/TransientScopeUserDefinedAddForDisposal.cs @@ -23,9 +23,9 @@ internal TransientScopeRoot(Dependency dependency) } [CreateFunction(typeof(TransientScopeRoot), "Create")] -internal partial class Container +internal sealed partial class Container { - private partial class DIE_DefaultTransientScope + private sealed partial class DIE_DefaultTransientScope { private Dependency DIE_Factory_Dependency { diff --git a/Test/Disposal/TransientScopeUserDefinedAddForDisposalAsync.cs b/Test/Disposal/TransientScopeUserDefinedAddForDisposalAsync.cs index df011fad..92ef61b8 100644 --- a/Test/Disposal/TransientScopeUserDefinedAddForDisposalAsync.cs +++ b/Test/Disposal/TransientScopeUserDefinedAddForDisposalAsync.cs @@ -27,9 +27,9 @@ internal TransientScopeRoot(Dependency dependency) } [CreateFunction(typeof(TransientScopeRoot), "Create")] -internal partial class Container +internal sealed partial class Container { - private partial class DIE_DefaultTransientScope + private sealed partial class DIE_DefaultTransientScope { private Dependency DIE_Factory_Dependency { @@ -41,7 +41,7 @@ private Dependency DIE_Factory_Dependency } } - private partial void DIE_AddForDisposalAsync(IAsyncDisposable disposable); + private partial void DIE_AddForDisposalAsync(IAsyncDisposable asyncDisposable); } } diff --git a/Test/Func/Double.cs b/Test/Func/Double.cs index 76baf97c..405ff5f5 100644 --- a/Test/Func/Double.cs +++ b/Test/Func/Double.cs @@ -18,7 +18,7 @@ internal Parent( } [CreateFunction(typeof(Parent), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Func/Vanilla.cs b/Test/Func/Vanilla.cs index 11945871..b7d0e918 100644 --- a/Test/Func/Vanilla.cs +++ b/Test/Func/Vanilla.cs @@ -9,7 +9,7 @@ namespace MrMeeseeks.DIE.Test.Func.Vanilla; internal class Dependency{} [CreateFunction(typeof(Func, Dependency>), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Generics/Choice/Double.cs b/Test/Generics/Choice/Double.cs index c985de7c..4390c8a1 100644 --- a/Test/Generics/Choice/Double.cs +++ b/Test/Generics/Choice/Double.cs @@ -10,7 +10,7 @@ internal class Class : IInterface {} [GenericParameterChoice(typeof(Class<,>), "T1", typeof(string))] [CreateFunction(typeof(IInterface), "Create")] -internal partial class Container {} +internal sealed partial class Container {} public class Tests { diff --git a/Test/Generics/Choice/DoubleBothChosen.cs b/Test/Generics/Choice/DoubleBothChosen.cs index 94c19e61..33357986 100644 --- a/Test/Generics/Choice/DoubleBothChosen.cs +++ b/Test/Generics/Choice/DoubleBothChosen.cs @@ -11,7 +11,7 @@ internal class Class : IInterface {} [GenericParameterChoice(typeof(Class<,>), "T0", typeof(int))] [GenericParameterChoice(typeof(Class<,>), "T1", typeof(string))] [CreateFunction(typeof(IInterface), "Create")] -internal partial class Container {} +internal sealed partial class Container {} public class Tests { diff --git a/Test/Generics/Choice/DoubleBothChosenWithSingleOtherSubstitute.cs b/Test/Generics/Choice/DoubleBothChosenWithSingleOtherSubstitute.cs index 82578973..b0b2eaf1 100644 --- a/Test/Generics/Choice/DoubleBothChosenWithSingleOtherSubstitute.cs +++ b/Test/Generics/Choice/DoubleBothChosenWithSingleOtherSubstitute.cs @@ -13,7 +13,7 @@ internal class Class : IInterface {} [GenericParameterSubstitutesChoice(typeof(Class<,>), "T1", typeof(bool))] [GenericParameterChoice(typeof(Class<,>), "T1", typeof(string))] [CreateFunction(typeof(IInterface), "Create")] -internal partial class Container {} +internal sealed partial class Container {} public class Tests { diff --git a/Test/Generics/Choice/DoubleWithSingleOtherSubstitute.cs b/Test/Generics/Choice/DoubleWithSingleOtherSubstitute.cs index 344b7d7f..30f806b3 100644 --- a/Test/Generics/Choice/DoubleWithSingleOtherSubstitute.cs +++ b/Test/Generics/Choice/DoubleWithSingleOtherSubstitute.cs @@ -11,7 +11,7 @@ internal class Class : IInterface {} [GenericParameterSubstitutesChoice(typeof(Class<,>), "T1", typeof(bool))] [GenericParameterChoice(typeof(Class<,>), "T1", typeof(string))] [CreateFunction(typeof(IInterface), "Create")] -internal partial class Container {} +internal sealed partial class Container {} public class Tests { diff --git a/Test/Generics/Choice/Single.cs b/Test/Generics/Choice/Single.cs index 618a7f2e..1cf48545 100644 --- a/Test/Generics/Choice/Single.cs +++ b/Test/Generics/Choice/Single.cs @@ -10,7 +10,7 @@ internal class Class : IInterface {} [GenericParameterChoice(typeof(Class<>), "T0", typeof(int))] [CreateFunction(typeof(IInterface), "Create")] -internal partial class Container {} +internal sealed partial class Container {} public class Tests { diff --git a/Test/Generics/Choice/SingleWithSingleOtherSubstitute.cs b/Test/Generics/Choice/SingleWithSingleOtherSubstitute.cs index 4f518b4a..1febfc35 100644 --- a/Test/Generics/Choice/SingleWithSingleOtherSubstitute.cs +++ b/Test/Generics/Choice/SingleWithSingleOtherSubstitute.cs @@ -11,7 +11,7 @@ internal class Class : IInterface {} [GenericParameterSubstitutesChoice(typeof(Class<>), "T0", typeof(bool))] [GenericParameterChoice(typeof(Class<>), "T0", typeof(int))] [CreateFunction(typeof(IInterface), "Create")] -internal partial class Container {} +internal sealed partial class Container {} public class Tests { diff --git a/Test/Generics/ChoiceIndirectlyBySingleSubstitute/Double.cs b/Test/Generics/ChoiceIndirectlyBySingleSubstitute/Double.cs index 2be7e21c..9550c0a4 100644 --- a/Test/Generics/ChoiceIndirectlyBySingleSubstitute/Double.cs +++ b/Test/Generics/ChoiceIndirectlyBySingleSubstitute/Double.cs @@ -10,7 +10,7 @@ internal class Class : IInterface {} [GenericParameterSubstitutesChoice(typeof(Class<,>), "T1", typeof(string))] [CreateFunction(typeof(IInterface), "Create")] -internal partial class Container {} +internal sealed partial class Container {} public class Tests { diff --git a/Test/Generics/ChoiceIndirectlyBySingleSubstitute/Single.cs b/Test/Generics/ChoiceIndirectlyBySingleSubstitute/Single.cs index 63e8ce9e..82383caf 100644 --- a/Test/Generics/ChoiceIndirectlyBySingleSubstitute/Single.cs +++ b/Test/Generics/ChoiceIndirectlyBySingleSubstitute/Single.cs @@ -10,7 +10,7 @@ internal class Class : IInterface {} [GenericParameterSubstitutesChoice(typeof(Class<>), "T0", typeof(int))] [CreateFunction(typeof(IInterface), "Create")] -internal partial class Container {} +internal sealed partial class Container {} public class Tests { diff --git a/Test/Generics/Configuration/AsyncTransient.cs b/Test/Generics/Configuration/AsyncTransient.cs index 12f4b776..5c2a1331 100644 --- a/Test/Generics/Configuration/AsyncTransient.cs +++ b/Test/Generics/Configuration/AsyncTransient.cs @@ -25,7 +25,7 @@ public async ValueTask DisposeAsync() } [CreateFunction(typeof(Class), "Create")] -internal partial class Container {} +internal sealed partial class Container {} public class Tests { diff --git a/Test/Generics/Configuration/AsyncTransientWithJustTransient.cs b/Test/Generics/Configuration/AsyncTransientWithJustTransient.cs index 7a55ce93..2241ced0 100644 --- a/Test/Generics/Configuration/AsyncTransientWithJustTransient.cs +++ b/Test/Generics/Configuration/AsyncTransientWithJustTransient.cs @@ -25,7 +25,7 @@ public async ValueTask DisposeAsync() } [CreateFunction(typeof(Class), "Create")] -internal partial class Container {} +internal sealed partial class Container {} public class Tests { diff --git a/Test/Generics/Configuration/Composite.cs b/Test/Generics/Configuration/Composite.cs index 98f606ad..3b1e4af3 100644 --- a/Test/Generics/Configuration/Composite.cs +++ b/Test/Generics/Configuration/Composite.cs @@ -31,7 +31,7 @@ internal Composite( [GenericParameterChoice(typeof(Composite<>), "T0", typeof(int))] [CreateFunction(typeof(IInterface), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Generics/Configuration/ConstructorChoice.cs b/Test/Generics/Configuration/ConstructorChoice.cs index 19e7d360..b1a4dad9 100644 --- a/Test/Generics/Configuration/ConstructorChoice.cs +++ b/Test/Generics/Configuration/ConstructorChoice.cs @@ -21,7 +21,7 @@ internal class Implementation [ConstructorChoice(typeof(Implementation<>), typeof(DependencyB))] [CreateFunction(typeof(Implementation), "Create")] -internal partial class Container {} +internal sealed partial class Container {} public class Tests { diff --git a/Test/Generics/Configuration/ContainerInstance.cs b/Test/Generics/Configuration/ContainerInstance.cs index f35fa68c..065cb55c 100644 --- a/Test/Generics/Configuration/ContainerInstance.cs +++ b/Test/Generics/Configuration/ContainerInstance.cs @@ -7,7 +7,7 @@ namespace MrMeeseeks.DIE.Test.Generics.Configuration.ContainerInstance; internal class Class : IContainerInstance { } [CreateFunction(typeof(Class), "Create")] -internal partial class Container {} +internal sealed partial class Container {} public class Tests { diff --git a/Test/Generics/Configuration/ContainerInstanceWithDifferentGenericParameter.cs b/Test/Generics/Configuration/ContainerInstanceWithDifferentGenericParameter.cs index 6634cbbc..53846bb0 100644 --- a/Test/Generics/Configuration/ContainerInstanceWithDifferentGenericParameter.cs +++ b/Test/Generics/Configuration/ContainerInstanceWithDifferentGenericParameter.cs @@ -8,7 +8,7 @@ internal class Class : IContainerInstance { } [CreateFunction(typeof(Class), "Create")] [CreateFunction(typeof(Class), "CreateString")] -internal partial class Container {} +internal sealed partial class Container {} public class Tests { diff --git a/Test/Generics/Configuration/Decorator.cs b/Test/Generics/Configuration/Decorator.cs index c8a85395..e6b1f9f4 100644 --- a/Test/Generics/Configuration/Decorator.cs +++ b/Test/Generics/Configuration/Decorator.cs @@ -36,7 +36,7 @@ internal DecoratorB( [GenericParameterChoice(typeof(DecoratorB<>), "T0", typeof(string))] [DecoratorSequenceChoice(typeof(IInterface), typeof(DecoratorA<>), typeof(DecoratorB<>))] [CreateFunction(typeof(IInterface), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Generics/Configuration/InitializerImplementationAsync.cs b/Test/Generics/Configuration/InitializerImplementationAsync.cs index d9e697bb..2838ac39 100644 --- a/Test/Generics/Configuration/InitializerImplementationAsync.cs +++ b/Test/Generics/Configuration/InitializerImplementationAsync.cs @@ -17,7 +17,7 @@ internal async Task InitializeAsync() [TypeInitializer(typeof(Dependency<>), nameof(Dependency.InitializeAsync))] [CreateFunction(typeof(Dependency), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Generics/Configuration/InitializerImplementationAsyncValue.cs b/Test/Generics/Configuration/InitializerImplementationAsyncValue.cs index 34a55956..68ba4f83 100644 --- a/Test/Generics/Configuration/InitializerImplementationAsyncValue.cs +++ b/Test/Generics/Configuration/InitializerImplementationAsyncValue.cs @@ -17,7 +17,7 @@ internal async ValueTask InitializeAsync() [TypeInitializer(typeof(Dependency<>), nameof(Dependency.InitializeAsync))] [CreateFunction(typeof(Dependency), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Generics/Configuration/InitializerImplementationSync.cs b/Test/Generics/Configuration/InitializerImplementationSync.cs index 6efbf80e..6b5bb1ea 100644 --- a/Test/Generics/Configuration/InitializerImplementationSync.cs +++ b/Test/Generics/Configuration/InitializerImplementationSync.cs @@ -16,7 +16,7 @@ internal void Initialize() [TypeInitializer(typeof(Dependency<>), nameof(Dependency.Initialize))] [CreateFunction(typeof(Dependency), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Generics/Configuration/InitializerInterfaceAsync.cs b/Test/Generics/Configuration/InitializerInterfaceAsync.cs index b011fde5..18a5524d 100644 --- a/Test/Generics/Configuration/InitializerInterfaceAsync.cs +++ b/Test/Generics/Configuration/InitializerInterfaceAsync.cs @@ -16,7 +16,7 @@ async Task ITaskTypeInitializer.InitializeAsync() } [CreateFunction(typeof(Dependency), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Generics/Configuration/InitializerInterfaceAsyncValue.cs b/Test/Generics/Configuration/InitializerInterfaceAsyncValue.cs index 48948ae1..4e7abafc 100644 --- a/Test/Generics/Configuration/InitializerInterfaceAsyncValue.cs +++ b/Test/Generics/Configuration/InitializerInterfaceAsyncValue.cs @@ -16,7 +16,7 @@ async ValueTask IValueTaskTypeInitializer.InitializeAsync() } [CreateFunction(typeof(Dependency), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Generics/Configuration/InitializerInterfaceSync.cs b/Test/Generics/Configuration/InitializerInterfaceSync.cs index 93c8f99a..9f9eb390 100644 --- a/Test/Generics/Configuration/InitializerInterfaceSync.cs +++ b/Test/Generics/Configuration/InitializerInterfaceSync.cs @@ -15,7 +15,7 @@ void ITypeInitializer.Initialize() } [CreateFunction(typeof(Dependency), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Generics/Configuration/InterfaceGenericComposite.cs b/Test/Generics/Configuration/InterfaceGenericComposite.cs index 8bf041c0..cbd66c67 100644 --- a/Test/Generics/Configuration/InterfaceGenericComposite.cs +++ b/Test/Generics/Configuration/InterfaceGenericComposite.cs @@ -31,7 +31,7 @@ internal Composite( [GenericParameterChoice(typeof(Composite<,>), "T1", typeof(string))] [CreateFunction(typeof(IInterface), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Generics/Configuration/InterfaceGenericDecorator.cs b/Test/Generics/Configuration/InterfaceGenericDecorator.cs index 648676af..3569137e 100644 --- a/Test/Generics/Configuration/InterfaceGenericDecorator.cs +++ b/Test/Generics/Configuration/InterfaceGenericDecorator.cs @@ -36,7 +36,7 @@ internal DecoratorB( [GenericParameterChoice(typeof(DecoratorB<,>), "T0", typeof(string))] [DecoratorSequenceChoice(typeof(IInterface<>), typeof(DecoratorA<,>), typeof(DecoratorB<,>))] [CreateFunction(typeof(IInterface), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Generics/Configuration/ScopeInstance.cs b/Test/Generics/Configuration/ScopeInstance.cs index 39528f83..cc44f3d4 100644 --- a/Test/Generics/Configuration/ScopeInstance.cs +++ b/Test/Generics/Configuration/ScopeInstance.cs @@ -21,7 +21,7 @@ internal ScopeRoot( } [CreateFunction(typeof(ScopeRoot), "Create")] -internal partial class Container {} +internal sealed partial class Container {} public class Tests { diff --git a/Test/Generics/Configuration/ScopeInstanceWithDifferentGenericParameter.cs b/Test/Generics/Configuration/ScopeInstanceWithDifferentGenericParameter.cs index cef87288..ea88f9fa 100644 --- a/Test/Generics/Configuration/ScopeInstanceWithDifferentGenericParameter.cs +++ b/Test/Generics/Configuration/ScopeInstanceWithDifferentGenericParameter.cs @@ -21,7 +21,7 @@ internal ScopeRoot( } [CreateFunction(typeof(ScopeRoot), "Create")] -internal partial class Container {} +internal sealed partial class Container {} public class Tests { diff --git a/Test/Generics/Configuration/ScopeRoot.cs b/Test/Generics/Configuration/ScopeRoot.cs index e035e295..6e231c3e 100644 --- a/Test/Generics/Configuration/ScopeRoot.cs +++ b/Test/Generics/Configuration/ScopeRoot.cs @@ -28,7 +28,7 @@ internal Root( } [CreateFunction(typeof(Root), "Create")] -internal partial class Container {} +internal sealed partial class Container {} public class Tests { diff --git a/Test/Generics/Configuration/SyncTransient.cs b/Test/Generics/Configuration/SyncTransient.cs index 8ca8d51d..1b236ff8 100644 --- a/Test/Generics/Configuration/SyncTransient.cs +++ b/Test/Generics/Configuration/SyncTransient.cs @@ -20,7 +20,7 @@ internal Class(Managed _) { } } [CreateFunction(typeof(Class), "Create")] -internal partial class Container {} +internal sealed partial class Container {} public class Tests { diff --git a/Test/Generics/Configuration/SyncTransientWithJustTransient.cs b/Test/Generics/Configuration/SyncTransientWithJustTransient.cs index cc269045..ade2d2be 100644 --- a/Test/Generics/Configuration/SyncTransientWithJustTransient.cs +++ b/Test/Generics/Configuration/SyncTransientWithJustTransient.cs @@ -20,7 +20,7 @@ internal Class(Managed _) { } } [CreateFunction(typeof(Class), "Create")] -internal partial class Container {} +internal sealed partial class Container {} public class Tests { diff --git a/Test/Generics/Configuration/TransientScopeInstance.cs b/Test/Generics/Configuration/TransientScopeInstance.cs index aca4d0ff..13e179d2 100644 --- a/Test/Generics/Configuration/TransientScopeInstance.cs +++ b/Test/Generics/Configuration/TransientScopeInstance.cs @@ -21,7 +21,7 @@ internal TransientScopeRoot( } [CreateFunction(typeof(TransientScopeRoot), "Create")] -internal partial class Container {} +internal sealed partial class Container {} public class Tests { diff --git a/Test/Generics/Configuration/TransientScopeInstanceWithDifferentGenericParameter.cs b/Test/Generics/Configuration/TransientScopeInstanceWithDifferentGenericParameter.cs index 3ef0da97..14ce6d92 100644 --- a/Test/Generics/Configuration/TransientScopeInstanceWithDifferentGenericParameter.cs +++ b/Test/Generics/Configuration/TransientScopeInstanceWithDifferentGenericParameter.cs @@ -21,7 +21,7 @@ internal TransientScopeRoot( } [CreateFunction(typeof(TransientScopeRoot), "Create")] -internal partial class Container {} +internal sealed partial class Container {} public class Tests { diff --git a/Test/Generics/Configuration/TransientScopeRoot.cs b/Test/Generics/Configuration/TransientScopeRoot.cs index 49ee9dbc..e3e88a62 100644 --- a/Test/Generics/Configuration/TransientScopeRoot.cs +++ b/Test/Generics/Configuration/TransientScopeRoot.cs @@ -28,7 +28,7 @@ internal Root( } [CreateFunction(typeof(Root), "Create")] -internal partial class Container {} +internal sealed partial class Container {} public class Tests { diff --git a/Test/Generics/Implementation/Double.cs b/Test/Generics/Implementation/Double.cs index ffd29de7..ae89f5b7 100644 --- a/Test/Generics/Implementation/Double.cs +++ b/Test/Generics/Implementation/Double.cs @@ -7,7 +7,7 @@ namespace MrMeeseeks.DIE.Test.Generics.Implementation.Double; internal class Class {} [CreateFunction(typeof(Class), "Create")] -internal partial class Container {} +internal sealed partial class Container {} public class Tests { diff --git a/Test/Generics/Implementation/Single.cs b/Test/Generics/Implementation/Single.cs index 718d90fb..27f7adec 100644 --- a/Test/Generics/Implementation/Single.cs +++ b/Test/Generics/Implementation/Single.cs @@ -7,7 +7,7 @@ namespace MrMeeseeks.DIE.Test.Generics.Implementation.Single; internal class Class {} [CreateFunction(typeof(Class), "Create")] -internal partial class Container {} +internal sealed partial class Container {} public class Tests { diff --git a/Test/Generics/Interface/Double.cs b/Test/Generics/Interface/Double.cs index 3b539a54..2a205b05 100644 --- a/Test/Generics/Interface/Double.cs +++ b/Test/Generics/Interface/Double.cs @@ -9,7 +9,7 @@ internal interface IInterface {} internal class Class : IInterface {} [CreateFunction(typeof(IInterface), "Create")] -internal partial class Container {} +internal sealed partial class Container {} public class Tests { diff --git a/Test/Generics/Interface/DoubleAndOneFixed.cs b/Test/Generics/Interface/DoubleAndOneFixed.cs index af69f76a..eb05c6ef 100644 --- a/Test/Generics/Interface/DoubleAndOneFixed.cs +++ b/Test/Generics/Interface/DoubleAndOneFixed.cs @@ -9,7 +9,7 @@ internal interface IInterface {} internal class Class : IInterface {} [CreateFunction(typeof(IInterface), "Create")] -internal partial class Container {} +internal sealed partial class Container {} public class Tests { diff --git a/Test/Generics/Interface/DoubleAndSetToSame.cs b/Test/Generics/Interface/DoubleAndSetToSame.cs index 67b6b1eb..3c060d8a 100644 --- a/Test/Generics/Interface/DoubleAndSetToSame.cs +++ b/Test/Generics/Interface/DoubleAndSetToSame.cs @@ -9,7 +9,7 @@ internal interface IInterface {} internal class Class : IInterface {} [CreateFunction(typeof(IInterface), "Create")] -internal partial class Container {} +internal sealed partial class Container {} public class Tests { diff --git a/Test/Generics/Interface/DoubleSwitched.cs b/Test/Generics/Interface/DoubleSwitched.cs index 012b2006..76e04d2d 100644 --- a/Test/Generics/Interface/DoubleSwitched.cs +++ b/Test/Generics/Interface/DoubleSwitched.cs @@ -9,7 +9,7 @@ internal interface IInterface {} internal class Class : IInterface {} [CreateFunction(typeof(IInterface), "Create")] -internal partial class Container {} +internal sealed partial class Container {} public class Tests { diff --git a/Test/Generics/Interface/Single.cs b/Test/Generics/Interface/Single.cs index 79a99b88..486f18f3 100644 --- a/Test/Generics/Interface/Single.cs +++ b/Test/Generics/Interface/Single.cs @@ -9,7 +9,7 @@ internal interface IInterface {} internal class Class : IInterface {} [CreateFunction(typeof(IInterface), "Create")] -internal partial class Container {} +internal sealed partial class Container {} public class Tests { diff --git a/Test/Generics/Interface/SingleAndBaseImplementationDoubleButOneFixed.cs b/Test/Generics/Interface/SingleAndBaseImplementationDoubleButOneFixed.cs index 94570425..d983df21 100644 --- a/Test/Generics/Interface/SingleAndBaseImplementationDoubleButOneFixed.cs +++ b/Test/Generics/Interface/SingleAndBaseImplementationDoubleButOneFixed.cs @@ -11,7 +11,7 @@ internal abstract class BaseClass : IInterface {} internal class Class : BaseClass {} [CreateFunction(typeof(IInterface), "Create")] -internal partial class Container {} +internal sealed partial class Container {} public class Tests { diff --git a/Test/Generics/SubstituteCollection/Double.cs b/Test/Generics/SubstituteCollection/Double.cs index 4134178a..00de61e6 100644 --- a/Test/Generics/SubstituteCollection/Double.cs +++ b/Test/Generics/SubstituteCollection/Double.cs @@ -11,7 +11,7 @@ internal class Class : IInterface {} [GenericParameterSubstitutesChoice(typeof(Class<,>), "T1", typeof(int), typeof(string))] [CreateFunction(typeof(IReadOnlyList>), "Create")] -internal partial class Container {} +internal sealed partial class Container {} public class Tests { diff --git a/Test/Generics/SubstituteCollection/DoubleBothSubstituted.cs b/Test/Generics/SubstituteCollection/DoubleBothSubstituted.cs index 132cb456..42859ed4 100644 --- a/Test/Generics/SubstituteCollection/DoubleBothSubstituted.cs +++ b/Test/Generics/SubstituteCollection/DoubleBothSubstituted.cs @@ -12,7 +12,7 @@ internal class Class : IInterface {} [GenericParameterSubstitutesChoice(typeof(Class<,>), "T0", typeof(bool), typeof(byte))] [GenericParameterSubstitutesChoice(typeof(Class<,>), "T1", typeof(int), typeof(string))] [CreateFunction(typeof(IReadOnlyList), "Create")] -internal partial class Container {} +internal sealed partial class Container {} public class Tests { diff --git a/Test/Generics/SubstituteCollection/DoubleBothSubstitutedWithChoice.cs b/Test/Generics/SubstituteCollection/DoubleBothSubstitutedWithChoice.cs index fe44ffd8..d88896ac 100644 --- a/Test/Generics/SubstituteCollection/DoubleBothSubstitutedWithChoice.cs +++ b/Test/Generics/SubstituteCollection/DoubleBothSubstitutedWithChoice.cs @@ -14,7 +14,7 @@ internal class Class : IInterface {} [GenericParameterChoice(typeof(Class<,>), "T0", typeof(byte))] [GenericParameterChoice(typeof(Class<,>), "T1", typeof(string))] [CreateFunction(typeof(IReadOnlyList), "Create")] -internal partial class Container {} +internal sealed partial class Container {} public class Tests { diff --git a/Test/Generics/SubstituteCollection/DoubleWithChoice.cs b/Test/Generics/SubstituteCollection/DoubleWithChoice.cs index d2555968..295a80d2 100644 --- a/Test/Generics/SubstituteCollection/DoubleWithChoice.cs +++ b/Test/Generics/SubstituteCollection/DoubleWithChoice.cs @@ -12,7 +12,7 @@ internal class Class : IInterface {} [GenericParameterSubstitutesChoice(typeof(Class<,>), "T1", typeof(int))] [GenericParameterChoice(typeof(Class<,>), "T1", typeof(string))] [CreateFunction(typeof(IReadOnlyList>), "Create")] -internal partial class Container {} +internal sealed partial class Container {} public class Tests { diff --git a/Test/Generics/SubstituteCollection/Single.cs b/Test/Generics/SubstituteCollection/Single.cs index 93e77a24..6f65e0f2 100644 --- a/Test/Generics/SubstituteCollection/Single.cs +++ b/Test/Generics/SubstituteCollection/Single.cs @@ -11,7 +11,7 @@ internal class Class : IInterface {} [GenericParameterSubstitutesChoice(typeof(Class<>), "T0", typeof(int), typeof(string))] [CreateFunction(typeof(IReadOnlyList), "Create")] -internal partial class Container {} +internal sealed partial class Container {} public class Tests { diff --git a/Test/Generics/SubstituteCollection/SingleWithChoice.cs b/Test/Generics/SubstituteCollection/SingleWithChoice.cs index eeb007c2..18cb67f4 100644 --- a/Test/Generics/SubstituteCollection/SingleWithChoice.cs +++ b/Test/Generics/SubstituteCollection/SingleWithChoice.cs @@ -12,7 +12,7 @@ internal class Class : IInterface {} [GenericParameterSubstitutesChoice(typeof(Class<>), "T0", typeof(int))] [GenericParameterChoice(typeof(Class<>), "T0", typeof(string))] [CreateFunction(typeof(IReadOnlyList), "Create")] -internal partial class Container {} +internal sealed partial class Container {} public class Tests { diff --git a/Test/Generics/SubstituteCollection/TripleInsanity.cs b/Test/Generics/SubstituteCollection/TripleInsanity.cs index 6a1ca200..262f6427 100644 --- a/Test/Generics/SubstituteCollection/TripleInsanity.cs +++ b/Test/Generics/SubstituteCollection/TripleInsanity.cs @@ -13,7 +13,7 @@ internal class Class : IInterface {} [GenericParameterSubstitutesChoice(typeof(Class<,,>), "T1", typeof(int), typeof(string), typeof(uint), typeof(bool), typeof(byte))] [GenericParameterSubstitutesChoice(typeof(Class<,,>), "T2", typeof(int), typeof(string), typeof(uint), typeof(bool), typeof(byte))] [CreateFunction(typeof(IReadOnlyList), "Create")] -internal partial class Container {} +internal sealed partial class Container {} public class Tests { diff --git a/Test/Implementation/Aggregation/AssemblyImplementationsAggregation.cs b/Test/Implementation/Aggregation/AssemblyImplementationsAggregation.cs index c61a1bb8..03957879 100644 --- a/Test/Implementation/Aggregation/AssemblyImplementationsAggregation.cs +++ b/Test/Implementation/Aggregation/AssemblyImplementationsAggregation.cs @@ -9,7 +9,7 @@ namespace MrMeeseeks.DIE.Test.Implementation.Aggregation.AssemblyImplementations [AssemblyImplementationsAggregation(typeof(MrMeeseeks.DIE.TestNotInternalsVisibleToChild.AssemblyInfo))] [ConstructorChoice(typeof(Parent.ClassToo))] [CreateFunction(typeof(Parent.ClassToo), "Create")] -internal partial class Container {} +internal sealed partial class Container {} public class Tests { diff --git a/Test/Implementation/Aggregation/ExternalType.cs b/Test/Implementation/Aggregation/ExternalType.cs index 02ae1ab1..8c048036 100644 --- a/Test/Implementation/Aggregation/ExternalType.cs +++ b/Test/Implementation/Aggregation/ExternalType.cs @@ -10,7 +10,7 @@ namespace MrMeeseeks.DIE.Test.Implementation.Aggregation.ExternalType; [AssemblyImplementationsAggregation(typeof(FileInfo))] [ImplementationAggregation(typeof(FileInfo))] [CreateFunction(typeof(Func), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Implementation/Aggregation/FilterAllImplementations.cs b/Test/Implementation/Aggregation/FilterAllImplementations.cs index 2590356a..b64b3d5a 100644 --- a/Test/Implementation/Aggregation/FilterAllImplementations.cs +++ b/Test/Implementation/Aggregation/FilterAllImplementations.cs @@ -13,7 +13,7 @@ internal class DependencyB : IInterface {} [FilterAllImplementationsAggregation] [ImplementationAggregation(typeof(DependencyB))] [CreateFunction(typeof(IInterface), "Create")] -internal partial class Container {} +internal sealed partial class Container {} public class Tests { diff --git a/Test/Implementation/Aggregation/InternalsVisibleTo.cs b/Test/Implementation/Aggregation/InternalsVisibleTo.cs index 9db9c4d9..d5793377 100644 --- a/Test/Implementation/Aggregation/InternalsVisibleTo.cs +++ b/Test/Implementation/Aggregation/InternalsVisibleTo.cs @@ -7,7 +7,7 @@ namespace MrMeeseeks.DIE.Test.Implementation.Aggregation.InternalsVisibleTo; [ConstructorChoice(typeof(Parent.ClassToo))] [CreateFunction(typeof(Parent.ClassToo), "Create")] -internal partial class Container {} +internal sealed partial class Container {} public class Tests { diff --git a/Test/Implementation/Choice/Collection.cs b/Test/Implementation/Choice/Collection.cs index ed2bbb84..96b94ff4 100644 --- a/Test/Implementation/Choice/Collection.cs +++ b/Test/Implementation/Choice/Collection.cs @@ -13,7 +13,7 @@ internal class SubClassB : Class {} [ImplementationCollectionChoice(typeof(Class), typeof(SubClassA), typeof(SubClassB))] [CreateFunction(typeof(IReadOnlyList), "Create")] -internal partial class Container {} +internal sealed partial class Container {} public class Tests { diff --git a/Test/Implementation/Choice/CollectionWithoutChoice.cs b/Test/Implementation/Choice/CollectionWithoutChoice.cs index e56c05fe..a94a74a5 100644 --- a/Test/Implementation/Choice/CollectionWithoutChoice.cs +++ b/Test/Implementation/Choice/CollectionWithoutChoice.cs @@ -12,7 +12,7 @@ internal class SubClassA : Class {} internal class SubClassB : Class {} [CreateFunction(typeof(IReadOnlyList), "Create")] -internal partial class Container {} +internal sealed partial class Container {} public class Tests { diff --git a/Test/Implementation/Choice/SingleInCollection.cs b/Test/Implementation/Choice/SingleInCollection.cs index 866f2178..abcf892d 100644 --- a/Test/Implementation/Choice/SingleInCollection.cs +++ b/Test/Implementation/Choice/SingleInCollection.cs @@ -10,7 +10,7 @@ internal class SubClass : Class {} [ImplementationCollectionChoice(typeof(Class), typeof(SubClass))] [CreateFunction(typeof(Class), "Create")] -internal partial class Container {} +internal sealed partial class Container {} public class Tests { diff --git a/Test/Implementation/Choice/Vanilla.cs b/Test/Implementation/Choice/Vanilla.cs index 43978482..01a5afac 100644 --- a/Test/Implementation/Choice/Vanilla.cs +++ b/Test/Implementation/Choice/Vanilla.cs @@ -10,7 +10,7 @@ internal class SubClass : Class {} [ImplementationChoice(typeof(Class), typeof(SubClass))] [CreateFunction(typeof(Class), "Create")] -internal partial class Container {} +internal sealed partial class Container {} public class Tests { diff --git a/Test/Implementation/Choice/VanillaWithoutChoice.cs b/Test/Implementation/Choice/VanillaWithoutChoice.cs index a627271e..d9cd2e54 100644 --- a/Test/Implementation/Choice/VanillaWithoutChoice.cs +++ b/Test/Implementation/Choice/VanillaWithoutChoice.cs @@ -9,7 +9,7 @@ internal class Class {} internal class SubClass : Class {} [CreateFunction(typeof(Class), "Create")] -internal partial class Container {} +internal sealed partial class Container {} public class Tests { diff --git a/Test/Implementation/Choice/WithSingleInCollection.cs b/Test/Implementation/Choice/WithSingleInCollection.cs index 3731adde..f86262be 100644 --- a/Test/Implementation/Choice/WithSingleInCollection.cs +++ b/Test/Implementation/Choice/WithSingleInCollection.cs @@ -13,7 +13,7 @@ internal class SubClassB : Class {} [ImplementationChoice(typeof(Class), typeof(SubClassA))] [ImplementationCollectionChoice(typeof(Class), typeof(SubClassB))] [CreateFunction(typeof(Class), "Create")] -internal partial class Container {} +internal sealed partial class Container {} public class Tests { diff --git a/Test/InitProperty/Vanilla.cs b/Test/InitProperty/Vanilla.cs index f397d95c..4eaec3fe 100644 --- a/Test/InitProperty/Vanilla.cs +++ b/Test/InitProperty/Vanilla.cs @@ -12,7 +12,7 @@ internal class Wrapper } [CreateFunction(typeof(Wrapper), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Lazy/Vanilla.cs b/Test/Lazy/Vanilla.cs index 2d61a059..cd2111d5 100644 --- a/Test/Lazy/Vanilla.cs +++ b/Test/Lazy/Vanilla.cs @@ -8,7 +8,7 @@ namespace MrMeeseeks.DIE.Test.Lazy.Vanilla; internal class Dependency{} [CreateFunction(typeof(Lazy), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Nullability/NonOptional/MultipleImplementations.cs b/Test/Nullability/NonOptional/MultipleImplementations.cs index e1c54a2b..9b4a4dbc 100644 --- a/Test/Nullability/NonOptional/MultipleImplementations.cs +++ b/Test/Nullability/NonOptional/MultipleImplementations.cs @@ -18,7 +18,7 @@ internal class Wrapper } [CreateFunction(typeof(Wrapper), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Nullability/NonOptional/NoImplementation.cs b/Test/Nullability/NonOptional/NoImplementation.cs index 6779aaf2..ab5fc44b 100644 --- a/Test/Nullability/NonOptional/NoImplementation.cs +++ b/Test/Nullability/NonOptional/NoImplementation.cs @@ -14,7 +14,7 @@ internal class Wrapper } [CreateFunction(typeof(Wrapper), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Nullability/Optional/MultipleImplementations.cs b/Test/Nullability/Optional/MultipleImplementations.cs index 6ed21771..9eaaa7ef 100644 --- a/Test/Nullability/Optional/MultipleImplementations.cs +++ b/Test/Nullability/Optional/MultipleImplementations.cs @@ -18,7 +18,7 @@ internal class Wrapper } [CreateFunction(typeof(Wrapper), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Nullability/Optional/NoImplementation.cs b/Test/Nullability/Optional/NoImplementation.cs index e6f0f88e..dea2d5bd 100644 --- a/Test/Nullability/Optional/NoImplementation.cs +++ b/Test/Nullability/Optional/NoImplementation.cs @@ -14,7 +14,7 @@ internal class Wrapper } [CreateFunction(typeof(Wrapper), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Record/CustomProperty.cs b/Test/Record/CustomProperty.cs index 67f4ddfd..cfdd6708 100644 --- a/Test/Record/CustomProperty.cs +++ b/Test/Record/CustomProperty.cs @@ -14,7 +14,7 @@ internal record Implementation(Dependency Dependency) [PropertyChoice(typeof(Implementation), nameof(Implementation.DependencyA))] [CreateFunction(typeof(Implementation), "Create")] -internal partial class Container{} +internal sealed partial class Container{} public class Tests { diff --git a/Test/Record/PrimaryConstr.cs b/Test/Record/PrimaryConstr.cs index c2e6f641..4970aa23 100644 --- a/Test/Record/PrimaryConstr.cs +++ b/Test/Record/PrimaryConstr.cs @@ -9,7 +9,7 @@ internal record Dependency; internal record Implementation(Dependency Dependency); [CreateFunction(typeof(Implementation), "Create")] -internal partial class Container{} +internal sealed partial class Container{} public class Tests { diff --git a/Test/Record/Vanilla.cs b/Test/Record/Vanilla.cs index d260a3b3..119402f7 100644 --- a/Test/Record/Vanilla.cs +++ b/Test/Record/Vanilla.cs @@ -7,7 +7,7 @@ namespace MrMeeseeks.DIE.Test.Record.Vanilla; internal record Dependency; [CreateFunction(typeof(Dependency), "Create")] -internal partial class Container{} +internal sealed partial class Container{} public class Tests { diff --git a/Test/Scoping/InScope.cs b/Test/Scoping/InScope.cs index 48f78db3..f144f668 100644 --- a/Test/Scoping/InScope.cs +++ b/Test/Scoping/InScope.cs @@ -11,7 +11,7 @@ internal class ScopeRoot : IScopeRoot [CreateFunction(typeof(Func), "Create0")] [CreateFunction(typeof(Func), "Create1")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Scoping/ScopeSpecificAttributes/Decorator.cs b/Test/Scoping/ScopeSpecificAttributes/Decorator.cs index 52cbe196..948fda17 100644 --- a/Test/Scoping/ScopeSpecificAttributes/Decorator.cs +++ b/Test/Scoping/ScopeSpecificAttributes/Decorator.cs @@ -95,30 +95,30 @@ internal ScopeRoot(IInterface dep) [CreateFunction(typeof(ScopeRoot), "Create3")] [CreateFunction(typeof(ScopeRootSpecific), "Create4")] [DecoratorSequenceChoice(typeof(IInterface), typeof(ContainerDecorator))] -internal partial class Container +internal sealed partial class Container { [DecoratorSequenceChoice(typeof(IInterface), typeof(TransientScopeDecorator))] - partial class DIE_DefaultTransientScope + private sealed partial class DIE_DefaultTransientScope { } [DecoratorSequenceChoice(typeof(IInterface), typeof(TransientScopeSpecificDecorator))] [CustomScopeForRootTypes(typeof(TransientScopeRootSpecific))] - partial class DIE_TransientScope_A + private sealed partial class DIE_TransientScope_A { } [DecoratorSequenceChoice(typeof(IInterface), typeof(ScopeDecorator))] - partial class DIE_DefaultScope + private sealed partial class DIE_DefaultScope { } [DecoratorSequenceChoice(typeof(IInterface), typeof(ScopeSpecificDecorator))] [CustomScopeForRootTypes(typeof(ScopeRootSpecific))] - partial class DIE_Scope_A + private sealed partial class DIE_Scope_A { } diff --git a/Test/Scoping/ScopeSpecificAttributes/Implementation.cs b/Test/Scoping/ScopeSpecificAttributes/Implementation.cs index d830d0a0..f7c2689c 100644 --- a/Test/Scoping/ScopeSpecificAttributes/Implementation.cs +++ b/Test/Scoping/ScopeSpecificAttributes/Implementation.cs @@ -31,25 +31,24 @@ internal class Scope : IScopeRoot [CreateFunction(typeof(Scope), "Create2")] [FilterImplementationAggregation(typeof(DependencyScope))] [FilterImplementationAggregation(typeof(DependencyTransientScope))] -internal partial class Container +internal sealed partial class Container { [FilterImplementationAggregation(typeof(DependencyContainer))] [ImplementationAggregation(typeof(DependencyTransientScope))] - partial class DIE_DefaultTransientScope + private sealed partial class DIE_DefaultTransientScope { } [FilterImplementationAggregation(typeof(DependencyContainer))] [ImplementationAggregation(typeof(DependencyScope))] - partial class DIE_DefaultScope + private sealed partial class DIE_DefaultScope { } } public class Tests { - [Fact] public async ValueTask Container() { diff --git a/Test/Scoping/ScopeSpecificAttributes/ImplementationCollection.cs b/Test/Scoping/ScopeSpecificAttributes/ImplementationCollection.cs index ff32ebe1..fe3767e6 100644 --- a/Test/Scoping/ScopeSpecificAttributes/ImplementationCollection.cs +++ b/Test/Scoping/ScopeSpecificAttributes/ImplementationCollection.cs @@ -30,18 +30,18 @@ internal class Scope : IScopeRoot [CreateFunction(typeof(IReadOnlyList), "Create0")] [CreateFunction(typeof(TransientScope), "Create1")] [CreateFunction(typeof(Scope), "Create2")] -internal partial class Container +internal sealed partial class Container { [FilterImplementationAggregation(typeof(DependencyContainer))] [FilterImplementationAggregation(typeof(DependencyScope))] - partial class DIE_DefaultTransientScope + private sealed partial class DIE_DefaultTransientScope { } [FilterImplementationAggregation(typeof(DependencyContainer))] [FilterImplementationAggregation(typeof(DependencyTransientScope))] - partial class DIE_DefaultScope + private sealed partial class DIE_DefaultScope { } diff --git a/Test/Scoping/TransientScopeInstance/InContainer.cs b/Test/Scoping/TransientScopeInstance/InContainer.cs index fcc86faf..b6e2b7d2 100644 --- a/Test/Scoping/TransientScopeInstance/InContainer.cs +++ b/Test/Scoping/TransientScopeInstance/InContainer.cs @@ -9,7 +9,7 @@ internal interface IInterface {} internal class Dependency : IInterface, ITransientScopeInstance {} [CreateFunction(typeof(IInterface), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Scoping/TransientScopeInstance/InScope.cs b/Test/Scoping/TransientScopeInstance/InScope.cs index 25441fd9..7962ec93 100644 --- a/Test/Scoping/TransientScopeInstance/InScope.cs +++ b/Test/Scoping/TransientScopeInstance/InScope.cs @@ -15,7 +15,7 @@ internal class ScopeRoot : IScopeRoot } [CreateFunction(typeof(ScopeRoot), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Scoping/TransientScopeInstance/InScopeInScope.cs b/Test/Scoping/TransientScopeInstance/InScopeInScope.cs index 1bbe6053..dfb3867d 100644 --- a/Test/Scoping/TransientScopeInstance/InScopeInScope.cs +++ b/Test/Scoping/TransientScopeInstance/InScopeInScope.cs @@ -21,7 +21,7 @@ internal class ScopeWithTransientScopeInstanceAbove : IScopeRoot } [CreateFunction(typeof(ScopeWithTransientScopeInstanceAbove), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Scoping/TransientScopeInstance/InTransientScope.cs b/Test/Scoping/TransientScopeInstance/InTransientScope.cs index 12d0770b..971eb5b0 100644 --- a/Test/Scoping/TransientScopeInstance/InTransientScope.cs +++ b/Test/Scoping/TransientScopeInstance/InTransientScope.cs @@ -31,7 +31,7 @@ public TransientScope(IDisposable scopeDisposal, IInterface dependency) } [CreateFunction(typeof(TransientScope), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Scoping/TransientScopeInstance/InTransientScopeWithScopes.cs b/Test/Scoping/TransientScopeInstance/InTransientScopeWithScopes.cs index 5a4c99d7..dcefab21 100644 --- a/Test/Scoping/TransientScopeInstance/InTransientScopeWithScopes.cs +++ b/Test/Scoping/TransientScopeInstance/InTransientScopeWithScopes.cs @@ -58,7 +58,7 @@ public void CleanUp() } [CreateFunction(typeof(TransientScopeWithScopes), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/Struct/NoExplicitConstructor.cs b/Test/Struct/NoExplicitConstructor.cs index fd95904f..d817ab57 100644 --- a/Test/Struct/NoExplicitConstructor.cs +++ b/Test/Struct/NoExplicitConstructor.cs @@ -7,7 +7,7 @@ namespace MrMeeseeks.DIE.Test.Struct.NoExplicitConstructor; internal struct Dependency {} [CreateFunction(typeof(Dependency), "Create")] -internal partial class Container { } +internal sealed partial class Container { } public class Tests { diff --git a/Test/Struct/OneExplicitConstructor.cs b/Test/Struct/OneExplicitConstructor.cs index c511ef61..9923e273 100644 --- a/Test/Struct/OneExplicitConstructor.cs +++ b/Test/Struct/OneExplicitConstructor.cs @@ -14,7 +14,7 @@ internal struct Dependency } [CreateFunction(typeof(Dependency), "Create")] -internal partial class Container { } +internal sealed partial class Container { } public class Tests { diff --git a/Test/Struct/RecordNoExplicitConstructor.cs b/Test/Struct/RecordNoExplicitConstructor.cs index fb8a7d12..d91f514a 100644 --- a/Test/Struct/RecordNoExplicitConstructor.cs +++ b/Test/Struct/RecordNoExplicitConstructor.cs @@ -7,7 +7,7 @@ namespace MrMeeseeks.DIE.Test.Struct.RecordNoExplicitConstructor; internal record struct Dependency; [CreateFunction(typeof(Dependency), "Create")] -internal partial class Container { } +internal sealed partial class Container { } public class Tests { diff --git a/Test/Struct/RecordOneExplicitConstructor.cs b/Test/Struct/RecordOneExplicitConstructor.cs index 3e309924..dac94558 100644 --- a/Test/Struct/RecordOneExplicitConstructor.cs +++ b/Test/Struct/RecordOneExplicitConstructor.cs @@ -9,7 +9,7 @@ internal class Inner {} internal record struct Dependency(Inner Inner); [CreateFunction(typeof(Dependency), "Create")] -internal partial class Container { } +internal sealed partial class Container { } public class Tests { diff --git a/Test/TypeInitializer/AsyncTask.cs b/Test/TypeInitializer/AsyncTask.cs index 26898fde..5d1234e4 100644 --- a/Test/TypeInitializer/AsyncTask.cs +++ b/Test/TypeInitializer/AsyncTask.cs @@ -16,7 +16,7 @@ Task ITaskTypeInitializer.InitializeAsync() } [CreateFunction(typeof(Dependency), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/TypeInitializer/AsyncValueTask.cs b/Test/TypeInitializer/AsyncValueTask.cs index fd68ef84..5e3771ff 100644 --- a/Test/TypeInitializer/AsyncValueTask.cs +++ b/Test/TypeInitializer/AsyncValueTask.cs @@ -16,7 +16,7 @@ ValueTask IValueTaskTypeInitializer.InitializeAsync() } [CreateFunction(typeof(Dependency), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/TypeInitializer/Sync.cs b/Test/TypeInitializer/Sync.cs index 9aa6bd23..521f5e5d 100644 --- a/Test/TypeInitializer/Sync.cs +++ b/Test/TypeInitializer/Sync.cs @@ -12,7 +12,7 @@ internal class Dependency : ITypeInitializer } [CreateFunction(typeof(Dependency), "Create")] -internal partial class Container +internal sealed partial class Container { } diff --git a/Test/ValueTuple/NonSyntaxVariant.cs b/Test/ValueTuple/NonSyntaxVariant.cs index 4a03f029..b45fab79 100644 --- a/Test/ValueTuple/NonSyntaxVariant.cs +++ b/Test/ValueTuple/NonSyntaxVariant.cs @@ -23,7 +23,7 @@ public Wrapper( } [CreateFunction(typeof(Wrapper), "Create")] -internal partial class Container +internal sealed partial class Container { private int _i; diff --git a/Test/ValueTuple/NonSyntaxVariantSingleItem.cs b/Test/ValueTuple/NonSyntaxVariantSingleItem.cs index 77755e87..0b3de5ae 100644 --- a/Test/ValueTuple/NonSyntaxVariantSingleItem.cs +++ b/Test/ValueTuple/NonSyntaxVariantSingleItem.cs @@ -17,7 +17,7 @@ public ValueTuple } [CreateFunction(typeof(Wrapper), "Create")] -internal partial class Container +internal sealed partial class Container { private int _i; diff --git a/Test/ValueTuple/SyntaxVariant.cs b/Test/ValueTuple/SyntaxVariant.cs index 7cce9d35..dfac1277 100644 --- a/Test/ValueTuple/SyntaxVariant.cs +++ b/Test/ValueTuple/SyntaxVariant.cs @@ -24,7 +24,7 @@ public Wrapper( } [CreateFunction(typeof(Wrapper), "Create")] -internal partial class Container +internal sealed partial class Container { private int _i; diff --git a/Test/ValueTuple/ValueTupleTests.cs b/Test/ValueTuple/ValueTupleTests.cs index 0a91ca18..63b758ce 100644 --- a/Test/ValueTuple/ValueTupleTests.cs +++ b/Test/ValueTuple/ValueTupleTests.cs @@ -17,7 +17,7 @@ public ValueTuple } [CreateFunction(typeof(Wrapper), "Create")] -internal partial class Container +internal sealed partial class Container { private int _i; From fc3f215e1910a7c7495e76170f4790b8123629a6 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sun, 26 Jun 2022 10:30:22 +0200 Subject: [PATCH 084/162] Special validations of user-defined elements --- Main/Diagnostics.cs | 2 +- Main/DieException.cs | 4 + Main/ExecuteImpl.cs | 15 +- .../Function/FunctionResolutionBuilder.cs | 6 +- Main/SourceGenerator.cs | 4 +- Main/UserDefinedElements.cs | 184 ++++++++++++++++++ Main/UserProvidedScopeElements.cs | 121 ------------ 7 files changed, 206 insertions(+), 130 deletions(-) create mode 100644 Main/UserDefinedElements.cs delete mode 100644 Main/UserProvidedScopeElements.cs diff --git a/Main/Diagnostics.cs b/Main/Diagnostics.cs index 2396c633..1b335731 100644 --- a/Main/Diagnostics.cs +++ b/Main/Diagnostics.cs @@ -49,7 +49,7 @@ public static Diagnostic ValidationUserDefinedElement(ISymbol userDefinedElement : $"Range \"{parentRange.Name}\" in parent-Container \"{parentContainer.Name}\""; return Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_67_03", "Validation (User-Defined Element)", - $"The user-defined \"{userDefinedElement.Name}\" (of \"{rangeDescription}) isn't validly defined: {specification}", + $"The user-defined \"{userDefinedElement.Name}\" (of {rangeDescription}) isn't validly defined: {specification}", "Error", DiagnosticSeverity.Error, true), userDefinedElement.Locations.FirstOrDefault() ?? Location.None); diff --git a/Main/DieException.cs b/Main/DieException.cs index 7067ee9c..f2152574 100644 --- a/Main/DieException.cs +++ b/Main/DieException.cs @@ -24,5 +24,9 @@ public class FunctionCycleDieException : DieException public class ValidationDieException : DieException { + public IImmutableList Diagnostics { get; } + + public ValidationDieException(IImmutableList diagnostics) => Diagnostics = diagnostics; + public override DieExceptionKind Kind => DieExceptionKind.Validation; } \ No newline at end of file diff --git a/Main/ExecuteImpl.cs b/Main/ExecuteImpl.cs index 664d0673..f41ee6c9 100644 --- a/Main/ExecuteImpl.cs +++ b/Main/ExecuteImpl.cs @@ -93,12 +93,21 @@ public void Execute() } else { - foreach (var validationDiagnostic in validationDiagnostics) - _diagLogger.Log(validationDiagnostic); - throw new ValidationDieException(); + throw new ValidationDieException(validationDiagnostics); } } + catch (ValidationDieException validationDieException) + { + if (_errorDescriptionInsteadOfBuildFailure) + _containerDieExceptionGenerator.Generate( + containerSymbol.ContainingNamespace.FullName(), + containerSymbol.Name, + validationDieException); + else + foreach (var validationDiagnostic in validationDieException.Diagnostics) + _diagLogger.Log(validationDiagnostic); + } catch (DieException dieException) { if (_errorDescriptionInsteadOfBuildFailure) diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs index bb669e0a..0f03be66 100644 --- a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs @@ -115,7 +115,7 @@ internal FunctionResolutionBuilder( if (currentFuncParameters.FirstOrDefault(t => SymbolEqualityComparer.Default.Equals(t.Type.OriginalDefinition, type.OriginalDefinition)) is { Type: not null, Resolution: not null } funcParameter) return (funcParameter.Resolution, null); - if (_userDefinedElements.GetInstanceFor(type) is { } instance) + if (_userDefinedElements.GetFactoryFieldFor(type) is { } instance) return ( new FieldResolution( RootReferenceGenerator.Generate(instance.Type), @@ -123,7 +123,7 @@ internal FunctionResolutionBuilder( instance.Name), null); - if (_userDefinedElements.GetPropertyFor(type) is { } property) + if (_userDefinedElements.GetFactoryPropertyFor(type) is { } property) return ( new FieldResolution( RootReferenceGenerator.Generate(property.Type), @@ -131,7 +131,7 @@ internal FunctionResolutionBuilder( property.Name), null); - if (_userDefinedElements.GetFactoryFor(type) is { } factory) + if (_userDefinedElements.GetFactoryMethodFor(type) is { } factory) return ( new FactoryResolution( RootReferenceGenerator.Generate(factory.ReturnType), diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index 31408049..dccab8b2 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -106,7 +106,7 @@ IContainerResolutionBuilder ResolutionTreeFactory(IContainerInfo ci) RangedFunctionGroupResolutionBuilderFactory, FunctionResolutionSynchronicityDecisionMakerFactory, LocalFunctionResolutionBuilderFactory, - new UserDefinedElements(ci.ContainerType, wellKnownTypes, wellKnownTypesChoice), + new UserDefinedElements(ci.ContainerType, ci.ContainerType, wellKnownTypes, wellKnownTypesChoice), functionCycleTracker); IScopeManager ScopeManagerFactory( @@ -124,7 +124,7 @@ IScopeManager ScopeManagerFactory( wellKnownTypesChoice, wellKnownTypesMiscellaneous), tfa => new CheckTypeProperties(new CurrentlyConsideredTypes(tfa, implementationTypeSetCache), wellKnownTypes), - st => new UserDefinedElements(st, wellKnownTypes, wellKnownTypesChoice), + st => new UserDefinedElements(st, ci.ContainerType, wellKnownTypes, wellKnownTypesChoice), new EmptyUserDefinedElements(), wellKnownTypesMiscellaneous); diff --git a/Main/UserDefinedElements.cs b/Main/UserDefinedElements.cs new file mode 100644 index 00000000..d1232100 --- /dev/null +++ b/Main/UserDefinedElements.cs @@ -0,0 +1,184 @@ +namespace MrMeeseeks.DIE; + +internal interface IUserDefinedElements +{ + IFieldSymbol? GetFactoryFieldFor(ITypeSymbol type); + IPropertySymbol? GetFactoryPropertyFor(ITypeSymbol type); + IMethodSymbol? GetFactoryMethodFor(ITypeSymbol type); + IMethodSymbol? AddForDisposal { get; } + IMethodSymbol? AddForDisposalAsync { get; } + IMethodSymbol? GetCustomConstructorParameterChoiceFor(INamedTypeSymbol type); +} + +internal class EmptyUserDefinedElements : IUserDefinedElements +{ + public IFieldSymbol? GetFactoryFieldFor(ITypeSymbol type) => null; + public IPropertySymbol? GetFactoryPropertyFor(ITypeSymbol type) => null; + public IMethodSymbol? GetFactoryMethodFor(ITypeSymbol type) => null; + public IMethodSymbol? AddForDisposal => null; + public IMethodSymbol? AddForDisposalAsync => null; + public IMethodSymbol? GetCustomConstructorParameterChoiceFor(INamedTypeSymbol type) => null; +} + +internal class UserDefinedElements : IUserDefinedElements +{ + private readonly IReadOnlyDictionary _typeToField; + private readonly IReadOnlyDictionary _typeToProperty; + private readonly IReadOnlyDictionary _typeToMethod; + private readonly IReadOnlyDictionary _customConstructorParameterChoiceMethods; + + public UserDefinedElements( + // parameter + INamedTypeSymbol scopeType, + INamedTypeSymbol containerType, + + // dependencies + WellKnownTypes wellKnownTypes, + WellKnownTypesChoice wellKnownTypesChoice) + { + var validationErrors = new List(); + var dieMembers = scopeType.GetMembers() + .Where(s => s.Name.StartsWith($"{Constants.DieAbbreviation}_")) + .ToList(); + + var nonValidFactoryMembers = dieMembers + .Where(s => s.Name.StartsWith(Constants.UserDefinedFactory) + && s is IFieldSymbol or IPropertySymbol or IMethodSymbol) + .GroupBy(s => s switch + { + IFieldSymbol fs => fs.Type, + IPropertySymbol ps => ps.Type, + IMethodSymbol ms => ms.ReturnType, + _ => throw new Exception("Impossible") + }, SymbolEqualityComparer.Default) + .Where(g => g.Count() > 1) + .ToImmutableArray(); + + if (nonValidFactoryMembers.Any()) + { + foreach (var nonValidFactoryMemberGroup in nonValidFactoryMembers) + foreach (var symbol in nonValidFactoryMemberGroup) + validationErrors.Add( + Diagnostics.ValidationUserDefinedElement( + symbol, + scopeType, + containerType, + "Multiple user-defined factories aren't allowed to have the same type.")); + + _typeToField = new Dictionary(); + + _typeToProperty = new Dictionary(); + + _typeToMethod = new Dictionary(); + } + else + { + _typeToField = dieMembers + .Where(s => s.Name.StartsWith(Constants.UserDefinedFactory)) + .OfType() + .ToDictionary(fs => fs.Type, fs => fs, SymbolEqualityComparer.IncludeNullability); + + _typeToProperty = dieMembers + .Where(s => s.Name.StartsWith(Constants.UserDefinedFactory)) + .Where(s => s is IPropertySymbol { GetMethod: { } }) + .OfType() + .ToDictionary(ps => ps.Type, ps => ps, SymbolEqualityComparer.IncludeNullability); + + _typeToMethod = dieMembers + .Where(s => s.Name.StartsWith(Constants.UserDefinedFactory)) + .Where(s => s is IMethodSymbol { ReturnsVoid: false, Arity: 0, IsConditional: false, MethodKind: MethodKind.Ordinary }) + .OfType() + .ToDictionary(ps => ps.ReturnType, ps => ps, SymbolEqualityComparer.IncludeNullability); + } + + AddForDisposal = dieMembers + .Where(s => s is IMethodSymbol + { + DeclaredAccessibility: Accessibility.Private, + Arity: 0, + ReturnsVoid: true, + IsPartialDefinition: true, + Name: Constants.UserDefinedAddForDisposal, + Parameters.Length: 1 + } method && SymbolEqualityComparer.Default.Equals(method.Parameters[0].Type, wellKnownTypes.Disposable)) + .OfType() + .FirstOrDefault(); + + AddForDisposalAsync = dieMembers + .Where(s => s is IMethodSymbol + { + DeclaredAccessibility: Accessibility.Private, + Arity: 0, + ReturnsVoid: true, + IsPartialDefinition: true, + Name: Constants.UserDefinedAddForDisposalAsync, + Parameters.Length: 1 + } method && SymbolEqualityComparer.Default.Equals(method.Parameters[0].Type, wellKnownTypes.AsyncDisposable)) + .OfType() + .FirstOrDefault(); + + var constrParamCandidates = dieMembers + .Where(s => s.Name.StartsWith(Constants.UserDefinedConstructorParameters)) + .Where(s => s is IMethodSymbol { ReturnsVoid: true, Arity: 0, IsConditional: false, MethodKind: MethodKind.Ordinary } method + && method.Parameters.Any(p => p.RefKind == RefKind.Out)) + .OfType() + .Select(m => + { + var type = m.GetAttributes() + .Where(ad => SymbolEqualityComparer.Default.Equals(ad.AttributeClass, + wellKnownTypesChoice.CustomConstructorParameterChoiceAttribute)) + .Select(ad => + { + if (ad.ConstructorArguments.Length != 1) + return null; + return ad.ConstructorArguments[0].Value as INamedTypeSymbol; + }) + .OfType() + .FirstOrDefault(); + + return type is { } ? (type, m) : ((INamedTypeSymbol, IMethodSymbol)?) null; + }) + .OfType<(INamedTypeSymbol, IMethodSymbol)>() + .ToImmutableArray(); + + var constrParamGroupings = constrParamCandidates + .GroupBy(t => t.Item1, SymbolEqualityComparer.Default) + .Where(g => g.Count() > 1) + .ToImmutableArray(); + + if (constrParamGroupings.Any()) + { + foreach (var nonValidConstrParamGroup in constrParamGroupings) + foreach (var t in nonValidConstrParamGroup) + validationErrors.Add( + Diagnostics.ValidationUserDefinedElement( + t.Item2, + scopeType, + containerType, + "Multiple user-defined custom constructor parameter methods aren't allowed to have the same type that they are based on.")); + + _customConstructorParameterChoiceMethods = new Dictionary(); + } + else + _customConstructorParameterChoiceMethods = constrParamCandidates + .OfType<(INamedTypeSymbol, IMethodSymbol)>() + .ToDictionary(t => t.Item1, t => t.Item2, SymbolEqualityComparer.Default); + + if (validationErrors.Any()) + throw new ValidationDieException(validationErrors.ToImmutableArray()); + } + + public IFieldSymbol? GetFactoryFieldFor(ITypeSymbol typeSymbol) => + _typeToField.TryGetValue(typeSymbol, out var ret) ? ret : null; + + public IPropertySymbol? GetFactoryPropertyFor(ITypeSymbol typeSymbol) => + _typeToProperty.TryGetValue(typeSymbol, out var ret) ? ret : null; + + public IMethodSymbol? GetFactoryMethodFor(ITypeSymbol typeSymbol) => + _typeToMethod.TryGetValue(typeSymbol, out var ret) ? ret : null; + + public IMethodSymbol? AddForDisposal { get; } + public IMethodSymbol? AddForDisposalAsync { get; } + public IMethodSymbol? GetCustomConstructorParameterChoiceFor(INamedTypeSymbol type) => + _customConstructorParameterChoiceMethods.TryGetValue(type, out var ret) ? ret : null; +} \ No newline at end of file diff --git a/Main/UserProvidedScopeElements.cs b/Main/UserProvidedScopeElements.cs deleted file mode 100644 index 8f90ebee..00000000 --- a/Main/UserProvidedScopeElements.cs +++ /dev/null @@ -1,121 +0,0 @@ -namespace MrMeeseeks.DIE; - -internal interface IUserDefinedElements -{ - IFieldSymbol? GetInstanceFor(ITypeSymbol type); - IPropertySymbol? GetPropertyFor(ITypeSymbol type); - IMethodSymbol? GetFactoryFor(ITypeSymbol type); - IMethodSymbol? AddForDisposal { get; } - IMethodSymbol? AddForDisposalAsync { get; } - IMethodSymbol? GetCustomConstructorParameterChoiceFor(INamedTypeSymbol type); -} - -internal class EmptyUserDefinedElements : IUserDefinedElements -{ - public IFieldSymbol? GetInstanceFor(ITypeSymbol type) => null; - public IPropertySymbol? GetPropertyFor(ITypeSymbol type) => null; - public IMethodSymbol? GetFactoryFor(ITypeSymbol type) => null; - public IMethodSymbol? AddForDisposal => null; - public IMethodSymbol? AddForDisposalAsync => null; - public IMethodSymbol? GetCustomConstructorParameterChoiceFor(INamedTypeSymbol type) => null; -} - -internal class UserDefinedElements : IUserDefinedElements -{ - private readonly IReadOnlyDictionary _typeToField; - private readonly IReadOnlyDictionary _typeToProperty; - private readonly IReadOnlyDictionary _typeToMethod; - private readonly IReadOnlyDictionary _customConstructorParameterChoiceMethods; - - public UserDefinedElements( - // parameter - INamedTypeSymbol scopeType, - - // dependencies - WellKnownTypes wellKnownTypes, - WellKnownTypesChoice wellKnownTypesChoice) - { - var dieMembers = scopeType.GetMembers() - .Where(s => s.Name.StartsWith($"{Constants.DieAbbreviation}_")) - .ToList(); - - _typeToField = dieMembers - .Where(s => s.Name.StartsWith(Constants.UserDefinedFactory)) - .OfType() - .ToDictionary(fs => fs.Type, fs => fs, SymbolEqualityComparer.IncludeNullability); - - _typeToProperty = dieMembers - .Where(s => s.Name.StartsWith(Constants.UserDefinedFactory)) - .Where(s => s is IPropertySymbol { GetMethod: { } }) - .OfType() - .ToDictionary(ps => ps.Type, ps => ps, SymbolEqualityComparer.IncludeNullability); - - _typeToMethod = dieMembers - .Where(s => s.Name.StartsWith(Constants.UserDefinedFactory)) - .Where(s => s is IMethodSymbol { ReturnsVoid: false, Arity: 0, IsConditional: false, MethodKind: MethodKind.Ordinary }) - .OfType() - .ToDictionary(ps => ps.ReturnType, ps => ps, SymbolEqualityComparer.IncludeNullability); - - AddForDisposal = dieMembers - .Where(s => s is IMethodSymbol - { - DeclaredAccessibility: Accessibility.Private, - ReturnsVoid: true, - IsPartialDefinition: true, - Name: Constants.UserDefinedAddForDisposal, - Parameters.Length: 1 - } method && SymbolEqualityComparer.Default.Equals(method.Parameters[0].Type, wellKnownTypes.Disposable)) - .OfType() - .FirstOrDefault(); - - AddForDisposalAsync = dieMembers - .Where(s => s is IMethodSymbol - { - DeclaredAccessibility: Accessibility.Private, - ReturnsVoid: true, - IsPartialDefinition: true, - Name: Constants.UserDefinedAddForDisposalAsync, - Parameters.Length: 1 - } method && SymbolEqualityComparer.Default.Equals(method.Parameters[0].Type, wellKnownTypes.AsyncDisposable)) - .OfType() - .FirstOrDefault(); - - _customConstructorParameterChoiceMethods = dieMembers - .Where(s => s.Name.StartsWith(Constants.UserDefinedConstructorParameters)) - .Where(s => s is IMethodSymbol { ReturnsVoid: true, Arity: 0, IsConditional: false, MethodKind: MethodKind.Ordinary } method - && method.Parameters.Any(p => p.RefKind == RefKind.Out)) - .OfType() - .Select(m => - { - var type = m.GetAttributes() - .Where(ad => SymbolEqualityComparer.Default.Equals(ad.AttributeClass, - wellKnownTypesChoice.CustomConstructorParameterChoiceAttribute)) - .Select(ad => - { - if (ad.ConstructorArguments.Length != 1) - return null; - return ad.ConstructorArguments[0].Value is INamedTypeSymbol type ? type : null; - }) - .OfType() - .FirstOrDefault(); - - return type is { } ? (type, m) : ((INamedTypeSymbol, IMethodSymbol)?) null; - }) - .OfType<(INamedTypeSymbol, IMethodSymbol)>() - .ToDictionary(t => t.Item1, t => t.Item2, SymbolEqualityComparer.Default); - } - - public IFieldSymbol? GetInstanceFor(ITypeSymbol typeSymbol) => - _typeToField.TryGetValue(typeSymbol, out var ret) ? ret : null; - - public IPropertySymbol? GetPropertyFor(ITypeSymbol typeSymbol) => - _typeToProperty.TryGetValue(typeSymbol, out var ret) ? ret : null; - - public IMethodSymbol? GetFactoryFor(ITypeSymbol typeSymbol) => - _typeToMethod.TryGetValue(typeSymbol, out var ret) ? ret : null; - - public IMethodSymbol? AddForDisposal { get; } - public IMethodSymbol? AddForDisposalAsync { get; } - public IMethodSymbol? GetCustomConstructorParameterChoiceFor(INamedTypeSymbol type) => - _customConstructorParameterChoiceMethods.TryGetValue(type, out var ret) ? ret : null; -} \ No newline at end of file From 5499aeac021b9f6b517c27e5dbac1aa68d555411 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sun, 26 Jun 2022 15:27:33 +0200 Subject: [PATCH 085/162] Hacky exception handling --- Main/CodeBuilding/RangeCodeBaseBuilder.cs | 4 ++ Main/DiagLogger.cs | 24 ++++++++++-- Main/Diagnostics.cs | 37 ++++++++++++++++--- Main/DieException.cs | 14 ++++++- .../Function/FunctionResolutionBuilder.cs | 14 ++++++- Sample/Container.cs | 2 +- Sample/Context.cs | 33 +++++------------ 7 files changed, 92 insertions(+), 36 deletions(-) diff --git a/Main/CodeBuilding/RangeCodeBaseBuilder.cs b/Main/CodeBuilding/RangeCodeBaseBuilder.cs index 035d8ed3..785d8f6b 100644 --- a/Main/CodeBuilding/RangeCodeBaseBuilder.cs +++ b/Main/CodeBuilding/RangeCodeBaseBuilder.cs @@ -343,6 +343,8 @@ private static StringBuilder GenerateFields( stringBuilder = items.OfType().Aggregate(stringBuilder, GenerateFields); stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); break; + case ErrorTreeItem(var message): + throw new SlippedResolutionDieException(message); case var (reference, typeFullName): stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); break; @@ -586,6 +588,8 @@ private StringBuilder GenerateResolutions( stringBuilder = stringBuilder.AppendLine( $"{reference} = new {itemFullName}[]{{{string.Join(", ", items.Select(d => $"({itemFullName}) {(d as Resolvable)?.Reference}"))}}};"); break; + case ErrorTreeItem(var message): + throw new SlippedResolutionDieException(message); default: throw new Exception("Unexpected case or not implemented."); } diff --git a/Main/DiagLogger.cs b/Main/DiagLogger.cs index 15321ff0..ffa63ec5 100644 --- a/Main/DiagLogger.cs +++ b/Main/DiagLogger.cs @@ -31,10 +31,26 @@ public void Log(int id, string title, string message, string category, Diagnosti public void Log(string message) => Log(0, "INFO", message, "INFO", DiagnosticSeverity.Warning); - public void Error(DieException exception) => - _context.ReportDiagnostic(Diagnostic.Create( - new DiagnosticDescriptor($"DIE{69.ToString().PadLeft(3, '0')}", "Error", "Circular implementation references", "Error", DiagnosticSeverity.Error, true), - Location.None)); + public void Error(DieException exception) + { + switch (exception) + { + case ImplementationCycleDieException implementationCycle: + _context.ReportDiagnostic(Diagnostics.CircularReferenceInsideFactory(implementationCycle)); + break; + case FunctionCycleDieException: + _context.ReportDiagnostic(Diagnostics.CircularReferenceAmongFactories); + break; + case ValidationDieException: + break; + case SlippedResolutionDieException slippedResolution: + _context.ReportDiagnostic(Diagnostics.SlippedResolutionError(slippedResolution)); + break; + default: + _context.ReportDiagnostic(Diagnostics.UnexpectedException(exception)); + break; + } + } public void Log(Diagnostic diagnostic) { diff --git a/Main/Diagnostics.cs b/Main/Diagnostics.cs index 1b335731..2960fa58 100644 --- a/Main/Diagnostics.cs +++ b/Main/Diagnostics.cs @@ -2,13 +2,18 @@ namespace MrMeeseeks.DIE; public static class Diagnostics { - public static Diagnostic CircularReferenceInsideFactory => - Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_68_00", - "Circular Reference Exception (inside factory)", - "This container and/or its configuration lead to a circular reference inside one of its factory functions, which need to be generated.", - "Error", DiagnosticSeverity.Error, - true), + public static Diagnostic CircularReferenceInsideFactory(ImplementationCycleDieException exception) + { + var cycleText = string.Join(" --> ", exception.Cycle.Select(nts => nts.FullName())); + + return Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_68_00", + "Circular Reference Exception (inside factory)", + $"This container and/or its configuration lead to a circular reference inside one of its factory functions, which need to be generated. The implementations involved in the cycle are: {cycleText}", + "Error", DiagnosticSeverity.Error, + true), Location.None); + } + public static Diagnostic CircularReferenceAmongFactories => Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_68_01", @@ -54,4 +59,24 @@ public static Diagnostic ValidationUserDefinedElement(ISymbol userDefinedElement true), userDefinedElement.Locations.FirstOrDefault() ?? Location.None); } + + public static Diagnostic UnexpectedException(DieException exception) + { + return Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_66_00", + "Unexpected Exception", + exception.ToString(), + "Error", DiagnosticSeverity.Error, + true), + Location.None); + } + + public static Diagnostic SlippedResolutionError(SlippedResolutionDieException exception) + { + return Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_66_00", + "Unexpected Exception", + exception.ErrorMessage, + "Error", DiagnosticSeverity.Error, + true), + Location.None); + } } \ No newline at end of file diff --git a/Main/DieException.cs b/Main/DieException.cs index f2152574..ac4b93dc 100644 --- a/Main/DieException.cs +++ b/Main/DieException.cs @@ -4,7 +4,8 @@ public enum DieExceptionKind { ImplementationCycle, FunctionCycle, - Validation + Validation, + SlippedResolutionError } public abstract class DieException : Exception @@ -14,7 +15,10 @@ public abstract class DieException : Exception public class ImplementationCycleDieException : DieException { + public ImplementationCycleDieException(IImmutableStack cycle) => Cycle = cycle; + public override DieExceptionKind Kind => DieExceptionKind.ImplementationCycle; + public IImmutableStack Cycle { get; } } public class FunctionCycleDieException : DieException @@ -29,4 +33,12 @@ public class ValidationDieException : DieException public ValidationDieException(IImmutableList diagnostics) => Diagnostics = diagnostics; public override DieExceptionKind Kind => DieExceptionKind.Validation; +} + +public class SlippedResolutionDieException : DieException +{ + public string ErrorMessage { get; } + + public SlippedResolutionDieException(string errorMessage) => ErrorMessage = errorMessage; + public override DieExceptionKind Kind => DieExceptionKind.SlippedResolutionError; } \ No newline at end of file diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs index 0f03be66..df10a254 100644 --- a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs @@ -668,7 +668,19 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup var implementationCycle = implementationStack.Contains(implementationType, SymbolEqualityComparer.Default); if (implementationCycle) - throw new ImplementationCycleDieException(); + { + var cycleStack = ImmutableStack.Create(implementationType); + var stack = implementationStack; + var i = implementationType; + do + { + stack = stack.Pop(out var popped); + cycleStack = cycleStack.Push(popped); + i = popped; + } while (!SymbolEqualityComparer.Default.Equals(implementationType, i)); + + throw new ImplementationCycleDieException(cycleStack); + } implementationStack = implementationStack.Push(implementationType); diff --git a/Sample/Container.cs b/Sample/Container.cs index e5b0f411..7eca09ce 100644 --- a/Sample/Container.cs +++ b/Sample/Container.cs @@ -17,4 +17,4 @@ [assembly:AllImplementationsAggregation] -[assembly:ErrorDescriptionInsteadOfBuildFailure] \ No newline at end of file +//[assembly:ErrorDescriptionInsteadOfBuildFailure] \ No newline at end of file diff --git a/Sample/Context.cs b/Sample/Context.cs index a8e6782a..3ca84c8e 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -1,37 +1,24 @@ -using System; -using MrMeeseeks.DIE.Configuration.Attributes; -using MrMeeseeks.DIE.Sample; +using MrMeeseeks.DIE.Configuration.Attributes; -namespace MrMeeseeks.DIE.Test.CustomEmbedding.ConstructorParameterWithDependencyInScope; +namespace MrMeeseeks.DIE.Test.CycleDetection.Implementation.Cycle.Proxied; -internal class Dependency -{ - public int Number { get; } - internal Dependency(int number) => Number = number; +internal class Proxy1 +{ + internal Proxy1(Dependency inner) {} } - -internal class OtherDependency +internal class Proxy0 { - public int Number => 69; + internal Proxy0(Proxy1 inner) {} } -internal class ScopeRoot : IScopeRoot +internal class Dependency { - public Dependency Dependency { get; } - - internal ScopeRoot( - Dependency dependency) => Dependency = dependency; + internal Dependency(Proxy0 inner) {} } -[CreateFunction(typeof(ScopeRoot), "Create")] +[CreateFunction(typeof(Dependency), "Create")] internal sealed partial class Container { - private partial void DIE_AddForDisposal(IDisposable disposable); - sealed partial class DIE_DefaultScope - { - [CustomConstructorParameterChoice(typeof(Dependency))] - private void DIE_ConstrParam_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; - } } \ No newline at end of file From 7ba2524f3789032dce3c8574c262eee431364e02 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sun, 26 Jun 2022 15:35:13 +0200 Subject: [PATCH 086/162] Minor fix :D --- Sample/Container.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sample/Container.cs b/Sample/Container.cs index 7eca09ce..e5b0f411 100644 --- a/Sample/Container.cs +++ b/Sample/Container.cs @@ -17,4 +17,4 @@ [assembly:AllImplementationsAggregation] -//[assembly:ErrorDescriptionInsteadOfBuildFailure] \ No newline at end of file +[assembly:ErrorDescriptionInsteadOfBuildFailure] \ No newline at end of file From 56233efbc832011b01f48da917650c55ecc460d7 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sun, 26 Jun 2022 18:40:22 +0200 Subject: [PATCH 087/162] Improved error messages --- Main/CodeBuilding/RangeCodeBaseBuilder.cs | 8 +-- Main/ContainerErrorGenerator.cs | 43 ------------ Main/DiagLogger.cs | 4 +- Main/Diagnostics.cs | 8 +-- Main/DieException.cs | 10 +-- Main/ExecuteImpl.cs | 12 +--- .../ContainerResolutionBuilder.cs | 6 ++ Main/ResolutionBuilding/ErrorContext.cs | 19 +++++ .../Function/FunctionResolutionBuilder.cs | 68 +++++++++--------- .../RangeResolutionBaseBuilder.cs | 5 +- Main/ResolutionBuilding/ScopeManager.cs | 26 ++++--- .../ScopeResolutionBuilder.cs | 4 ++ .../TransientScopeResolutionBuilder.cs | 4 ++ Main/ResolutionTreeCreationErrorHarvester.cs | 69 ------------------- Main/ResolutionTreeItem.cs | 2 +- Main/SourceGenerator.cs | 12 ++-- 16 files changed, 115 insertions(+), 185 deletions(-) delete mode 100644 Main/ContainerErrorGenerator.cs create mode 100644 Main/ResolutionBuilding/ErrorContext.cs delete mode 100644 Main/ResolutionTreeCreationErrorHarvester.cs diff --git a/Main/CodeBuilding/RangeCodeBaseBuilder.cs b/Main/CodeBuilding/RangeCodeBaseBuilder.cs index 785d8f6b..3820e072 100644 --- a/Main/CodeBuilding/RangeCodeBaseBuilder.cs +++ b/Main/CodeBuilding/RangeCodeBaseBuilder.cs @@ -343,8 +343,8 @@ private static StringBuilder GenerateFields( stringBuilder = items.OfType().Aggregate(stringBuilder, GenerateFields); stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); break; - case ErrorTreeItem(var message): - throw new SlippedResolutionDieException(message); + case ErrorTreeItem(var diagnostic): + throw new CompilationDieException(diagnostic); case var (reference, typeFullName): stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); break; @@ -588,8 +588,8 @@ private StringBuilder GenerateResolutions( stringBuilder = stringBuilder.AppendLine( $"{reference} = new {itemFullName}[]{{{string.Join(", ", items.Select(d => $"({itemFullName}) {(d as Resolvable)?.Reference}"))}}};"); break; - case ErrorTreeItem(var message): - throw new SlippedResolutionDieException(message); + case ErrorTreeItem(var diagnostic): + throw new CompilationDieException(diagnostic); default: throw new Exception("Unexpected case or not implemented."); } diff --git a/Main/ContainerErrorGenerator.cs b/Main/ContainerErrorGenerator.cs deleted file mode 100644 index dadb647a..00000000 --- a/Main/ContainerErrorGenerator.cs +++ /dev/null @@ -1,43 +0,0 @@ -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.Text; - -namespace MrMeeseeks.DIE; - -internal interface IContainerErrorGenerator -{ - void Generate(IContainerInfo containerInfo, IReadOnlyList errorTreeItems); -} - -internal class ContainerErrorGenerator : IContainerErrorGenerator -{ - private readonly GeneratorExecutionContext _context; - - internal ContainerErrorGenerator( - GeneratorExecutionContext context) => - _context = context; - - public void Generate(IContainerInfo containerInfo, IReadOnlyList errorTreeItems) - { - var generatedContainer = new StringBuilder() - .AppendLine($"#nullable enable") - .AppendLine($"namespace {containerInfo.Namespace}") - .AppendLine($"{{") - .AppendLine($"partial class {containerInfo.Name}") - .AppendLine($"{{") - .AppendLine($"public object Resolve()") - .AppendLine($"{{") - .AppendLine($"throw new Exception(@\"{string.Join(Environment.NewLine, errorTreeItems.Select(eri => eri.Message))}\");") - .AppendLine($"}}") - .AppendLine($"}}") - .AppendLine($"}}") - .AppendLine($"#nullable disable"); - - var containerSource = CSharpSyntaxTree - .ParseText(SourceText.From(generatedContainer.ToString(), Encoding.UTF8)) - .GetRoot() - .NormalizeWhitespace() - .SyntaxTree - .GetText(); - _context.AddSource($"{containerInfo.Namespace}.{containerInfo.Name}.g.cs", containerSource); - } -} \ No newline at end of file diff --git a/Main/DiagLogger.cs b/Main/DiagLogger.cs index ffa63ec5..da73d8d3 100644 --- a/Main/DiagLogger.cs +++ b/Main/DiagLogger.cs @@ -43,8 +43,8 @@ public void Error(DieException exception) break; case ValidationDieException: break; - case SlippedResolutionDieException slippedResolution: - _context.ReportDiagnostic(Diagnostics.SlippedResolutionError(slippedResolution)); + case CompilationDieException slippedResolution: + _context.ReportDiagnostic(slippedResolution.Diagnostic); break; default: _context.ReportDiagnostic(Diagnostics.UnexpectedException(exception)); diff --git a/Main/Diagnostics.cs b/Main/Diagnostics.cs index 2960fa58..7bef8b40 100644 --- a/Main/Diagnostics.cs +++ b/Main/Diagnostics.cs @@ -70,11 +70,11 @@ public static Diagnostic UnexpectedException(DieException exception) Location.None); } - public static Diagnostic SlippedResolutionError(SlippedResolutionDieException exception) + public static Diagnostic CompilationError(string message, Location location) { - return Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_66_00", - "Unexpected Exception", - exception.ErrorMessage, + return Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_65_00", + "Error During Compilation", + message, "Error", DiagnosticSeverity.Error, true), Location.None); diff --git a/Main/DieException.cs b/Main/DieException.cs index ac4b93dc..3d1e9804 100644 --- a/Main/DieException.cs +++ b/Main/DieException.cs @@ -5,7 +5,7 @@ public enum DieExceptionKind ImplementationCycle, FunctionCycle, Validation, - SlippedResolutionError + Compilation } public abstract class DieException : Exception @@ -35,10 +35,10 @@ public class ValidationDieException : DieException public override DieExceptionKind Kind => DieExceptionKind.Validation; } -public class SlippedResolutionDieException : DieException +public class CompilationDieException : DieException { - public string ErrorMessage { get; } + public Diagnostic Diagnostic { get; } - public SlippedResolutionDieException(string errorMessage) => ErrorMessage = errorMessage; - public override DieExceptionKind Kind => DieExceptionKind.SlippedResolutionError; + public CompilationDieException(Diagnostic diagnostic) => Diagnostic = diagnostic; + public override DieExceptionKind Kind => DieExceptionKind.Compilation; } \ No newline at end of file diff --git a/Main/ExecuteImpl.cs b/Main/ExecuteImpl.cs index f41ee6c9..6b521ae4 100644 --- a/Main/ExecuteImpl.cs +++ b/Main/ExecuteImpl.cs @@ -16,11 +16,9 @@ internal class ExecuteImpl : IExecute private readonly GeneratorExecutionContext _context; private readonly WellKnownTypesMiscellaneous _wellKnownTypesMiscellaneous; private readonly IContainerGenerator _containerGenerator; - private readonly IContainerErrorGenerator _containerErrorGenerator; private readonly IContainerDieExceptionGenerator _containerDieExceptionGenerator; private readonly IValidateContainer _validateContainer; private readonly Func _containerResolutionBuilderFactory; - private readonly IResolutionTreeCreationErrorHarvester _resolutionTreeCreationErrorHarvester; private readonly Func _containerInfoFactory; private readonly IDiagLogger _diagLogger; @@ -29,11 +27,9 @@ internal ExecuteImpl( GeneratorExecutionContext context, WellKnownTypesMiscellaneous wellKnownTypesMiscellaneous, IContainerGenerator containerGenerator, - IContainerErrorGenerator containerErrorGenerator, IContainerDieExceptionGenerator containerDieExceptionGenerator, IValidateContainer validateContainer, Func containerResolutionBuilderFactory, - IResolutionTreeCreationErrorHarvester resolutionTreeCreationErrorHarvester, Func containerInfoFactory, IDiagLogger diagLogger) { @@ -41,11 +37,9 @@ internal ExecuteImpl( _context = context; _wellKnownTypesMiscellaneous = wellKnownTypesMiscellaneous; _containerGenerator = containerGenerator; - _containerErrorGenerator = containerErrorGenerator; _containerDieExceptionGenerator = containerDieExceptionGenerator; _validateContainer = validateContainer; _containerResolutionBuilderFactory = containerResolutionBuilderFactory; - _resolutionTreeCreationErrorHarvester = resolutionTreeCreationErrorHarvester; _containerInfoFactory = containerInfoFactory; _diagLogger = diagLogger; } @@ -85,11 +79,7 @@ public void Execute() containerResolutionBuilder.FunctionCycleTracker.DetectCycle(); var containerResolution = containerResolutionBuilder.Build(); - var errorTreeItems = _resolutionTreeCreationErrorHarvester.Harvest(containerResolution); - if (errorTreeItems.Any()) - _containerErrorGenerator.Generate(containerInfo, errorTreeItems); - else - _containerGenerator.Generate(containerInfo, containerResolution); + _containerGenerator.Generate(containerInfo, containerResolution); } else { diff --git a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs index a688c113..4956cfa2 100644 --- a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs @@ -62,6 +62,10 @@ internal ContainerResolutionBuilder( transientScopeInterfaceResolutionBuilder.AddImplementation(this); _transientScopeAdapterReference = RootReferenceGenerator.Generate("TransientScopeAdapter"); + + ErrorContext = new ErrorContext( + containerInfo.Name, + containerInfo.ContainerType.Locations.FirstOrDefault() ?? Location.None); } public void AddCreateResolveFunctions(IReadOnlyList<(INamedTypeSymbol, string)> createFunctionData) @@ -80,6 +84,8 @@ public MultiSynchronicityFunctionCallResolution CreateContainerInstanceReference public IFunctionCycleTracker FunctionCycleTracker { get; } + public override IErrorContext ErrorContext { get; } + public override MultiSynchronicityFunctionCallResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter) => CreateContainerInstanceReferenceResolution(parameter, Constants.ThisKeyword); diff --git a/Main/ResolutionBuilding/ErrorContext.cs b/Main/ResolutionBuilding/ErrorContext.cs new file mode 100644 index 00000000..7d540b08 --- /dev/null +++ b/Main/ResolutionBuilding/ErrorContext.cs @@ -0,0 +1,19 @@ +namespace MrMeeseeks.DIE.ResolutionBuilding; + +internal interface IErrorContext +{ + string Prefix { get; } + Location Location { get; } +} + +internal class ErrorContext : IErrorContext +{ + public ErrorContext(string prefix, Location location) + { + Prefix = prefix; + Location = location; + } + + public string Prefix { get; } + public Location Location { get; } +} \ No newline at end of file diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs index df10a254..0a679a40 100644 --- a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs @@ -83,8 +83,7 @@ internal FunctionResolutionBuilder( IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters, IFunctionResolutionSynchronicityDecisionMaker synchronicityDecisionMaker, object handleIdentity, - - + // dependencies WellKnownTypes wellKnownTypes, IReferenceGeneratorFactory referenceGeneratorFactory, @@ -109,6 +108,9 @@ internal FunctionResolutionBuilder( Resolvable = new(CreateResolvable); } + private string ErrorMessage(IImmutableStack stack, ITypeSymbol currentType, string message) => + $"[R:{_rangeResolutionBaseBuilder.ErrorContext.Prefix}][TS:{(stack.IsEmpty ? "empty" : stack.Peek().FullName())}][CT:{currentType.FullName()}] {message}"; + protected (Resolvable, ITaskConsumableResolution?) SwitchType(SwitchTypeParameter parameter) { var (type, currentFuncParameters, implementationStack) = parameter; @@ -206,13 +208,12 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup { if (namedTypeSymbol.TypeArguments.SingleOrDefault() is not INamedTypeSymbol genericType) { - return ( - new ErrorTreeItem(namedTypeSymbol.TypeArguments.Length switch + return (new ErrorTreeItem(Diagnostics.CompilationError(namedTypeSymbol.TypeArguments.Length switch { - 0 => $"[{namedTypeSymbol.FullName()}] Lazy: No type argument", - > 1 => $"[{namedTypeSymbol.FullName()}] Lazy: more than one type argument", - _ => $"[{namedTypeSymbol.FullName()}] Lazy: {namedTypeSymbol.TypeArguments[0].FullName()} is not a named type symbol" - }), + 0 => ErrorMessage(implementationStack, namedTypeSymbol, "Lazy: No type argument"), + > 1 => ErrorMessage(implementationStack, namedTypeSymbol, "Lazy: more than one type argument"), + _ => ErrorMessage(implementationStack, namedTypeSymbol, "Lazy: {namedTypeSymbol.TypeArguments[0].FullName()} is not a named type symbol"), + }, _rangeResolutionBaseBuilder.ErrorContext.Location)), null); } @@ -236,7 +237,8 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup if (returnTypeRaw is not INamedTypeSymbol returnType) { return ( - new ErrorTreeItem($"[{type.FullName()}] Func: Return type not named"), + new ErrorTreeItem(Diagnostics.CompilationError( + ErrorMessage(implementationStack, type, "Func: Return type not named"), _rangeResolutionBaseBuilder.ErrorContext.Location)), null); } @@ -265,18 +267,18 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup if (type is not INamedTypeSymbol collectionType) { return ( - new ErrorTreeItem($"[{type.FullName()}] Collection: Collection is not a named type symbol"), + new ErrorTreeItem(Diagnostics.CompilationError( + ErrorMessage(implementationStack, type, "Collection: Collection is not a named type symbol"), _rangeResolutionBaseBuilder.ErrorContext.Location)), null); } if (collectionType.TypeArguments.SingleOrDefault() is not INamedTypeSymbol wrappedType) { - return ( - new ErrorTreeItem(collectionType.TypeArguments.Length switch + return (new ErrorTreeItem(Diagnostics.CompilationError(collectionType.TypeArguments.Length switch { - 0 => $"[{type.FullName()}] Collection: No item type argument", - > 1 => $"[{type.FullName()}] Collection: More than one item type argument", - _ => $"[{type.FullName()}] Collection: {collectionType.TypeArguments[0].FullName()} is not a named type symbol" - }), + 0 => ErrorMessage(implementationStack, type, "Collection: No item type argument"), + >1 => ErrorMessage(implementationStack, type, "Collection: More than one item type argument"), + _ => ErrorMessage(implementationStack, type, $"Collection: {collectionType.TypeArguments[0].FullName()} is not a named type symbol") + }, _rangeResolutionBaseBuilder.ErrorContext.Location)), null); } ITypeSymbol wrappedItemTypeSymbol = wrappedType; @@ -300,7 +302,8 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup if (wrappedItemTypeSymbol is not INamedTypeSymbol wrappedItemType) { return ( - new ErrorTreeItem($"[{type.FullName()}] Collection: Collection's inner type is not a named type symbol"), + new ErrorTreeItem(Diagnostics.CompilationError( + ErrorMessage(implementationStack, type, "Collection: Collection's inner type is not a named type symbol"), _rangeResolutionBaseBuilder.ErrorContext.Location)), null); } @@ -310,7 +313,8 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup if (unwrappedItemTypeSymbol is not INamedTypeSymbol unwrappedItemType) { return ( - new ErrorTreeItem($"[{type.FullName()}] Collection: Collection's inner type is not a named type symbol"), + new ErrorTreeItem(Diagnostics.CompilationError( + ErrorMessage(implementationStack, type, "Collection: Collection's inner type is not a named type symbol"), _rangeResolutionBaseBuilder.ErrorContext.Location)), null); } @@ -349,7 +353,8 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup return SwitchClass(new SwitchClassParameter(classOrStructType, currentFuncParameters, implementationStack)); return ( - new ErrorTreeItem($"[{type.FullName()}] Couldn't process in resolution tree creation."), + new ErrorTreeItem(Diagnostics.CompilationError( + ErrorMessage(implementationStack, type, "Couldn't process in resolution tree creation."), _rangeResolutionBaseBuilder.ErrorContext.Location)), null); } @@ -485,7 +490,9 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup { return interfaceType.NullableAnnotation == NullableAnnotation.Annotated ? (new NullResolution(RootReferenceGenerator.Generate(interfaceType), interfaceType.FullName()), null) // todo warning - : (new ErrorTreeItem($"[{interfaceType.FullName()}] Interface: Multiple or no implementations where a single is required"), null); + : (new ErrorTreeItem(Diagnostics.CompilationError( + ErrorMessage(implementationStack, interfaceType, "Interface: Multiple or no implementations where a single is required"), _rangeResolutionBaseBuilder.ErrorContext.Location)), + null); } return SwitchInterfaceWithoutComposition(new CreateInterfaceParameter( @@ -552,7 +559,9 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup { return implementationType.NullableAnnotation == NullableAnnotation.Annotated ? (new NullResolution(RootReferenceGenerator.Generate(implementationType), implementationType.FullName()), null) // todo warning - : (new ErrorTreeItem($"[{implementationType.FullName()}] Interface: Multiple or no implementations where a single is required"), null); + : (new ErrorTreeItem(Diagnostics.CompilationError( + ErrorMessage(implementationStack, implementationType, "Interface: Multiple or no implementations where a single is required"), _rangeResolutionBaseBuilder.ErrorContext.Location)), + null); } var nextParameter = new SwitchImplementationParameter( @@ -653,15 +662,12 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup return implementationType.NullableAnnotation == NullableAnnotation.Annotated ? (new NullResolution(RootReferenceGenerator.Generate(implementationType), implementationType.FullName()), null) // todo warning - : (new ErrorTreeItem(implementationType.InstanceConstructors.Length switch + : (new ErrorTreeItem(Diagnostics.CompilationError(implementationType.InstanceConstructors.Length switch { - 0 => - $"[{implementationType.FullName()}] Class.Constructor: No constructor found for implementation {implementationType.FullName()}", - > 1 => - $"[{implementationType.FullName()}] Class.Constructor: More than one constructor found for implementation {implementationType.FullName()}", - _ => - $"[{implementationType.FullName()}] Class.Constructor: {implementationType.InstanceConstructors[0].Name} is not a method symbol" - }), + 0 => ErrorMessage(implementationStack, implementationType, $"Class.Constructor: No constructor found for implementation {implementationType.FullName()}"), + > 1 => ErrorMessage(implementationStack, implementationType, $"Class.Constructor: More than one constructor found for implementation {implementationType.FullName()}"), + _ => ErrorMessage(implementationStack, implementationType, $"Class.Constructor: {implementationType.InstanceConstructors[0].Name} is not a method symbol") + }, _rangeResolutionBaseBuilder.ErrorContext.Location)), null); } @@ -875,8 +881,8 @@ false when initializationMethod.ReturnType.Equals(_wellKnownTypes.ValueTask, Sym if (typeSymbol is not INamedTypeSymbol parameterType) return ("", - new ErrorTreeItem( - $"[{impType.FullName()}] Class.Constructor.Parameter: Parameter type {typeSymbol.FullName()} is not a named type symbol")); + new ErrorTreeItem(Diagnostics.CompilationError( + ErrorMessage(implementationStack, typeSymbol, $"Class.Constructor.Parameter: Parameter type {typeSymbol.FullName()} is not a named type symbol"), _rangeResolutionBaseBuilder.ErrorContext.Location))); return ( parameterName, diff --git a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs index 031a2222..c55c7824 100644 --- a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs +++ b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs @@ -8,6 +8,8 @@ internal interface IRangeResolutionBaseBuilder ICheckTypeProperties CheckTypeProperties { get; } IUserDefinedElements UserDefinedElements { get; } + IErrorContext ErrorContext { get; } + MultiSynchronicityFunctionCallResolution CreateContainerInstanceReferenceResolution( ForConstructorParameter parameter); @@ -38,7 +40,8 @@ internal abstract class RangeResolutionBaseBuilder : IRangeResolutionBaseBuilder { public ICheckTypeProperties CheckTypeProperties { get; } public IUserDefinedElements UserDefinedElements { get; } - + public abstract IErrorContext ErrorContext { get; } + protected IMethodSymbol? AddForDisposal { get; } protected IMethodSymbol? AddForDisposalAsync { get; } diff --git a/Main/ResolutionBuilding/ScopeManager.cs b/Main/ResolutionBuilding/ScopeManager.cs index 5038a2f5..63e4e5fa 100644 --- a/Main/ResolutionBuilding/ScopeManager.cs +++ b/Main/ResolutionBuilding/ScopeManager.cs @@ -17,6 +17,7 @@ internal interface IScopeManager internal class ScopeManager : IScopeManager { + private readonly IContainerInfo _containerInfo; private readonly IContainerResolutionBuilder _containerResolutionBuilder; private readonly ITransientScopeInterfaceResolutionBuilder _transientScopeInterfaceResolutionBuilder; private readonly ImmutableList _containerTypesFromAttributesList; @@ -28,6 +29,7 @@ private readonly Func< IScopeManager, IUserDefinedElements, ICheckTypeProperties, + IErrorContext, IScopeResolutionBuilder> _scopeResolutionBuilderFactory; private readonly Func< string, @@ -36,6 +38,7 @@ private readonly Func< IScopeManager, IUserDefinedElements, ICheckTypeProperties, + IErrorContext, ITransientScopeResolutionBuilder> _transientScopeResolutionBuilderFactory; private readonly Func, ScopeTypesFromAttributes> _scopeTypesFromAttributesFactory; private readonly Func, ICheckTypeProperties> _checkTypePropertiesFactory; @@ -59,6 +62,7 @@ public ScopeManager( IScopeManager, IUserDefinedElements, ICheckTypeProperties, + IErrorContext, ITransientScopeResolutionBuilder> transientScopeResolutionBuilderFactory, Func< string, @@ -67,6 +71,7 @@ public ScopeManager( IScopeManager, IUserDefinedElements, ICheckTypeProperties, + IErrorContext, IScopeResolutionBuilder> scopeResolutionBuilderFactory, Func, ScopeTypesFromAttributes> scopeTypesFromAttributesFactory, Func, ICheckTypeProperties> checkTypePropertiesFactory, @@ -74,6 +79,7 @@ public ScopeManager( IUserDefinedElements emptyUserDefinedElements, WellKnownTypesMiscellaneous wellKnownTypesMiscellaneous) { + _containerInfo = containerInfo; _containerResolutionBuilder = containerResolutionBuilder; _transientScopeInterfaceResolutionBuilder = transientScopeInterfaceResolutionBuilder; _containerTypesFromAttributesList = containerTypesFromAttributesList; @@ -95,7 +101,8 @@ public ScopeManager( defaultScopeType is {} ? _userProvidedScopeElementsFactory(defaultScopeType) : emptyUserDefinedElements, - _checkTypePropertiesFactory(_containerTypesFromAttributesList.Add(defaultScopeTypesFromAttributes))); + _checkTypePropertiesFactory(_containerTypesFromAttributesList.Add(defaultScopeTypesFromAttributes)), + new ErrorContext($"{Constants.DefaultScopeName} (in {containerInfo.Name})", defaultScopeType?.Locations.FirstOrDefault() ?? Location.None)); }, LazyThreadSafetyMode.ExecutionAndPublication); _defaultTransientScopeBuilder = new Lazy( @@ -111,7 +118,8 @@ defaultScopeType is {} defaultTransientScopeType is {} ? _userProvidedScopeElementsFactory(defaultTransientScopeType) : emptyUserDefinedElements, - _checkTypePropertiesFactory(_containerTypesFromAttributesList.Add(defaultTransientScopeTypesFromAttributes))); + _checkTypePropertiesFactory(_containerTypesFromAttributesList.Add(defaultTransientScopeTypesFromAttributes)), + new ErrorContext($"{Constants.DefaultTransientScopeName} (in {containerInfo.Name})", defaultTransientScopeType?.Locations.FirstOrDefault() ?? Location.None)); _transientScopeInterfaceResolutionBuilder.AddImplementation(ret); return ret; }, @@ -181,7 +189,8 @@ public IScopeResolutionBuilder GetScopeBuilder(INamedTypeSymbol scopeRootType) _transientScopeInterfaceResolutionBuilder, this, _userProvidedScopeElementsFactory(scopeType), - _checkTypePropertiesFactory(_containerTypesFromAttributesList.Add(scopeTypesFromAttributes))); + _checkTypePropertiesFactory(_containerTypesFromAttributesList.Add(scopeTypesFromAttributes)), + new ErrorContext($"{scopeType.Name} (in {_containerInfo.Name})", scopeType.Locations.FirstOrDefault() ?? Location.None)); _customScopeBuilders[scopeRootType] = ret; return ret; } @@ -191,17 +200,18 @@ public ITransientScopeResolutionBuilder GetTransientScopeBuilder(INamedTypeSymbo if (_customTransientScopeBuilders.TryGetValue(transientScopeRootType, out var builder)) return builder; - if (!_transientScopeRootTypeToScopeType.TryGetValue(transientScopeRootType, out var scopeType)) + if (!_transientScopeRootTypeToScopeType.TryGetValue(transientScopeRootType, out var transientScopeType)) return _defaultTransientScopeBuilder.Value; - var scopeTypesFromAttributes = _scopeTypesFromAttributesFactory(scopeType.GetAttributes()); + var scopeTypesFromAttributes = _scopeTypesFromAttributesFactory(transientScopeType.GetAttributes()); var ret = _transientScopeResolutionBuilderFactory( - scopeType.Name, + transientScopeType.Name, _containerResolutionBuilder, _transientScopeInterfaceResolutionBuilder, this, - _userProvidedScopeElementsFactory(scopeType), - _checkTypePropertiesFactory(_containerTypesFromAttributesList.Add(scopeTypesFromAttributes))); + _userProvidedScopeElementsFactory(transientScopeType), + _checkTypePropertiesFactory(_containerTypesFromAttributesList.Add(scopeTypesFromAttributes)), + new ErrorContext($"{transientScopeType.Name} (in {_containerInfo.Name})", transientScopeType.Locations.FirstOrDefault() ?? Location.None)); _customTransientScopeBuilders[transientScopeRootType] = ret; _transientScopeInterfaceResolutionBuilder.AddImplementation(ret); return ret; diff --git a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs index 2314a710..814ecc3e 100644 --- a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs @@ -34,6 +34,7 @@ internal ScopeResolutionBuilder( IScopeManager scopeManager, IUserDefinedElements userDefinedElements, ICheckTypeProperties checkTypeProperties, + IErrorContext errorContext, // dependencies WellKnownTypes wellKnownTypes, @@ -52,6 +53,7 @@ internal ScopeResolutionBuilder( synchronicityDecisionMakerFactory, localFunctionResolutionBuilderFactory) { + ErrorContext = errorContext; _containerResolutionBuilder = containerResolutionBuilder; _transientScopeInterfaceResolutionBuilder = transientScopeInterfaceResolutionBuilder; _scopeManager = scopeManager; @@ -62,6 +64,8 @@ internal ScopeResolutionBuilder( _transientScopeParameterReference = RootReferenceGenerator.Generate("transientScope"); } + public override IErrorContext ErrorContext { get; } + public override MultiSynchronicityFunctionCallResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter) => _containerResolutionBuilder.CreateContainerInstanceReferenceResolution(parameter, _containerReference); diff --git a/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs b/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs index 04625bde..1a553da3 100644 --- a/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs @@ -31,6 +31,7 @@ internal TransientScopeResolutionBuilder( IScopeManager scopeManager, IUserDefinedElements userDefinedElements, ICheckTypeProperties checkTypeProperties, + IErrorContext errorContext, // dependencies WellKnownTypes wellKnownTypes, @@ -49,6 +50,7 @@ internal TransientScopeResolutionBuilder( synchronicityDecisionMakerFactory, localFunctionResolutionBuilderFactory) { + ErrorContext = errorContext; _containerResolutionBuilder = containerResolutionBuilder; _transientScopeInterfaceResolutionBuilder = transientScopeInterfaceResolutionBuilder; _scopeManager = scopeManager; @@ -57,6 +59,8 @@ internal TransientScopeResolutionBuilder( _containerParameterReference = RootReferenceGenerator.Generate("container"); } + public override IErrorContext ErrorContext { get; } + public override MultiSynchronicityFunctionCallResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter) => _containerResolutionBuilder.CreateContainerInstanceReferenceResolution(parameter, _containerReference); diff --git a/Main/ResolutionTreeCreationErrorHarvester.cs b/Main/ResolutionTreeCreationErrorHarvester.cs deleted file mode 100644 index 0b52042b..00000000 --- a/Main/ResolutionTreeCreationErrorHarvester.cs +++ /dev/null @@ -1,69 +0,0 @@ -namespace MrMeeseeks.DIE; - -internal interface IResolutionTreeCreationErrorHarvester -{ - IReadOnlyList Harvest(ResolutionTreeItem root); -} - -internal class ResolutionTreeCreationErrorHarvester : IResolutionTreeCreationErrorHarvester -{ - public IReadOnlyList Harvest(ResolutionTreeItem root) - { - var errorTreeItems = new List(); - //Inner(root, errorTreeItems); // todo error handling - return errorTreeItems; - - static void Inner(ResolutionTreeItem item, ICollection errorTreeItems) - { - switch (item) - { - case DeferringResolvable: - break; - case FunctionCallResolution: - break; - case RootResolutionFunction: - break; - case TransientScopeAsDisposableResolution: - break; - case ScopeRootFunction: - break; - case ScopeRootResolution: - break; - case FieldResolution: - break; - case RangeResolution containerResolution: - foreach (var overload in containerResolution.RangedInstanceFunctionGroups.SelectMany(ri => ri.Overloads)) - Inner(overload.Resolvable, errorTreeItems); - foreach (var rootResolution in containerResolution.RootResolutions) - Inner(rootResolution, errorTreeItems); - break; - case ErrorTreeItem errorTreeItem: - errorTreeItems.Add(errorTreeItem); - break; - case ConstructorResolution constructorResolution: - foreach (var valueTuple in constructorResolution.Parameter) - Inner(valueTuple.Dependency, errorTreeItems); - break; - case SyntaxValueTupleResolution syntaxValueTupleResolution: - foreach (var resolvable in syntaxValueTupleResolution.Items) - Inner(resolvable, errorTreeItems); - break; - case CollectionResolution collectionResolution: - foreach (var resolutionTreeItem in collectionResolution.Parameter) - Inner(resolutionTreeItem, errorTreeItems); - break; - case ParameterResolution: - break; - case FuncResolution: - break; - case InterfaceResolution interfaceResolution: - Inner(interfaceResolution.Dependency, errorTreeItems); - break; - case Resolvable: - throw new ArgumentOutOfRangeException(nameof(item)); - default: - throw new ArgumentOutOfRangeException(nameof(item)); - } - } - } -} \ No newline at end of file diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index 05cf4584..ab6f5587 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -72,7 +72,7 @@ internal record TransientScopeAsAsyncDisposableResolution( string TypeFullName) : Resolvable(Reference, TypeFullName); internal record ErrorTreeItem( - string Message) : Resolvable("error_99_99", "Error"); + Diagnostic Diagnostic) : Resolvable("error_99_99", "Error"); internal record InterfaceResolution( string Reference, diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index dccab8b2..326a2e53 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -65,20 +65,16 @@ public void Execute(GeneratorExecutionContext context) wellKnownTypesMiscellaneous); var containerGenerator = new ContainerGenerator(context, diagLogger, ContainerCodeBuilderFactory, TransientScopeCodeBuilderFactory, ScopeCodeBuilderFactory); var referenceGeneratorFactory = new ReferenceGeneratorFactory(ReferenceGeneratorFactory); - var containerErrorGenerator = new ContainerErrorGenerator(context); var containerDieExceptionGenerator = new ContainerDieExceptionGenerator(context, wellKnownTypesMiscellaneous); - var resolutionTreeCreationErrorHarvester = new ResolutionTreeCreationErrorHarvester(); var implementationTypeSetCache = new ImplementationTypeSetCache(context, wellKnownTypes); new ExecuteImpl( errorDescriptionInsteadOfBuildFailure, context, wellKnownTypesMiscellaneous, containerGenerator, - containerErrorGenerator, containerDieExceptionGenerator, validateContainer, ResolutionTreeFactory, - resolutionTreeCreationErrorHarvester, ContainerInfoFactory, diagLogger).Execute(); @@ -134,13 +130,15 @@ ITransientScopeResolutionBuilder TransientScopeResolutionBuilderFactory( ITransientScopeInterfaceResolutionBuilder transientScopeInterfaceResolutionBuilder, IScopeManager scopeManager, IUserDefinedElements userProvidedScopeElements, - ICheckTypeProperties checkTypeProperties) => new TransientScopeResolutionBuilder( + ICheckTypeProperties checkTypeProperties, + IErrorContext errorContext) => new TransientScopeResolutionBuilder( name, containerBuilder, transientScopeInterfaceResolutionBuilder, scopeManager, userProvidedScopeElements, checkTypeProperties, + errorContext, wellKnownTypes, referenceGeneratorFactory, @@ -154,13 +152,15 @@ IScopeResolutionBuilder ScopeResolutionBuilderFactory( ITransientScopeInterfaceResolutionBuilder transientScopeInterfaceResolutionBuilder, IScopeManager scopeManager, IUserDefinedElements userProvidedScopeElements, - ICheckTypeProperties checkTypeProperties) => new ScopeResolutionBuilder( + ICheckTypeProperties checkTypeProperties, + IErrorContext errorContext) => new ScopeResolutionBuilder( name, containerBuilder, transientScopeInterfaceResolutionBuilder, scopeManager, userProvidedScopeElements, checkTypeProperties, + errorContext, wellKnownTypes, referenceGeneratorFactory, From c53d520aa0bcb30a105e4ad8dadcf7a97ac9fa36 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Tue, 28 Jun 2022 23:28:37 +0200 Subject: [PATCH 088/162] Fixing bug with parameters --- .../Function/FunctionResolutionBuilder.cs | 9 +++++-- .../LocalFunctionResolutionBuilder.cs | 6 ++--- .../RangedFunctionResolutionBuilder.cs | 8 ++++-- ...copeRootCreateFunctionResolutionBuilder.cs | 6 ++++- Sample/Context.cs | 25 ++++++------------- Test/Scoping/FuncContainerInstance.cs | 22 ++++++++++++++++ 6 files changed, 49 insertions(+), 27 deletions(-) create mode 100644 Test/Scoping/FuncContainerInstance.cs diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs index 0a679a40..61f33d6c 100644 --- a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs @@ -71,6 +71,8 @@ internal abstract partial class FunctionResolutionBuilder : IFunctionResolutionB public Lazy SynchronicityDecision => _synchronicityDecisionMaker.Decision; protected Lazy Resolvable { get; } + protected IReadOnlyList<(ITypeSymbol, ParameterResolution)> CurrentParameters { get; } + protected IReadOnlyList Parameters { get; } public INamedTypeSymbol OriginalReturnType { get; } @@ -101,8 +103,11 @@ internal FunctionResolutionBuilder( $"{OriginalReturnType.FullName()}({string.Join(", ", currentParameters.Select(p => p.Resolution.TypeFullName))})"); RootReferenceGenerator = referenceGeneratorFactory.Create(); - Parameters = currentParameters - .Select(p => new ParameterResolution(RootReferenceGenerator.Generate(p.Type), p.Resolution.TypeFullName)) + CurrentParameters = currentParameters + .Select(p => (p.Type, new ParameterResolution(RootReferenceGenerator.Generate(p.Type), p.Resolution.TypeFullName))) + .ToList(); + Parameters = CurrentParameters + .Select(p => p.Item2) .ToList(); Resolvable = new(CreateResolvable); diff --git a/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs index 73d55d87..3c31f0e6 100644 --- a/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs @@ -7,7 +7,6 @@ internal interface ILocalFunctionResolutionBuilder : IFunctionResolutionBuilder internal class LocalFunctionResolutionBuilder : FunctionResolutionBuilder, ILocalFunctionResolutionBuilder { private readonly INamedTypeSymbol _returnType; - private readonly IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> _parameters; public LocalFunctionResolutionBuilder( // parameter @@ -32,14 +31,13 @@ public LocalFunctionResolutionBuilder( functionCycleTracker) { _returnType = returnType; - _parameters = parameters; Name = RootReferenceGenerator.Generate("Create", _returnType); } protected override string Name { get; } - protected override Resolvable CreateResolvable() => SwitchType(new SwitchTypeParameter(_returnType, _parameters, ImmutableStack.Empty)).Item1; + protected override Resolvable CreateResolvable() => SwitchType(new SwitchTypeParameter(_returnType, CurrentParameters, ImmutableStack.Empty)).Item1; public override FunctionResolution Build() { @@ -48,7 +46,7 @@ public override FunctionResolution Build() Name, TypeFullName, Resolvable.Value, - _parameters.Select(t => t.Resolution).ToList(), + Parameters, SynchronicityDecision.Value); } } \ No newline at end of file diff --git a/Main/ResolutionBuilding/Function/RangedFunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/RangedFunctionResolutionBuilder.cs index 2ab2cd84..d7b07371 100644 --- a/Main/ResolutionBuilding/Function/RangedFunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/RangedFunctionResolutionBuilder.cs @@ -39,7 +39,11 @@ public RangedFunctionResolutionBuilder( protected override string Name { get; } protected override Resolvable CreateResolvable() => CreateConstructorResolution( - _forConstructorParameter with { ImplementationStack = ImmutableStack.Empty }).Item1; + _forConstructorParameter with + { + ImplementationStack = ImmutableStack.Empty, + CurrentFuncParameters = CurrentParameters + }).Item1; public override FunctionResolution Build() { @@ -49,7 +53,7 @@ public override FunctionResolution Build() Name, TypeFullName, Resolvable.Value, - _forConstructorParameter.CurrentFuncParameters.Select(t => t.Resolution).ToList(), + Parameters, SynchronicityDecision.Value); } } \ No newline at end of file diff --git a/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs index 81066c20..86051b58 100644 --- a/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs @@ -37,7 +37,11 @@ public ScopeRootCreateFunctionResolutionBuilder( protected override string Name { get; } protected override Resolvable CreateResolvable() => SwitchImplementation( - _parameter with { ImplementationStack = ImmutableStack.Empty }).Item1; + _parameter with + { + ImplementationStack = ImmutableStack.Empty, + CurrentParameters = CurrentParameters + }).Item1; public override FunctionResolution Build() { diff --git a/Sample/Context.cs b/Sample/Context.cs index 3ca84c8e..ff561e15 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -1,23 +1,12 @@ -using MrMeeseeks.DIE.Configuration.Attributes; +using System; +using System.IO; +using MrMeeseeks.DIE.Configuration.Attributes; -namespace MrMeeseeks.DIE.Test.CycleDetection.Implementation.Cycle.Proxied; +namespace MrMeeseeks.DIE.Test.ConstructorChoice.WithParameter; - -internal class Proxy1 -{ - internal Proxy1(Dependency inner) {} -} -internal class Proxy0 -{ - internal Proxy0(Proxy1 inner) {} -} - -internal class Dependency -{ - internal Dependency(Proxy0 inner) {} -} - -[CreateFunction(typeof(Dependency), "Create")] +[ImplementationAggregation(typeof(FileInfo))] +[ConstructorChoice(typeof(FileInfo), typeof(string))] +[CreateFunction(typeof(Func), "Create")] internal sealed partial class Container { diff --git a/Test/Scoping/FuncContainerInstance.cs b/Test/Scoping/FuncContainerInstance.cs new file mode 100644 index 00000000..3002d87e --- /dev/null +++ b/Test/Scoping/FuncContainerInstance.cs @@ -0,0 +1,22 @@ +using MrMeeseeks.DIE.Configuration.Attributes; +using System; +using System.Threading.Tasks; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Scoping.FuncContainerInstance; + +internal class Dependency : IContainerInstance {} + +[CreateFunction(typeof(Func), "Create")] +internal sealed partial class Container {} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var instance = container.Create()("Foo"); + Assert.IsType(instance); + } +} \ No newline at end of file From 3f6d3ee6f118500404744c91429abd54d1bba2cd Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Tue, 5 Jul 2022 18:08:07 +0200 Subject: [PATCH 089/162] Removed debug logging of start and end --- Main/CodeBuilding/ContainerGenerator.cs | 6 ------ Main/ContainerInfo.cs | 4 ---- Main/DiagLogger.cs | 11 ----------- Main/ExecuteImpl.cs | 4 ---- 4 files changed, 25 deletions(-) diff --git a/Main/CodeBuilding/ContainerGenerator.cs b/Main/CodeBuilding/ContainerGenerator.cs index 9fa39ded..05f3ac53 100644 --- a/Main/CodeBuilding/ContainerGenerator.cs +++ b/Main/CodeBuilding/ContainerGenerator.cs @@ -32,12 +32,6 @@ internal ContainerGenerator( public void Generate(IContainerInfo containerInfo, ContainerResolution containerResolution) { - if (!containerInfo.IsValid) - { - _diagLogger.Log($"return generation"); - return; - } - var containerCodeBuilder = _containerCodeBuilderFactory( containerInfo, containerResolution, diff --git a/Main/ContainerInfo.cs b/Main/ContainerInfo.cs index 5d431877..e93142d0 100644 --- a/Main/ContainerInfo.cs +++ b/Main/ContainerInfo.cs @@ -5,7 +5,6 @@ internal interface IContainerInfo string Name { get; } string Namespace { get; } string FullName { get; } - bool IsValid { get; } INamedTypeSymbol ContainerType { get; } IReadOnlyList<(INamedTypeSymbol, string)> CreateFunctionData { get; } } @@ -36,14 +35,11 @@ internal ContainerInfo( : ((INamedTypeSymbol, string)?) null) .OfType<(INamedTypeSymbol, string)>() .ToList(); - - IsValid = CreateFunctionData.Any(); } public string Name { get; } public string Namespace { get; } public string FullName { get; } - public bool IsValid { get; } public INamedTypeSymbol ContainerType { get; } public IReadOnlyList<(INamedTypeSymbol, string)> CreateFunctionData { get; } } \ No newline at end of file diff --git a/Main/DiagLogger.cs b/Main/DiagLogger.cs index da73d8d3..a31920a3 100644 --- a/Main/DiagLogger.cs +++ b/Main/DiagLogger.cs @@ -2,10 +2,6 @@ internal interface IDiagLogger { - void Log(string message); - - void Log(int id, string title, string message, string category, DiagnosticSeverity diagnosticSeverity); - void Error(DieException exception); void Log(Diagnostic diagnostic); @@ -23,13 +19,6 @@ internal DiagLogger( _ignoreErrors = ignoreErrors; _context = context; } - - public void Log(int id, string title, string message, string category, DiagnosticSeverity diagnosticSeverity) => - _context.ReportDiagnostic(Diagnostic.Create( - new DiagnosticDescriptor($"DIE{id.ToString().PadLeft(3, '0')}", title, message, category, diagnosticSeverity, true), - Location.None)); - - public void Log(string message) => Log(0, "INFO", message, "INFO", DiagnosticSeverity.Warning); public void Error(DieException exception) { diff --git a/Main/ExecuteImpl.cs b/Main/ExecuteImpl.cs index 6b521ae4..4d935a4d 100644 --- a/Main/ExecuteImpl.cs +++ b/Main/ExecuteImpl.cs @@ -46,8 +46,6 @@ internal ExecuteImpl( public void Execute() { - _diagLogger.Log("Start Execute"); - foreach (var syntaxTree in _context.Compilation.SyntaxTrees) { var semanticModel = _context.Compilation.GetSemanticModel(syntaxTree); @@ -114,7 +112,5 @@ public void Execute() } } } - - _diagLogger.Log("End Execute"); } } \ No newline at end of file From 3b2c67d757fbf46a177304ae1e06de0a72c061eb Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sun, 10 Jul 2022 17:39:06 +0200 Subject: [PATCH 090/162] Making Lazy & Func merge previous overrides --- Main/CodeBuilding/RangeCodeBaseBuilder.cs | 24 ++++---- .../ContainerResolutionBuilder.cs | 20 +++---- ...ontainerCreateFunctionResolutionBuilder.cs | 4 +- .../FunctionResolutionBuilder.Dtos.cs | 12 ++-- .../Function/FunctionResolutionBuilder.cs | 57 +++++++++++++------ .../LocalFunctionResolutionBuilder.cs | 10 +++- .../RangedFunctionGroupResolutionBuilder.cs | 2 +- .../RangedFunctionResolutionBuilder.cs | 7 ++- ...copeRootCreateFunctionResolutionBuilder.cs | 5 +- .../RangeResolutionBaseBuilder.cs | 18 +++--- Main/ResolutionBuilding/ResolutionDtos.cs | 12 ++-- .../ScopeResolutionBuilder.cs | 10 ++-- ...ransientScopeInterfaceResolutionBuilder.cs | 10 ++-- .../TransientScopeResolutionBuilder.cs | 10 ++-- Main/ResolutionTreeItem.cs | 5 +- Main/SourceGenerator.cs | 2 +- Test/Func/Override.cs | 40 +++++++++++++ Test/Func/OverrideCombination.cs | 56 ++++++++++++++++++ .../OverrideMultipleParameterOfSameType.cs | 40 +++++++++++++ Test/Func/OverrideMultipleTypes.cs | 55 ++++++++++++++++++ Test/Lazy/Override.cs | 41 +++++++++++++ 21 files changed, 354 insertions(+), 86 deletions(-) create mode 100644 Test/Func/Override.cs create mode 100644 Test/Func/OverrideCombination.cs create mode 100644 Test/Func/OverrideMultipleParameterOfSameType.cs create mode 100644 Test/Func/OverrideMultipleTypes.cs create mode 100644 Test/Lazy/Override.cs diff --git a/Main/CodeBuilding/RangeCodeBaseBuilder.cs b/Main/CodeBuilding/RangeCodeBaseBuilder.cs index 3820e072..471e5446 100644 --- a/Main/CodeBuilding/RangeCodeBaseBuilder.cs +++ b/Main/CodeBuilding/RangeCodeBaseBuilder.cs @@ -324,7 +324,7 @@ private static StringBuilder GenerateFields( stringBuilder = items.Aggregate(stringBuilder, GenerateFields); stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); break; - case FuncResolution(var reference, var typeFullName, _): + case FuncResolution(var reference, var typeFullName, _, _): stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); break; case ParameterResolution: @@ -375,12 +375,17 @@ private StringBuilder GenerateResolutions( case MultiSynchronicityFunctionCallResolution { SelectedFunctionCall: {} selectedFunctionCall}: stringBuilder = GenerateResolutions(stringBuilder, selectedFunctionCall); break; - case LazyResolution(var reference, var typeFullName, var methodGroup): - string owner = ""; - if (methodGroup.OwnerReference is { } explicitOwner) - owner = $"{explicitOwner}."; + case LazyResolution(var reference, var typeFullName, var innerCallOfLambda): + if (innerCallOfLambda.SelectedFunctionCall != innerCallOfLambda.Sync) + throw new Exception("Lazy resolution has to call sync function"); // todo stringBuilder = stringBuilder - .AppendLine($"{reference} = new {typeFullName}({owner}{methodGroup.Reference});"); + .AppendLine($"{reference} = new {typeFullName}(() => {Constants.ThisKeyword}.{innerCallOfLambda.Sync.FunctionReference}({string.Join(", ", innerCallOfLambda.Sync.Parameters.Select(p => $"{p.Name}: {p.Reference}"))}));"); + break; + case FuncResolution(var reference, _, var lambdaParameters, var innerCallOfLambda): + if (innerCallOfLambda.SelectedFunctionCall != innerCallOfLambda.Sync) + throw new Exception("Func resolution has to call sync function"); // todo + stringBuilder = stringBuilder + .AppendLine($"{reference} = ({string.Join(", " ,lambdaParameters.Select(p => p.Reference))}) => {Constants.ThisKeyword}.{innerCallOfLambda.Sync.FunctionReference}({string.Join(", ", innerCallOfLambda.Sync.Parameters.Select(p => $"{p.Name}: {p.Reference}"))});"); break; case FunctionCallResolution(var reference, _, _, var functionReference, var functionOwner, var parameters) functionCallResolution: string owner2 = ""; @@ -563,13 +568,6 @@ private StringBuilder GenerateResolutions( stringBuilder = items.Aggregate(stringBuilder, GenerateResolutions); stringBuilder = stringBuilder.AppendLine($"{reference} = ({string.Join(", ", items.Select(d => d.Reference))});"); break; - case FuncResolution(var reference, _, var methodGroup): - string owner1 = ""; - if (methodGroup.OwnerReference is { } explicitOwner1) - owner1 = $"{explicitOwner1}."; - stringBuilder = stringBuilder - .AppendLine($"{reference} = {owner1}{methodGroup.Reference};"); - break; case ParameterResolution: break; // parameter exists already case NullResolution(var reference, var typeFullName): diff --git a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs index 4956cfa2..46471b07 100644 --- a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs @@ -40,7 +40,7 @@ internal ContainerResolutionBuilder( Func createFunctionResolutionBuilderFactory, Func rangedFunctionGroupResolutionBuilderFactory, Func synchronicityDecisionMakerFactory, - Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory, + Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory, IUserDefinedElements userDefinedElement, IFunctionCycleTracker functionCycleTracker) : base( @@ -95,7 +95,7 @@ public override MultiSynchronicityFunctionCallResolution CreateTransientScopeIns public override TransientScopeRootResolution CreateTransientScopeRootResolution( SwitchImplementationParameter parameter, INamedTypeSymbol rootType, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) => + ImmutableSortedDictionary currentParameters) => _scopeManager .GetTransientScopeBuilder(rootType) .AddCreateResolveFunction( @@ -107,7 +107,7 @@ public override TransientScopeRootResolution CreateTransientScopeRootResolution( public override ScopeRootResolution CreateScopeRootResolution( SwitchImplementationParameter parameter, INamedTypeSymbol rootType, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) => + ImmutableSortedDictionary currentParameters) => _scopeManager .GetScopeBuilder(rootType) .AddCreateResolveFunction( @@ -165,7 +165,7 @@ public ContainerResolution Build() SymbolEqualityComparer.Default)) { var call = createFunction.BuildFunctionCall( - Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>(), + ImmutableSortedDictionary.Empty, Constants.ThisKeyword); call.Sync.Await = false; call.AsyncTask.Await = false; @@ -186,7 +186,7 @@ public ContainerResolution Build() .FullName(); var wrappedTaskReference = RootReferenceGenerator.Generate(_wellKnownTypes.Task); var taskCall = createFunction.BuildFunctionCall( - Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>(), + ImmutableSortedDictionary.Empty, Constants.ThisKeyword); taskCall.Sync.Await = false; taskCall.AsyncTask.Await = false; @@ -210,7 +210,7 @@ public ContainerResolution Build() .FullName(); var wrappedValueTaskReference = RootReferenceGenerator.Generate(_wellKnownTypes.Task); var valueTaskCall = createFunction.BuildFunctionCall( - Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>(), + ImmutableSortedDictionary.Empty, Constants.ThisKeyword); valueTaskCall.Sync.Await = false; valueTaskCall.AsyncTask.Await = false; @@ -233,7 +233,7 @@ public ContainerResolution Build() SymbolEqualityComparer.Default)) { var call = createFunction.BuildFunctionCall( - Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>(), + ImmutableSortedDictionary.Empty, Constants.ThisKeyword); call.Sync.Await = false; call.AsyncTask.Await = false; @@ -254,7 +254,7 @@ public ContainerResolution Build() .FullName(); var wrappedValueTaskReference = RootReferenceGenerator.Generate(_wellKnownTypes.Task); var valueCall = createFunction.BuildFunctionCall( - Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>(), + ImmutableSortedDictionary.Empty, Constants.ThisKeyword); valueCall.Sync.Await = false; valueCall.AsyncTask.Await = false; @@ -281,7 +281,7 @@ public ContainerResolution Build() .Construct(createFunction.OriginalReturnType) .FullName(); var call = createFunction.BuildFunctionCall( - Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>(), + ImmutableSortedDictionary.Empty, Constants.ThisKeyword); call.Sync.Await = false; call.AsyncTask.Await = false; @@ -301,7 +301,7 @@ public ContainerResolution Build() rootFunctions.Add(publicTaskResolutionFunction); var valueCall = createFunction.BuildFunctionCall( - Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>(), + ImmutableSortedDictionary.Empty, Constants.ThisKeyword); valueCall.Sync.Await = false; valueCall.AsyncTask.Await = false; diff --git a/Main/ResolutionBuilding/Function/ContainerCreateFunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/ContainerCreateFunctionResolutionBuilder.cs index 18e3192f..676b2f35 100644 --- a/Main/ResolutionBuilding/Function/ContainerCreateFunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/ContainerCreateFunctionResolutionBuilder.cs @@ -21,7 +21,7 @@ public ContainerCreateFunctionResolutionBuilder( : base( rangeResolutionBaseBuilder, returnType, - Array.Empty<(ITypeSymbol, ParameterResolution)>(), + ImmutableSortedDictionary.Empty, synchronicityDecisionMaker, new object(), @@ -38,7 +38,7 @@ public ContainerCreateFunctionResolutionBuilder( protected override Resolvable CreateResolvable() => SwitchType(new SwitchTypeParameter( _returnType, - Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>(), + ImmutableSortedDictionary.Empty, ImmutableStack.Empty)).Item1; public override FunctionResolution Build() diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.Dtos.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.Dtos.cs index 4f9e4b9e..dd971312 100644 --- a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.Dtos.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.Dtos.cs @@ -4,38 +4,38 @@ internal abstract partial class FunctionResolutionBuilder { private record SwitchInterfaceAfterScopeRootParameter( INamedTypeSymbol InterfaceType, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters, + ImmutableSortedDictionary CurrentParameters, IImmutableStack ImplementationStack); private record CreateInterfaceParameter( INamedTypeSymbol InterfaceType, INamedTypeSymbol ImplementationType, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters, + ImmutableSortedDictionary CurrentParameters, IImmutableStack ImplementationStack); private record CreateInterfaceParameterAsComposition( INamedTypeSymbol InterfaceType, INamedTypeSymbol ImplementationType, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters, + ImmutableSortedDictionary CurrentParameters, IImmutableStack ImplementationStack, CompositionInterfaceExtension Composition) : CreateInterfaceParameter(InterfaceType, ImplementationType, CurrentParameters, ImplementationStack); private record SwitchClassParameter( INamedTypeSymbol TypeSymbol, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters, + ImmutableSortedDictionary CurrentParameters, IImmutableStack ImplementationStack); private record SwitchImplementationParameterWithDecoration( INamedTypeSymbol ImplementationType, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters, + ImmutableSortedDictionary CurrentParameters, IImmutableStack ImplementationStack, DecorationInterfaceExtension Decoration) : SwitchImplementationParameter(ImplementationType, CurrentParameters, ImplementationStack); private record SwitchImplementationParameterWithComposition( INamedTypeSymbol ImplementationType, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters, + ImmutableSortedDictionary CurrentParameters, IImmutableStack ImplementationStack, CompositionInterfaceExtension Composition) : SwitchImplementationParameter(ImplementationType, CurrentParameters, ImplementationStack); diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs index 61f33d6c..b61a5208 100644 --- a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs @@ -45,7 +45,7 @@ internal interface IFunctionResolutionBuilder : IResolutionBuilder currentParameters, + ImmutableSortedDictionary currentParameters, string? ownerReference); MethodGroupResolution BuildMethodGroup(); @@ -82,7 +82,7 @@ internal FunctionResolutionBuilder( // parameters IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, INamedTypeSymbol returnType, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters, + ImmutableSortedDictionary currentParameters, IFunctionResolutionSynchronicityDecisionMaker synchronicityDecisionMaker, object handleIdentity, @@ -100,11 +100,11 @@ internal FunctionResolutionBuilder( _userDefinedElements = rangeResolutionBaseBuilder.UserDefinedElements; _handle = new FunctionResolutionBuilderHandle( handleIdentity, - $"{OriginalReturnType.FullName()}({string.Join(", ", currentParameters.Select(p => p.Resolution.TypeFullName))})"); + $"{OriginalReturnType.FullName()}({string.Join(", ", currentParameters.Select(p => p.Value.Item2.TypeFullName))})"); RootReferenceGenerator = referenceGeneratorFactory.Create(); CurrentParameters = currentParameters - .Select(p => (p.Type, new ParameterResolution(RootReferenceGenerator.Generate(p.Type), p.Resolution.TypeFullName))) + .Select(p => (p.Value.Item1, new ParameterResolution(RootReferenceGenerator.Generate(p.Value.Item1), p.Value.Item2.TypeFullName))) .ToList(); Parameters = CurrentParameters .Select(p => p.Item2) @@ -119,8 +119,9 @@ private string ErrorMessage(IImmutableStack stack, ITypeSymbol protected (Resolvable, ITaskConsumableResolution?) SwitchType(SwitchTypeParameter parameter) { var (type, currentFuncParameters, implementationStack) = parameter; - if (currentFuncParameters.FirstOrDefault(t => SymbolEqualityComparer.Default.Equals(t.Type.OriginalDefinition, type.OriginalDefinition)) is { Type: not null, Resolution: not null } funcParameter) - return (funcParameter.Resolution, null); + if (currentFuncParameters.FirstOrDefault(t => SymbolEqualityComparer.Default.Equals( + t.Value.Item1.OriginalDefinition, type.OriginalDefinition)) is { Value.Item1: not null, Value.Item2: not null } funcParameter) + return (funcParameter.Value.Item2, null); if (_userDefinedElements.GetFactoryFieldFor(type) is { } instance) return ( @@ -222,14 +223,22 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup null); } + var currentParameters = ImmutableSortedDictionary.CreateRange( + currentFuncParameters.Select(cp => + new KeyValuePair( + cp.Value.Item1.FullName(), + cp.Value))); + var newLocalFunction = _rangeResolutionBaseBuilder.CreateLocalFunctionResolution( genericType, - Array.Empty<(ITypeSymbol Type, ParameterResolution Resolution)>()); + currentParameters); var constructorInjection = new LazyResolution( RootReferenceGenerator.Generate(namedTypeSymbol), namedTypeSymbol.FullName(), - newLocalFunction.BuildMethodGroup()); + newLocalFunction.BuildFunctionCall( + currentParameters, + Constants.ThisKeyword)); return (constructorInjection, null); } @@ -247,21 +256,37 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup null); } - var parameterTypes = namedTypeSymbol0 + var lambdaParameters = namedTypeSymbol0 .TypeArguments .Take(namedTypeSymbol0.TypeArguments.Length - 1) .Select(ts => (Type: ts, Resolution: new ParameterResolution(RootReferenceGenerator.Generate(ts), ts.FullName()))) .ToArray(); + var setOfProcessedTypes = new HashSet(SymbolEqualityComparer.IncludeNullability); + + var nextCurrentParameters = currentFuncParameters; + + foreach (var lambdaParameter in lambdaParameters) + { + if (setOfProcessedTypes.Contains(lambdaParameter.Type, SymbolEqualityComparer.IncludeNullability) + || lambdaParameter.Type is not INamedTypeSymbol lambdaType) + continue; + + setOfProcessedTypes.Add(lambdaType); + + nextCurrentParameters = nextCurrentParameters.Add(lambdaParameter.Type.FullName(), lambdaParameter); + } + var newLocalFunction = _rangeResolutionBaseBuilder.CreateLocalFunctionResolution( returnType, - parameterTypes); + nextCurrentParameters); return ( new FuncResolution( RootReferenceGenerator.Generate(type), type.FullName(), - newLocalFunction.BuildMethodGroup()), + lambdaParameters.Select(t => t.Resolution).ToImmutableArray(), + newLocalFunction.BuildFunctionCall(nextCurrentParameters, Constants.ThisKeyword)), null); } @@ -807,7 +832,7 @@ false when initializationMethod.ReturnType.Equals(_wellKnownTypes.ValueTask, Sym ITypeSymbol typeSymbol, string parameterName, INamedTypeSymbol impType, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currParameter) + ImmutableSortedDictionary currParameter) { if (outParameters.TryGetValue(parameterName, out var outParameterResolution)) return (parameterName, new ParameterResolution(outParameterResolution.Reference, outParameterResolution.TypeFullName)); @@ -914,7 +939,7 @@ protected void AdjustForSynchronicity() => }; public MultiSynchronicityFunctionCallResolution BuildFunctionCall( - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters, string? ownerReference) + ImmutableSortedDictionary currentParameters, string? ownerReference) { var returnReference = RootReferenceGenerator.Generate("ret"); return new(new(returnReference, @@ -922,20 +947,20 @@ public MultiSynchronicityFunctionCallResolution BuildFunctionCall( OriginalReturnType.FullName(), Name, ownerReference, - Parameters.Zip(currentParameters, (p, cp) => (p.Reference, cp.Resolution.Reference)).ToList()) + Parameters.Zip(currentParameters, (p, cp) => (p.Reference, cp.Value.Item2.Reference)).ToList()) { Await = false }, new(returnReference, _wellKnownTypes.Task1.Construct(OriginalReturnType).FullName(), OriginalReturnType.FullName(), Name, ownerReference, - Parameters.Zip(currentParameters, (p, cp) => (p.Reference, cp.Resolution.Reference)).ToList()), + Parameters.Zip(currentParameters, (p, cp) => (p.Reference, cp.Value.Item2.Reference)).ToList()), new(returnReference, _wellKnownTypes.ValueTask1.Construct(OriginalReturnType).FullName(), OriginalReturnType.FullName(), Name, ownerReference, - Parameters.Zip(currentParameters, (p, cp) => (p.Reference, cp.Resolution.Reference)).ToList()), + Parameters.Zip(currentParameters, (p, cp) => (p.Reference, cp.Value.Item2.Reference)).ToList()), SynchronicityDecision, _handle); } diff --git a/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs index 3c31f0e6..7811579f 100644 --- a/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs @@ -12,7 +12,7 @@ public LocalFunctionResolutionBuilder( // parameter IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, INamedTypeSymbol returnType, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> parameters, + ImmutableSortedDictionary parameters, IFunctionResolutionSynchronicityDecisionMaker synchronicityDecisionMaker, // dependencies @@ -37,7 +37,13 @@ public LocalFunctionResolutionBuilder( protected override string Name { get; } - protected override Resolvable CreateResolvable() => SwitchType(new SwitchTypeParameter(_returnType, CurrentParameters, ImmutableStack.Empty)).Item1; + protected override Resolvable CreateResolvable() => SwitchType(new SwitchTypeParameter( + _returnType, + ImmutableSortedDictionary.CreateRange( + CurrentParameters.Select(t => new KeyValuePair( + t.Item1.FullName(), + t))), + ImmutableStack.Empty)).Item1; public override FunctionResolution Build() { diff --git a/Main/ResolutionBuilding/Function/RangedFunctionGroupResolutionBuilder.cs b/Main/ResolutionBuilding/Function/RangedFunctionGroupResolutionBuilder.cs index 70090c7c..c852f605 100644 --- a/Main/ResolutionBuilding/Function/RangedFunctionGroupResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/RangedFunctionGroupResolutionBuilder.cs @@ -56,7 +56,7 @@ public IRangedFunctionResolutionBuilder GetInstanceFunction( ForConstructorParameter parameter, Lazy synchronicityDecisionMaker) { - var listedParameterTypes = string.Join(",", parameter.CurrentFuncParameters.Select(p => p.Item2.TypeFullName)); + var listedParameterTypes = string.Join(",", parameter.CurrentParameters.Select(p => p.Value.Item2.TypeFullName)); if (!_overloads.TryGetValue(listedParameterTypes, out var function)) { function = _rangedFunctionResolutionBuilderFactory( diff --git a/Main/ResolutionBuilding/Function/RangedFunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/RangedFunctionResolutionBuilder.cs index d7b07371..42e38452 100644 --- a/Main/ResolutionBuilding/Function/RangedFunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/RangedFunctionResolutionBuilder.cs @@ -23,7 +23,7 @@ public RangedFunctionResolutionBuilder( : base( rangeResolutionBaseBuilder, forConstructorParameter.ImplementationType, - forConstructorParameter.CurrentFuncParameters, + forConstructorParameter.CurrentParameters, synchronicityDecisionMaker, handleIdentity, @@ -42,7 +42,10 @@ protected override Resolvable CreateResolvable() => CreateConstructorResolution( _forConstructorParameter with { ImplementationStack = ImmutableStack.Empty, - CurrentFuncParameters = CurrentParameters + CurrentParameters = ImmutableSortedDictionary.CreateRange( + CurrentParameters.Select(t => new KeyValuePair( + t.Item1.FullName(), + t))) }).Item1; public override FunctionResolution Build() diff --git a/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs index 86051b58..6434f19c 100644 --- a/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs @@ -40,7 +40,10 @@ protected override Resolvable CreateResolvable() => SwitchImplementation( _parameter with { ImplementationStack = ImmutableStack.Empty, - CurrentParameters = CurrentParameters + CurrentParameters = ImmutableSortedDictionary.CreateRange( + CurrentParameters.Select(t => new KeyValuePair( + t.Item1.FullName(), + t))) }).Item1; public override FunctionResolution Build() diff --git a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs index c55c7824..0f098f08 100644 --- a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs +++ b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs @@ -22,18 +22,18 @@ MultiSynchronicityFunctionCallResolution CreateScopeInstanceReferenceResolution( TransientScopeRootResolution CreateTransientScopeRootResolution( SwitchImplementationParameter parameter, INamedTypeSymbol rootType, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters); + ImmutableSortedDictionary currentParameters); ScopeRootResolution CreateScopeRootResolution( SwitchImplementationParameter parameter, INamedTypeSymbol rootType, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters); + ImmutableSortedDictionary currentParameters); void RegisterDisposalType(DisposalType disposalType); IFunctionResolutionBuilder CreateLocalFunctionResolution( INamedTypeSymbol type, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters); + ImmutableSortedDictionary currentParameters); } internal abstract class RangeResolutionBaseBuilder : IRangeResolutionBaseBuilder @@ -47,7 +47,7 @@ internal abstract class RangeResolutionBaseBuilder : IRangeResolutionBaseBuilder private readonly WellKnownTypes _wellKnownTypes; private readonly Func _rangedFunctionGroupResolutionBuilderFactory; - private readonly Func, ILocalFunctionResolutionBuilder> _localFunctionResolutionBuilderFactory; + private readonly Func, ILocalFunctionResolutionBuilder> _localFunctionResolutionBuilderFactory; private readonly Func _synchronicityDecisionMakerFactory; protected readonly IReferenceGenerator RootReferenceGenerator; @@ -69,7 +69,7 @@ protected RangeResolutionBaseBuilder( IReferenceGeneratorFactory referenceGeneratorFactory, Func rangedFunctionGroupResolutionBuilderFactory, Func synchronicityDecisionMakerFactory, - Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) + Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) { CheckTypeProperties = checkTypeProperties; UserDefinedElements = userDefinedElements; @@ -102,17 +102,17 @@ public MultiSynchronicityFunctionCallResolution CreateScopeInstanceReferenceReso public abstract TransientScopeRootResolution CreateTransientScopeRootResolution( SwitchImplementationParameter parameter, INamedTypeSymbol rootType, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters); + ImmutableSortedDictionary currentParameters); public abstract ScopeRootResolution CreateScopeRootResolution( SwitchImplementationParameter parameter, INamedTypeSymbol rootType, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters); + ImmutableSortedDictionary currentParameters); public abstract void RegisterDisposalType(DisposalType disposalType); - public IFunctionResolutionBuilder CreateLocalFunctionResolution(INamedTypeSymbol type, IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) + public IFunctionResolutionBuilder CreateLocalFunctionResolution(INamedTypeSymbol type, ImmutableSortedDictionary currentParameters) { - var key = $"{type.FullName()}:::{string.Join(":::", currentParameters.Select(p => p.Resolution.TypeFullName))}"; + var key = $"{type.FullName()}:::{string.Join(":::", currentParameters.Select(p => p.Value.Item2.TypeFullName))}"; if (!LocalFunctions.TryGetValue(key, out var localFunction)) { localFunction = _localFunctionResolutionBuilderFactory(this, type, currentParameters); diff --git a/Main/ResolutionBuilding/ResolutionDtos.cs b/Main/ResolutionBuilding/ResolutionDtos.cs index 7e3bc599..3fc217fb 100644 --- a/Main/ResolutionBuilding/ResolutionDtos.cs +++ b/Main/ResolutionBuilding/ResolutionDtos.cs @@ -40,13 +40,13 @@ internal record Parameter; internal record SwitchTypeParameter( ITypeSymbol Type, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentFuncParameters, + ImmutableSortedDictionary CurrentParameters, IImmutableStack ImplementationStack) : Parameter; internal record SwitchImplementationParameter( INamedTypeSymbol ImplementationType, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentParameters, + ImmutableSortedDictionary CurrentParameters, IImmutableStack ImplementationStack) { public INamedTypeSymbol ReturnType => ImplementationType; @@ -54,26 +54,26 @@ internal record SwitchImplementationParameter( internal record ForConstructorParameter( INamedTypeSymbol ImplementationType, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentFuncParameters, + ImmutableSortedDictionary CurrentParameters, IImmutableStack ImplementationStack); internal abstract record ForConstructorParameterWithInterfaceExtension( INamedTypeSymbol ImplementationType, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentFuncParameters, + ImmutableSortedDictionary CurrentFuncParameters, IImmutableStack ImplementationStack, InterfaceExtension InterfaceExtension) : ForConstructorParameter(ImplementationType, CurrentFuncParameters, ImplementationStack); internal record ForConstructorParameterWithDecoration( INamedTypeSymbol ImplementationType, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentFuncParameters, + ImmutableSortedDictionary CurrentFuncParameters, IImmutableStack ImplementationStack, DecorationInterfaceExtension Decoration) : ForConstructorParameterWithInterfaceExtension(ImplementationType, CurrentFuncParameters, ImplementationStack, Decoration); internal record ForConstructorParameterWithComposition( INamedTypeSymbol ImplementationType, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> CurrentFuncParameters, + ImmutableSortedDictionary CurrentFuncParameters, IImmutableStack ImplementationStack, CompositionInterfaceExtension Composition) : ForConstructorParameterWithInterfaceExtension(ImplementationType, CurrentFuncParameters, ImplementationStack, Composition); diff --git a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs index 814ecc3e..d5ea95c6 100644 --- a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs @@ -10,7 +10,7 @@ ScopeRootResolution AddCreateResolveFunction( INamedTypeSymbol rootType, string containerInstanceScopeReference, string transientInstanceScopeReference, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters); + ImmutableSortedDictionary currentParameters); } internal class ScopeResolutionBuilder : RangeResolutionBaseBuilder, IScopeResolutionBuilder @@ -42,7 +42,7 @@ internal ScopeResolutionBuilder( Func scopeRootCreateFunctionResolutionBuilderFactory, Func rangedFunctionGroupResolutionBuilderFactory, Func synchronicityDecisionMakerFactory, - Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) + Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) : base( name, checkTypeProperties, @@ -75,7 +75,7 @@ public override MultiSynchronicityFunctionCallResolution CreateTransientScopeIns public override TransientScopeRootResolution CreateTransientScopeRootResolution( SwitchImplementationParameter parameter, INamedTypeSymbol rootType, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) => + ImmutableSortedDictionary currentParameters) => _scopeManager .GetTransientScopeBuilder(rootType) .AddCreateResolveFunction( @@ -87,7 +87,7 @@ public override TransientScopeRootResolution CreateTransientScopeRootResolution( public override ScopeRootResolution CreateScopeRootResolution( SwitchImplementationParameter parameter, INamedTypeSymbol rootType, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) => + ImmutableSortedDictionary currentParameters) => _scopeManager .GetScopeBuilder(rootType) .AddCreateResolveFunction( @@ -109,7 +109,7 @@ public ScopeRootResolution AddCreateResolveFunction( INamedTypeSymbol rootType, string containerInstanceScopeReference, string transientInstanceScopeReference, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) + ImmutableSortedDictionary currentParameters) { var key = $"{rootType.FullName()}{(currentParameters.Any() ? $"_{string.Join(";", currentParameters)}" : "")}"; if (!_scopeRootFunctionResolutions.TryGetValue( diff --git a/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs b/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs index f3b5e824..8d88feb9 100644 --- a/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs +++ b/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs @@ -105,7 +105,7 @@ private MultiSynchronicityFunctionCallResolution CreateRangedInstanceReferenceRe var (reference, handle) = tuple; - var key = $"{referenceKey}:::{string.Join(":::", currentParameters.Select(p => p.Type.FullName()))}"; + var key = $"{referenceKey}:::{string.Join(":::", currentParameters.Select(p => p.Value.Item1.FullName()))}"; if (!_rangedInstanceReferenceResolutions.TryGetValue(key, out var interfaceDeclaration)) { var queueItem = new RangedInstanceResolutionsQueueItem( @@ -136,7 +136,7 @@ private MultiSynchronicityFunctionCallResolution CreateRangedInstanceReferenceRe _wellKnownTypes.Task1.Construct(implementationType).FullName(), _wellKnownTypes.ValueTask1.Construct(implementationType).FullName(), currentParameters.Select(t => - new ParameterResolution(_rootReferenceGenerator.Generate(t.Type), t.Type.FullName())).ToList(), + new ParameterResolution(_rootReferenceGenerator.Generate(t.Value.Item1), t.Value.Item1.FullName())).ToList(), synchronicityDecisionMaker.Decision); _rangedInstanceReferenceResolutions[key] = interfaceDeclaration; } @@ -149,7 +149,7 @@ private MultiSynchronicityFunctionCallResolution CreateRangedInstanceReferenceRe interfaceDeclaration.TypeFullName, interfaceDeclaration.Reference, owningObjectReference, - interfaceDeclaration.Parameter.Zip(currentParameters, (p, cp) => (p.Reference, cp.Resolution.Reference)) + interfaceDeclaration.Parameter.Zip(currentParameters, (p, cp) => (p.Reference, cp.Value.Item2.Reference)) .ToList()) { Await = false }, new(returnReference, @@ -157,14 +157,14 @@ private MultiSynchronicityFunctionCallResolution CreateRangedInstanceReferenceRe interfaceDeclaration.TypeFullName, interfaceDeclaration.Reference, owningObjectReference, - interfaceDeclaration.Parameter.Zip(currentParameters, (p, cp) => (p.Reference, cp.Resolution.Reference)) + interfaceDeclaration.Parameter.Zip(currentParameters, (p, cp) => (p.Reference, cp.Value.Item2.Reference)) .ToList()), new(returnReference, _wellKnownTypes.ValueTask1.Construct(implementationType).FullName(), interfaceDeclaration.TypeFullName, interfaceDeclaration.Reference, owningObjectReference, - interfaceDeclaration.Parameter.Zip(currentParameters, (p, cp) => (p.Reference, cp.Resolution.Reference)) + interfaceDeclaration.Parameter.Zip(currentParameters, (p, cp) => (p.Reference, cp.Value.Item2.Reference)) .ToList()), _synchronicityDecisionMakers[key].Decision, handle); diff --git a/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs b/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs index 1a553da3..9ce9ce33 100644 --- a/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs @@ -9,7 +9,7 @@ TransientScopeRootResolution AddCreateResolveFunction( SwitchImplementationParameter parameter, INamedTypeSymbol rootType, string containerInstanceScopeReference, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters); + ImmutableSortedDictionary currentParameters); } internal class TransientScopeResolutionBuilder : RangeResolutionBaseBuilder, ITransientScopeResolutionBuilder @@ -39,7 +39,7 @@ internal TransientScopeResolutionBuilder( Func scopeRootCreateFunctionResolutionBuilderFactory, Func rangedFunctionGroupResolutionBuilderFactory, Func synchronicityDecisionMakerFactory, - Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) + Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) : base( name, checkTypeProperties, @@ -70,7 +70,7 @@ public override MultiSynchronicityFunctionCallResolution CreateTransientScopeIns public override TransientScopeRootResolution CreateTransientScopeRootResolution( SwitchImplementationParameter parameter, INamedTypeSymbol rootType, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) => + ImmutableSortedDictionary currentParameters) => _scopeManager .GetTransientScopeBuilder(rootType) .AddCreateResolveFunction( @@ -82,7 +82,7 @@ public override TransientScopeRootResolution CreateTransientScopeRootResolution( public override ScopeRootResolution CreateScopeRootResolution( SwitchImplementationParameter parameter, INamedTypeSymbol rootType, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) => + ImmutableSortedDictionary currentParameters) => _scopeManager .GetScopeBuilder(rootType) .AddCreateResolveFunction( @@ -103,7 +103,7 @@ public TransientScopeRootResolution AddCreateResolveFunction( SwitchImplementationParameter parameter, INamedTypeSymbol rootType, string containerInstanceScopeReference, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> currentParameters) + ImmutableSortedDictionary currentParameters) { var key = $"{rootType.FullName()}{(currentParameters.Any() ? $"_{string.Join(";", currentParameters)}" : "")}"; if (!_transientScopeRootFunctionResolutions.TryGetValue( diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index ab6f5587..c0b2426f 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -125,7 +125,7 @@ internal record ConstructorResolution( internal record LazyResolution( string Reference, string TypeFullName, - MethodGroupResolution MethodGroup) : Resolvable(Reference, TypeFullName); + MultiSynchronicityFunctionCallResolution InnerCallOfLambda) : Resolvable(Reference, TypeFullName); internal record SyntaxValueTupleResolution( string Reference, @@ -164,7 +164,8 @@ internal record InterfaceFunctionDeclarationResolution( internal record FuncResolution( string Reference, string TypeFullName, - MethodGroupResolution MethodGroupResolution) : Resolvable(Reference, TypeFullName); + IReadOnlyList LambdaParameters, + MultiSynchronicityFunctionCallResolution InnerCallOfLambda) : Resolvable(Reference, TypeFullName); internal record FactoryResolution( string Reference, diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index 326a2e53..5b8fe76f 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -172,7 +172,7 @@ IScopeResolutionBuilder ScopeResolutionBuilderFactory( ILocalFunctionResolutionBuilder LocalFunctionResolutionBuilderFactory( IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, INamedTypeSymbol returnType, - IReadOnlyList<(ITypeSymbol Type, ParameterResolution Resolution)> parameters) => new LocalFunctionResolutionBuilder( + ImmutableSortedDictionary parameters) => new LocalFunctionResolutionBuilder( rangeResolutionBaseBuilder, returnType, parameters, diff --git a/Test/Func/Override.cs b/Test/Func/Override.cs new file mode 100644 index 00000000..3e190cbe --- /dev/null +++ b/Test/Func/Override.cs @@ -0,0 +1,40 @@ +using System; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Func.Override; + +internal class Dependency +{ + public int Value { get; } + + internal Dependency(int value) => Value = value; +} + +internal class Parent +{ + public Dependency Dependency { get; } + + internal Parent( + Func fac) => + Dependency = fac(1); +} + +[CreateFunction(typeof(Parent), "Create")] +internal sealed partial class Container +{ + private int DIE_Factory_int => 0; +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var parent = container.Create(); + Assert.IsType(parent); + Assert.Equal(1, parent.Dependency.Value); + } +} diff --git a/Test/Func/OverrideCombination.cs b/Test/Func/OverrideCombination.cs new file mode 100644 index 00000000..84e1c635 --- /dev/null +++ b/Test/Func/OverrideCombination.cs @@ -0,0 +1,56 @@ +using System; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Func.OverrideCombination; + +internal class Dependency +{ + public int ValueInt { get; } + public string ValueString { get; } + + internal Dependency( + int valueInt, + string valueString) + { + ValueInt = valueInt; + ValueString = valueString; + } +} + +internal class Parent0 +{ + public Dependency Dependency { get; } + + internal Parent0( + Func fac) => + Dependency = fac("1"); +} + +internal class Parent1 +{ + public Dependency Dependency { get; } + + internal Parent1( + Func fac) => + Dependency = fac(2).Dependency; +} + +[CreateFunction(typeof(Parent1), "Create")] +internal sealed partial class Container +{ +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var parent = container.Create(); + Assert.IsType(parent); + Assert.Equal(2, parent.Dependency.ValueInt); + Assert.Equal("1", parent.Dependency.ValueString); + } +} diff --git a/Test/Func/OverrideMultipleParameterOfSameType.cs b/Test/Func/OverrideMultipleParameterOfSameType.cs new file mode 100644 index 00000000..5bdd38a2 --- /dev/null +++ b/Test/Func/OverrideMultipleParameterOfSameType.cs @@ -0,0 +1,40 @@ +using System; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Func.OverrideMultipleParameterOfSameType; + +internal class Dependency +{ + public int Value { get; } + + internal Dependency(int value) => Value = value; +} + +internal class Parent +{ + public Dependency Dependency { get; } + + internal Parent( + Func fac) => + Dependency = fac(1, 2, 3); +} + +[CreateFunction(typeof(Parent), "Create")] +internal sealed partial class Container +{ + private int DIE_Factory_int => 0; +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var parent = container.Create(); + Assert.IsType(parent); + Assert.Equal(1, parent.Dependency.Value); + } +} diff --git a/Test/Func/OverrideMultipleTypes.cs b/Test/Func/OverrideMultipleTypes.cs new file mode 100644 index 00000000..94771400 --- /dev/null +++ b/Test/Func/OverrideMultipleTypes.cs @@ -0,0 +1,55 @@ +using System; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Func.OverrideMultipleTypes; + +internal class Dependency +{ + public int ValueInt { get; } + public uint ValueUint { get; } + public long ValueLong { get; } + public ulong ValueUlong { get; } + public string ValueString { get; } + + internal Dependency( + int valueInt, + uint valueUint, + long valueLong, + ulong valueUlong, + string valueString) + { + ValueInt = valueInt; + ValueUint = valueUint; + ValueLong = valueLong; + ValueUlong = valueUlong; + ValueString = valueString; + } +} + +internal class Parent +{ + public Dependency Dependency { get; } + + internal Parent( + Func fac) => + Dependency = fac(0, 1, "2", 3, 4); +} + +[CreateFunction(typeof(Parent), "Create")] +internal sealed partial class Container +{ +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var parent = container.Create(); + Assert.IsType(parent); + Assert.IsType(parent.Dependency); + } +} diff --git a/Test/Lazy/Override.cs b/Test/Lazy/Override.cs new file mode 100644 index 00000000..497cac75 --- /dev/null +++ b/Test/Lazy/Override.cs @@ -0,0 +1,41 @@ +using System; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Lazy.Override; + +internal class Dependency +{ + internal int Value { get; } + internal Dependency(int value) => Value = value; +} + +internal class Parent0 +{ + internal Dependency Dependency { get; } + internal Parent0(Lazy dependency) => Dependency = dependency.Value; +} + +internal class Parent1 +{ + internal Dependency Dependency { get; } + internal Parent1(Func fac) => Dependency = fac(23).Dependency; +} + +[CreateFunction(typeof(Parent1), "Create")] +internal sealed partial class Container +{ +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var parent = container.Create(); + Assert.IsType(parent); + Assert.Equal(23, parent.Dependency.Value); + } +} From d93369825ec54d8023a8b08d99fb8f971ac5121a Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sun, 10 Jul 2022 20:59:17 +0200 Subject: [PATCH 091/162] Fixed overriding issue --- Main/Properties/launchSettings.json | 4 ++ .../Function/FunctionResolutionBuilder.cs | 2 +- Test/Func/OverrideExistingOverride.cs | 48 +++++++++++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 Test/Func/OverrideExistingOverride.cs diff --git a/Main/Properties/launchSettings.json b/Main/Properties/launchSettings.json index 360d8b8a..32517e43 100644 --- a/Main/Properties/launchSettings.json +++ b/Main/Properties/launchSettings.json @@ -7,6 +7,10 @@ "Main_Test": { "commandName": "DebugRoslynComponent", "targetProject": "..\\Test\\Test.csproj" + }, + "Main_BFF": { + "commandName": "DebugRoslynComponent", + "targetProject": "..\\..\\BFF\\develop\\Composition.DIE\\Composition.DIE.csproj" } } } \ No newline at end of file diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs index b61a5208..59e0270d 100644 --- a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs @@ -274,7 +274,7 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup setOfProcessedTypes.Add(lambdaType); - nextCurrentParameters = nextCurrentParameters.Add(lambdaParameter.Type.FullName(), lambdaParameter); + nextCurrentParameters = nextCurrentParameters.SetItem(lambdaParameter.Type.FullName(), lambdaParameter); } var newLocalFunction = _rangeResolutionBaseBuilder.CreateLocalFunctionResolution( diff --git a/Test/Func/OverrideExistingOverride.cs b/Test/Func/OverrideExistingOverride.cs new file mode 100644 index 00000000..02c42314 --- /dev/null +++ b/Test/Func/OverrideExistingOverride.cs @@ -0,0 +1,48 @@ +using System; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Func.OverrideExistingOverride; + +internal class Dependency +{ + public int Value { get; } + + internal Dependency(int value) => Value = value; +} + +internal class Parent0 +{ + public Dependency Dependency { get; } + + internal Parent0( + Func fac) => + Dependency = fac(6); +} + +internal class Parent1 +{ + public Dependency Dependency { get; } + + internal Parent1( + Func fac) => + Dependency = fac(1).Dependency; +} + +[CreateFunction(typeof(Parent1), "Create")] +internal sealed partial class Container +{ +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var parent = container.Create(); + Assert.IsType(parent); + Assert.Equal(6, parent.Dependency.Value); + } +} From 15ffaa721b6d8be98fdc036adee1c1d1c4d8f1e9 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Mon, 11 Jul 2022 09:12:44 +0200 Subject: [PATCH 092/162] Putting whole stack into error message --- Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs index 59e0270d..7e1c1375 100644 --- a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs @@ -114,7 +114,7 @@ internal FunctionResolutionBuilder( } private string ErrorMessage(IImmutableStack stack, ITypeSymbol currentType, string message) => - $"[R:{_rangeResolutionBaseBuilder.ErrorContext.Prefix}][TS:{(stack.IsEmpty ? "empty" : stack.Peek().FullName())}][CT:{currentType.FullName()}] {message}"; + $"[R:{_rangeResolutionBaseBuilder.ErrorContext.Prefix}][TS:{(stack.IsEmpty ? "empty" : stack.Peek().FullName())}][CT:{currentType.FullName()}] {message} [S:{string.Join("<==", stack.Select(t => t.FullName()))}]"; protected (Resolvable, ITaskConsumableResolution?) SwitchType(SwitchTypeParameter parameter) { From 17c2fe1518f4f096db5555e7d79db2e7901ee4c3 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Mon, 11 Jul 2022 09:31:51 +0200 Subject: [PATCH 093/162] Fix --- Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs index 7e1c1375..694f4c56 100644 --- a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs @@ -114,7 +114,7 @@ internal FunctionResolutionBuilder( } private string ErrorMessage(IImmutableStack stack, ITypeSymbol currentType, string message) => - $"[R:{_rangeResolutionBaseBuilder.ErrorContext.Prefix}][TS:{(stack.IsEmpty ? "empty" : stack.Peek().FullName())}][CT:{currentType.FullName()}] {message} [S:{string.Join("<==", stack.Select(t => t.FullName()))}]"; + $"[R:{_rangeResolutionBaseBuilder.ErrorContext.Prefix}][TS:{(stack.IsEmpty ? "empty" : stack.Peek().FullName())}][CT:{currentType.FullName()}] {message} [S:{(stack.IsEmpty ? "empty" : string.Join("<==", stack.Select(t => t.FullName())))}]"; protected (Resolvable, ITaskConsumableResolution?) SwitchType(SwitchTypeParameter parameter) { From 073a5d79634c78a5327950ee4096436ced5f33a3 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Mon, 11 Jul 2022 10:27:48 +0200 Subject: [PATCH 094/162] Forwarding unexpected errors to IDE --- Main/DiagLogger.cs | 5 ++++- Main/Diagnostics.cs | 16 +++++++++++++--- Main/ExecuteImpl.cs | 9 +++++++-- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/Main/DiagLogger.cs b/Main/DiagLogger.cs index a31920a3..f707a687 100644 --- a/Main/DiagLogger.cs +++ b/Main/DiagLogger.cs @@ -3,6 +3,7 @@ internal interface IDiagLogger { void Error(DieException exception); + void Error(Diagnostic diagnostic); void Log(Diagnostic diagnostic); } @@ -36,11 +37,13 @@ public void Error(DieException exception) _context.ReportDiagnostic(slippedResolution.Diagnostic); break; default: - _context.ReportDiagnostic(Diagnostics.UnexpectedException(exception)); + _context.ReportDiagnostic(Diagnostics.UnexpectedDieException(exception)); break; } } + public void Error(Diagnostic diagnostic) => _context.ReportDiagnostic(diagnostic); + public void Log(Diagnostic diagnostic) { if (!_ignoreErrors || diagnostic.Severity != DiagnosticSeverity.Error) diff --git a/Main/Diagnostics.cs b/Main/Diagnostics.cs index 7bef8b40..bddc2dbd 100644 --- a/Main/Diagnostics.cs +++ b/Main/Diagnostics.cs @@ -60,10 +60,20 @@ public static Diagnostic ValidationUserDefinedElement(ISymbol userDefinedElement userDefinedElement.Locations.FirstOrDefault() ?? Location.None); } - public static Diagnostic UnexpectedException(DieException exception) + public static Diagnostic UnexpectedDieException(DieException exception) { return Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_66_00", - "Unexpected Exception", + "Unexpected Exception (DIE)", + exception.ToString(), + "Error", DiagnosticSeverity.Error, + true), + Location.None); + } + + public static Diagnostic UnexpectedException(Exception exception) + { + return Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_66_01", + "Unexpected Exception (General)", exception.ToString(), "Error", DiagnosticSeverity.Error, true), @@ -77,6 +87,6 @@ public static Diagnostic CompilationError(string message, Location location) message, "Error", DiagnosticSeverity.Error, true), - Location.None); + location); } } \ No newline at end of file diff --git a/Main/ExecuteImpl.cs b/Main/ExecuteImpl.cs index 4d935a4d..7e6b40ec 100644 --- a/Main/ExecuteImpl.cs +++ b/Main/ExecuteImpl.cs @@ -106,9 +106,14 @@ public void Execute() else _diagLogger.Error(dieException); } - catch (Exception) + catch (Exception exception) { - // ignore + if (_errorDescriptionInsteadOfBuildFailure) + { + // ignore + } + else + _diagLogger.Error(Diagnostics.UnexpectedException(exception)); } } } From ac970469821df2d4f717f8ec65ef2aa4b2fa8904 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Mon, 11 Jul 2022 13:52:32 +0200 Subject: [PATCH 095/162] Caching scoped instances in factory functions --- Main/CodeBuilding/RangeCodeBaseBuilder.cs | 6 ++++++ .../Function/FunctionResolutionBuilder.cs | 9 +++++++++ Main/ResolutionTreeItem.cs | 4 ++++ 3 files changed, 19 insertions(+) diff --git a/Main/CodeBuilding/RangeCodeBaseBuilder.cs b/Main/CodeBuilding/RangeCodeBaseBuilder.cs index 471e5446..34f4a1ff 100644 --- a/Main/CodeBuilding/RangeCodeBaseBuilder.cs +++ b/Main/CodeBuilding/RangeCodeBaseBuilder.cs @@ -231,6 +231,9 @@ private static StringBuilder GenerateFields( case DeferringResolvable { Resolvable: {} resolvable}: stringBuilder = GenerateFields(stringBuilder, resolvable); break; + case ProxyResolvable(_, _): + // proxy resolvables don't produce own code + break; case NewReferenceResolvable(var reference, var typeFullName, var resolvable): stringBuilder = GenerateFields(stringBuilder, resolvable); stringBuilder = stringBuilder @@ -367,6 +370,9 @@ private StringBuilder GenerateResolutions( case MultiTaskResolution { SelectedResolvable: {} resolvable}: stringBuilder = GenerateResolutions(stringBuilder, resolvable); break; + case ProxyResolvable(_, _): + // proxy resolvables don't produce own code + break; case NewReferenceResolvable(var reference, var typeFullName, var resolvable): stringBuilder = GenerateResolutions(stringBuilder, resolvable); stringBuilder = stringBuilder diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs index 694f4c56..ab20d05b 100644 --- a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs @@ -59,6 +59,8 @@ internal abstract partial class FunctionResolutionBuilder : IFunctionResolutionB private readonly IFunctionCycleTracker _functionCycleTracker; private readonly ICheckTypeProperties _checkTypeProperties; + private readonly Dictionary _scopedInstancesReferenceCache = new(SymbolEqualityComparer.Default); + protected readonly IReferenceGenerator RootReferenceGenerator; private readonly IUserDefinedElements _userDefinedElements; @@ -657,6 +659,10 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup _ => new ForConstructorParameter(implementationType, currentParameters, implementationStack) }; + if (scopeLevel != ScopeLevel.None + && _scopedInstancesReferenceCache.TryGetValue(implementationType, out var scopedReference)) + return (scopedReference, null); + var ret = scopeLevel switch { >= ScopeLevel.Scope when parameter is SwitchImplementationParameterWithDecoration or SwitchImplementationParameterWithDecoration => @@ -671,6 +677,9 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup CreateConstructorResolution(nextParameter) }; + if (scopeLevel != ScopeLevel.None) + _scopedInstancesReferenceCache[implementationType] = new ProxyResolvable(ret.Item1.Reference, ret.Item1.TypeFullName); + if (ret.Item1 is MultiSynchronicityFunctionCallResolution multi) _functionCycleTracker.TrackFunctionCall(_handle, multi.FunctionResolutionBuilderHandle); diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index c0b2426f..040a87c7 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -19,6 +19,10 @@ internal record NewReferenceResolvable( string TypeFullName, Resolvable Resolvable) : Resolvable(Reference, TypeFullName); +internal record ProxyResolvable( + string Reference, + string TypeFullName) : Resolvable(Reference, TypeFullName); + internal record FunctionResolution( string Reference, string TypeFullName, From ebc5ee10368ea8a124ebfbd8e279017ca622b6e0 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Mon, 11 Jul 2022 20:11:43 +0200 Subject: [PATCH 096/162] Temporary debugging --- Main/CodeBuilding/RangeCodeBaseBuilder.cs | 224 ++++-------------- Main/ExecuteImpl.cs | 18 +- Main/ResolutionTreeItem.cs | 10 +- Sample/Context.cs | 22 +- .../MultipleReferencesOfSameScopedInstance.cs | 42 ++++ 5 files changed, 128 insertions(+), 188 deletions(-) create mode 100644 Test/Scoping/MultipleReferencesOfSameScopedInstance.cs diff --git a/Main/CodeBuilding/RangeCodeBaseBuilder.cs b/Main/CodeBuilding/RangeCodeBaseBuilder.cs index 34f4a1ff..2d577bc4 100644 --- a/Main/CodeBuilding/RangeCodeBaseBuilder.cs +++ b/Main/CodeBuilding/RangeCodeBaseBuilder.cs @@ -212,152 +212,9 @@ private StringBuilder GenerateResolutionFunctionContent( StringBuilder stringBuilder, Resolvable resolution) { - stringBuilder = GenerateFields(stringBuilder, resolution); return GenerateResolutions(stringBuilder, resolution); } - private static StringBuilder GenerateFields( - StringBuilder stringBuilder, - Resolvable resolution) - { - switch (resolution) - { - case LazyResolution(var reference, var typeFullName, _): - stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); - break; - case FunctionCallResolution(var reference, _, _, _, _, _) functionCallResolution: - stringBuilder = stringBuilder.AppendLine($"{functionCallResolution.SelectedTypeFullName} {reference};"); - break; - case DeferringResolvable { Resolvable: {} resolvable}: - stringBuilder = GenerateFields(stringBuilder, resolvable); - break; - case ProxyResolvable(_, _): - // proxy resolvables don't produce own code - break; - case NewReferenceResolvable(var reference, var typeFullName, var resolvable): - stringBuilder = GenerateFields(stringBuilder, resolvable); - stringBuilder = stringBuilder - .AppendLine($"{typeFullName} {reference};"); - break; - case MultiTaskResolution { SelectedResolvable: {} resolvable}: - stringBuilder = GenerateFields(stringBuilder, resolvable); - break; - case MultiSynchronicityFunctionCallResolution { SelectedFunctionCall: {} selectedFunctionCall}: - stringBuilder = GenerateFields(stringBuilder, selectedFunctionCall); - break; - case ValueTaskFromWrappedTaskResolution(var resolvable, var reference, var fullName): - stringBuilder = GenerateFields(stringBuilder, resolvable); - stringBuilder = stringBuilder - .AppendLine($"{fullName} {reference};"); - break; - case TaskFromWrappedValueTaskResolution(var resolvable, var reference, var fullName): - stringBuilder = GenerateFields(stringBuilder, resolvable); - stringBuilder = stringBuilder - .AppendLine($"{fullName} {reference};"); - break; - case TaskFromTaskResolution(var wrappedResolvable, _, var taskReference, var taskFullName): - stringBuilder = GenerateFields(stringBuilder, wrappedResolvable); - stringBuilder = stringBuilder - .AppendLine($"{taskFullName} {taskReference};"); - break; - case TaskFromValueTaskResolution(var wrappedResolvable, _, var taskReference, var taskFullName): - stringBuilder = GenerateFields(stringBuilder, wrappedResolvable); - stringBuilder = stringBuilder - .AppendLine($"{taskFullName} {taskReference};"); - break; - case TaskFromSyncResolution(var wrappedResolvable, var taskReference, var taskFullName): - stringBuilder = GenerateFields(stringBuilder, wrappedResolvable); - stringBuilder = stringBuilder - .AppendLine($"{taskFullName} {taskReference};"); - break; - case ValueTaskFromTaskResolution(var wrappedResolvable, _, var valueTaskReference, var valueTaskFullName): - stringBuilder = GenerateFields(stringBuilder, wrappedResolvable); - stringBuilder = stringBuilder - .AppendLine($"{valueTaskFullName} {valueTaskReference};"); - break; - case ValueTaskFromValueTaskResolution(var wrappedResolvable, _, var valueTaskReference, var valueTaskFullName): - stringBuilder = GenerateFields(stringBuilder, wrappedResolvable); - stringBuilder = stringBuilder - .AppendLine($"{valueTaskFullName} {valueTaskReference};"); - break; - case ValueTaskFromSyncResolution(var wrappedResolvable, var valueTaskReference, var valueTaskFullName): - stringBuilder = GenerateFields(stringBuilder, wrappedResolvable); - stringBuilder = stringBuilder - .AppendLine($"{valueTaskFullName} {valueTaskReference};"); - break; - case TransientScopeRootResolution(var transientScopeReference, var transientScopeTypeFullName, _, var functionCallResolution): - stringBuilder = stringBuilder.AppendLine($"{transientScopeTypeFullName} {transientScopeReference};"); - stringBuilder = GenerateFields(stringBuilder, functionCallResolution); - break; - case ScopeRootResolution(var scopeReference, var scopeTypeFullName, _, _, var functionCallResolution): - stringBuilder = stringBuilder.AppendLine($"{scopeTypeFullName} {scopeReference};"); - stringBuilder = GenerateFields(stringBuilder, functionCallResolution); - break; - case NullResolution(var reference, var typeFullName): - stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); - break; - case TransientScopeAsDisposableResolution(var reference, var typeFullName): - stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); - break; - case TransientScopeAsAsyncDisposableResolution(var reference, var typeFullName): - stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); - break; - case InterfaceResolution(var reference, var typeFullName, Resolvable resolutionBase): - stringBuilder = GenerateFields(stringBuilder, resolutionBase); - stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); - break; - case OutParameterResolution(var reference, var typeFullName): - stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); - break; - case ConstructorParameterChoiceResolution(_, var parameters): - stringBuilder = parameters.Aggregate(stringBuilder, (builder, tuple) => GenerateFields(builder, tuple.Dependency)); - break; - case ConstructorResolution(var reference, var typeFullName, _, var parameters, var initializedProperties, var initialization, var parameterChoiceResolution): - if (parameterChoiceResolution is {}) - stringBuilder = GenerateFields(stringBuilder, parameterChoiceResolution); - stringBuilder = parameters.Aggregate(stringBuilder, - (builder, tuple) => GenerateFields(builder, tuple.Dependency)); - stringBuilder = initializedProperties.Aggregate(stringBuilder, - (builder, tuple) => GenerateFields(builder, tuple.Dependency)); - stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); - if (initialization is TaskBaseTypeInitializationResolution { Await: false } taskInit) - stringBuilder = stringBuilder.AppendLine($"{taskInit.TaskTypeFullName} {taskInit.TaskReference};"); - break; - case SyntaxValueTupleResolution(var reference, var typeFullName, var items): - stringBuilder = items.Aggregate(stringBuilder, GenerateFields); - stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); - break; - case FuncResolution(var reference, var typeFullName, _, _): - stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); - break; - case ParameterResolution: - break; // the parameter is the field - case MethodGroupResolution: - break; // referenced directly - case FieldResolution(var reference, var typeFullName, _): - stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); - break; - case FactoryResolution(var reference, var typeFullName, _, var parameters): - stringBuilder = parameters.Aggregate(stringBuilder, - (builder, tuple) => GenerateFields(builder, tuple.Dependency)); - stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); - break; - case CollectionResolution(var reference, var typeFullName, _, var items): - stringBuilder = items.OfType().Aggregate(stringBuilder, GenerateFields); - stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); - break; - case ErrorTreeItem(var diagnostic): - throw new CompilationDieException(diagnostic); - case var (reference, typeFullName): - stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); - break; - default: - throw new Exception("Unexpected case or not implemented."); - } - - return stringBuilder; - } - private StringBuilder GenerateResolutions( StringBuilder stringBuilder, Resolvable resolution) @@ -376,7 +233,7 @@ private StringBuilder GenerateResolutions( case NewReferenceResolvable(var reference, var typeFullName, var resolvable): stringBuilder = GenerateResolutions(stringBuilder, resolvable); stringBuilder = stringBuilder - .AppendLine($"{reference} = ({typeFullName}) {resolvable.Reference};"); + .AppendLine($"{typeFullName} {reference} = ({typeFullName}) {resolvable.Reference};"); break; case MultiSynchronicityFunctionCallResolution { SelectedFunctionCall: {} selectedFunctionCall}: stringBuilder = GenerateResolutions(stringBuilder, selectedFunctionCall); @@ -385,13 +242,13 @@ private StringBuilder GenerateResolutions( if (innerCallOfLambda.SelectedFunctionCall != innerCallOfLambda.Sync) throw new Exception("Lazy resolution has to call sync function"); // todo stringBuilder = stringBuilder - .AppendLine($"{reference} = new {typeFullName}(() => {Constants.ThisKeyword}.{innerCallOfLambda.Sync.FunctionReference}({string.Join(", ", innerCallOfLambda.Sync.Parameters.Select(p => $"{p.Name}: {p.Reference}"))}));"); + .AppendLine($"{typeFullName} {reference} = new {typeFullName}(() => {Constants.ThisKeyword}.{innerCallOfLambda.Sync.FunctionReference}({string.Join(", ", innerCallOfLambda.Sync.Parameters.Select(p => $"{p.Name}: {p.Reference}"))}));"); break; - case FuncResolution(var reference, _, var lambdaParameters, var innerCallOfLambda): + case FuncResolution(var reference, var typeFullName, var lambdaParameters, var innerCallOfLambda): if (innerCallOfLambda.SelectedFunctionCall != innerCallOfLambda.Sync) throw new Exception("Func resolution has to call sync function"); // todo stringBuilder = stringBuilder - .AppendLine($"{reference} = ({string.Join(", " ,lambdaParameters.Select(p => p.Reference))}) => {Constants.ThisKeyword}.{innerCallOfLambda.Sync.FunctionReference}({string.Join(", ", innerCallOfLambda.Sync.Parameters.Select(p => $"{p.Name}: {p.Reference}"))});"); + .AppendLine($"{typeFullName} {reference} = ({string.Join(", " ,lambdaParameters.Select(p => p.Reference))}) => {Constants.ThisKeyword}.{innerCallOfLambda.Sync.FunctionReference}({string.Join(", ", innerCallOfLambda.Sync.Parameters.Select(p => $"{p.Name}: {p.Reference}"))});"); break; case FunctionCallResolution(var reference, _, _, var functionReference, var functionOwner, var parameters) functionCallResolution: string owner2 = ""; @@ -399,25 +256,25 @@ private StringBuilder GenerateResolutions( owner2 = $"{explicitOwner2}."; if (functionCallResolution.Await) stringBuilder = stringBuilder - .AppendLine($"{reference} = ({functionCallResolution.SelectedTypeFullName})(await {owner2}{functionReference}({string.Join(", ", parameters.Select(p => $"{p.Name}: {p.Reference}"))}));"); + .AppendLine($"{functionCallResolution.SelectedTypeFullName} {reference} = ({functionCallResolution.SelectedTypeFullName})(await {owner2}{functionReference}({string.Join(", ", parameters.Select(p => $"{p.Name}: {p.Reference}"))}));"); else stringBuilder = stringBuilder - .AppendLine($"{reference} = ({functionCallResolution.SelectedTypeFullName}){owner2}{functionReference}({string.Join(", ", parameters.Select(p => $"{p.Name}: {p.Reference}"))});"); + .AppendLine($"{functionCallResolution.SelectedTypeFullName} {reference} = ({functionCallResolution.SelectedTypeFullName}){owner2}{functionReference}({string.Join(", ", parameters.Select(p => $"{p.Name}: {p.Reference}"))});"); break; case ValueTaskFromWrappedTaskResolution(var resolvable, var reference, var fullName): stringBuilder = GenerateResolutions(stringBuilder, resolvable); stringBuilder = stringBuilder - .AppendLine($"{reference} = new {fullName}({resolvable.Reference});"); + .AppendLine($"{fullName} {reference} = new {fullName}({resolvable.Reference});"); break; - case TaskFromWrappedValueTaskResolution(var resolvable, var reference, _): + case TaskFromWrappedValueTaskResolution(var resolvable, var reference, var fullName): stringBuilder = GenerateResolutions(stringBuilder, resolvable); stringBuilder = stringBuilder - .AppendLine($"{reference} = {resolvable.Reference}.AsTask();"); + .AppendLine($"{fullName} {reference} = {resolvable.Reference}.AsTask();"); break; - case TaskFromTaskResolution(var wrappedResolvable, var initialization, var taskReference, _): + case TaskFromTaskResolution(var wrappedResolvable, var initialization, var taskReference, var taskFullName): stringBuilder = GenerateResolutions(stringBuilder, wrappedResolvable); stringBuilder = stringBuilder - .AppendLine($"{taskReference} = {initialization.TaskReference}.ContinueWith(t =>") + .AppendLine($"{taskFullName} {taskReference} = {initialization.TaskReference}.ContinueWith(t =>") .AppendLine("{") .AppendLine("if (t.IsCompletedSuccessfully)") .AppendLine($"return {wrappedResolvable.Reference};") @@ -428,10 +285,10 @@ private StringBuilder GenerateResolutions( .AppendLine($"throw new {WellKnownTypes.Exception.FullName()}(\"Something unexpected.\");") .AppendLine("});"); break; - case TaskFromValueTaskResolution(var wrappedResolvable, var initialization, var taskReference, _): + case TaskFromValueTaskResolution(var wrappedResolvable, var initialization, var taskReference, var taskFullName): stringBuilder = GenerateResolutions(stringBuilder, wrappedResolvable); stringBuilder = stringBuilder - .AppendLine($"{taskReference} = {initialization.TaskReference}.AsTask().ContinueWith(t =>") + .AppendLine($"{taskFullName} {taskReference} = {initialization.TaskReference}.AsTask().ContinueWith(t =>") .AppendLine("{") .AppendLine("if (t.IsCompletedSuccessfully)") .AppendLine($"return {wrappedResolvable.Reference};") @@ -442,14 +299,14 @@ private StringBuilder GenerateResolutions( .AppendLine($"throw new {WellKnownTypes.Exception.FullName()}(\"Something unexpected.\");") .AppendLine("});"); break; - case TaskFromSyncResolution(var wrappedResolvable, var taskReference, _): + case TaskFromSyncResolution(var wrappedResolvable, var taskReference, var taskFullName): stringBuilder = GenerateResolutions(stringBuilder, wrappedResolvable); - stringBuilder = stringBuilder.AppendLine($"{taskReference} = {WellKnownTypes.Task.FullName()}.FromResult({wrappedResolvable.Reference});"); + stringBuilder = stringBuilder.AppendLine($"{taskFullName} {taskReference} = {WellKnownTypes.Task.FullName()}.FromResult({wrappedResolvable.Reference});"); break; case ValueTaskFromTaskResolution(var wrappedResolvable, var initialization, var valueTaskReference, var valueTaskFullName): stringBuilder = GenerateResolutions(stringBuilder, wrappedResolvable); stringBuilder = stringBuilder - .AppendLine($"{valueTaskReference} = new {valueTaskFullName}({initialization.TaskReference}.ContinueWith(t =>") + .AppendLine($"{valueTaskFullName} {valueTaskReference} = new {valueTaskFullName}({initialization.TaskReference}.ContinueWith(t =>") .AppendLine("{") .AppendLine("if (t.IsCompletedSuccessfully)") .AppendLine($"return {wrappedResolvable.Reference};") @@ -463,7 +320,7 @@ private StringBuilder GenerateResolutions( case ValueTaskFromValueTaskResolution(var wrappedResolvable, var initialization, var valueTaskReference, var valueTaskFullName): stringBuilder = GenerateResolutions(stringBuilder, wrappedResolvable); stringBuilder = stringBuilder - .AppendLine($"{valueTaskReference} = new {valueTaskFullName}({initialization.TaskReference}.AsTask().ContinueWith(t =>") + .AppendLine($"{valueTaskFullName} {valueTaskReference} = new {valueTaskFullName}({initialization.TaskReference}.AsTask().ContinueWith(t =>") .AppendLine("{") .AppendLine("if (t.IsCompletedSuccessfully)") .AppendLine($"return {wrappedResolvable.Reference};") @@ -474,13 +331,13 @@ private StringBuilder GenerateResolutions( .AppendLine($"throw new {WellKnownTypes.Exception.FullName()}(\"Something unexpected.\");") .AppendLine("}));"); break; - case ValueTaskFromSyncResolution(var wrappedResolvable, var valueTaskReference, _): + case ValueTaskFromSyncResolution(var wrappedResolvable, var valueTaskReference, var valueTaskFullName): stringBuilder = GenerateResolutions(stringBuilder, wrappedResolvable); - stringBuilder = stringBuilder.AppendLine($"{valueTaskReference} = {WellKnownTypes.ValueTask.FullName()}.FromResult({wrappedResolvable.Reference});"); + stringBuilder = stringBuilder.AppendLine($"{valueTaskFullName} {valueTaskReference} = {WellKnownTypes.ValueTask.FullName()}.FromResult({wrappedResolvable.Reference});"); break; case TransientScopeRootResolution(var transientScopeReference, var transientScopeTypeFullName, var containerInstanceScopeReference, var createFunctionCall): stringBuilder = stringBuilder - .AppendLine($"{transientScopeReference} = new {transientScopeTypeFullName}({containerInstanceScopeReference});"); + .AppendLine($"{transientScopeTypeFullName} {transientScopeReference} = new {transientScopeTypeFullName}({containerInstanceScopeReference});"); if (_containerResolution.DisposalType is not DisposalType.None) { var disposalType = _containerResolution.DisposalType is DisposalType.Async @@ -494,7 +351,7 @@ private StringBuilder GenerateResolutions( break; case ScopeRootResolution(var scopeReference, var scopeTypeFullName, var containerInstanceScopeReference, var transientInstanceScopeReference, var createFunctionCall): stringBuilder = stringBuilder - .AppendLine($"{scopeReference} = new {scopeTypeFullName}({containerInstanceScopeReference}, {transientInstanceScopeReference});"); + .AppendLine($"{scopeTypeFullName} {scopeReference} = new {scopeTypeFullName}({containerInstanceScopeReference}, {transientInstanceScopeReference});"); if (_containerResolution.DisposalType is DisposalType.Async) stringBuilder = stringBuilder.AppendLine($"{_rangeResolution.DisposalHandling.AsyncDisposableCollection.Reference}.Add(({WellKnownTypes.AsyncDisposable.FullName()}) {scopeReference});"); if (_containerResolution.DisposalType is DisposalType.Sync) @@ -504,27 +361,28 @@ private StringBuilder GenerateResolutions( case InterfaceResolution(var reference, var typeFullName, Resolvable resolutionBase): stringBuilder = GenerateResolutions(stringBuilder, resolutionBase); stringBuilder = stringBuilder.AppendLine( - $"{reference} = ({typeFullName}) {resolutionBase.Reference};"); + $"{typeFullName} {reference} = ({typeFullName}) {resolutionBase.Reference};"); break; case TransientScopeAsDisposableResolution(var reference, var typeFullName): stringBuilder = _containerResolution.DisposalType switch { DisposalType.Async => throw new Exception("If the container disposal has to be async, then sync disposal handles in transient scopes are not allowed."), - DisposalType.Sync => stringBuilder.AppendLine($"{reference} = ({typeFullName}) this;"), - DisposalType.None => stringBuilder.AppendLine($"{reference} = ({typeFullName}) {_containerResolution.NopDisposable.ClassName}.{_containerResolution.NopDisposable.InstanceReference};"), + DisposalType.Sync => stringBuilder.AppendLine($"{typeFullName} {reference} = ({typeFullName}) this;"), + DisposalType.None => stringBuilder.AppendLine($"{typeFullName} {reference} = ({typeFullName}) {_containerResolution.NopDisposable.ClassName}.{_containerResolution.NopDisposable.InstanceReference};"), _ => stringBuilder }; break; case TransientScopeAsAsyncDisposableResolution(var reference, var typeFullName): stringBuilder = _containerResolution.DisposalType switch { - DisposalType.Async => stringBuilder.AppendLine($"{reference} = ({typeFullName}) this;"), - DisposalType.Sync => stringBuilder.AppendLine($"{reference} = ({typeFullName}) new {_containerResolution.SyncToAsyncDisposable.ClassName}(({WellKnownTypes.Disposable.FullName()}) this);"), - DisposalType.None => stringBuilder.AppendLine($"{reference} = ({typeFullName}) {_containerResolution.NopAsyncDisposable.ClassName}.{_containerResolution.NopAsyncDisposable.InstanceReference};"), + DisposalType.Async => stringBuilder.AppendLine($"{typeFullName} {reference} = ({typeFullName}) this;"), + DisposalType.Sync => stringBuilder.AppendLine($"{typeFullName} {reference} = ({typeFullName}) new {_containerResolution.SyncToAsyncDisposable.ClassName}(({WellKnownTypes.Disposable.FullName()}) this);"), + DisposalType.None => stringBuilder.AppendLine($"{typeFullName} {reference} = ({typeFullName}) {_containerResolution.NopAsyncDisposable.ClassName}.{_containerResolution.NopAsyncDisposable.InstanceReference};"), _ => stringBuilder }; break; - case OutParameterResolution(_, _): + case OutParameterResolution(var reference, var typeFullName): + stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); break; case ConstructorParameterChoiceResolution(var functionName, var parameters): stringBuilder = parameters.Aggregate(stringBuilder, @@ -544,7 +402,7 @@ private StringBuilder GenerateResolutions( ? $" {{ {string.Join(", ", initializedProperties.Select(p => $"{p.Name} = {p.Dependency.Reference}"))} }}" : ""; stringBuilder = stringBuilder.AppendLine( - $"{reference} = new {typeFullName}({constructorParameter}){objectInitializerParameter};"); + $"{typeFullName} {reference} = new {typeFullName}({constructorParameter}){objectInitializerParameter};"); if (disposalType is not DisposalType.None) { var interfaceType = disposalType is DisposalType.Sync @@ -564,33 +422,33 @@ private StringBuilder GenerateResolutions( stringBuilder.AppendLine($"(({initInterfaceTypeName}) {reference}).{initMethodName}();"), TaskBaseTypeInitializationResolution { Await: true, TypeFullName: {} initInterfaceTypeName, MethodName: {} initMethodName} => stringBuilder.AppendLine($"await (({initInterfaceTypeName}) {reference}).{initMethodName}();"), - TaskBaseTypeInitializationResolution { Await: false, TypeFullName: {} initInterfaceTypeName, MethodName: {} initMethodName, TaskReference: {} taskReference} => - stringBuilder.AppendLine($"{taskReference} = (({initInterfaceTypeName}) {reference}).{initMethodName}();"), + TaskBaseTypeInitializationResolution { Await: false, TypeFullName: {} initInterfaceTypeName, MethodName: {} initMethodName, TaskReference: {} taskReference} taskInit => + stringBuilder.AppendLine($"{taskInit.TaskTypeFullName} {taskReference} = (({initInterfaceTypeName}) {reference}).{initMethodName}();"), _ => stringBuilder }; } break; - case SyntaxValueTupleResolution(var reference, _, var items): + case SyntaxValueTupleResolution(var reference, var typeFullName, var items): stringBuilder = items.Aggregate(stringBuilder, GenerateResolutions); - stringBuilder = stringBuilder.AppendLine($"{reference} = ({string.Join(", ", items.Select(d => d.Reference))});"); + stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference} = ({string.Join(", ", items.Select(d => d.Reference))});"); break; case ParameterResolution: break; // parameter exists already case NullResolution(var reference, var typeFullName): - stringBuilder = stringBuilder.AppendLine($"{reference} = ({typeFullName}) null;"); + stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference} = ({typeFullName}) null;"); break; - case FieldResolution(var reference, _, var fieldName): - stringBuilder = stringBuilder.AppendLine($"{reference} = this.{fieldName};"); + case FieldResolution(var reference, var typeFullName, var fieldName): + stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference} = this.{fieldName};"); break; - case FactoryResolution(var reference, _, var functionName, var parameters): + case FactoryResolution(var reference, var typeFullName, var functionName, var parameters): stringBuilder = parameters.Aggregate(stringBuilder, (builder, tuple) => GenerateResolutions(builder, tuple.Dependency ?? throw new Exception())); - stringBuilder = stringBuilder.AppendLine($"{reference} = this.{functionName}({string.Join(", ", parameters.Select(t => $"{t.Name}: {t.Dependency.Reference}"))});"); + stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference} = this.{functionName}({string.Join(", ", parameters.Select(t => $"{t.Name}: {t.Dependency.Reference}"))});"); break; - case CollectionResolution(var reference, _, var itemFullName, var items): + case CollectionResolution(var reference, var typeFullName, var itemFullName, var items): stringBuilder = items.OfType().Aggregate(stringBuilder, GenerateResolutions); stringBuilder = stringBuilder.AppendLine( - $"{reference} = new {itemFullName}[]{{{string.Join(", ", items.Select(d => $"({itemFullName}) {(d as Resolvable)?.Reference}"))}}};"); + $"{typeFullName} {reference} = new {itemFullName}[]{{{string.Join(", ", items.Select(d => $"({itemFullName}) {(d as Resolvable)?.Reference}"))}}};"); break; case ErrorTreeItem(var diagnostic): throw new CompilationDieException(diagnostic); diff --git a/Main/ExecuteImpl.cs b/Main/ExecuteImpl.cs index 7e6b40ec..283e13f1 100644 --- a/Main/ExecuteImpl.cs +++ b/Main/ExecuteImpl.cs @@ -60,6 +60,7 @@ public void Execute() .ToList(); foreach (var containerSymbol in containerClasses) { + ResolutionTreeItem.Count = 0; try { var containerInfo = _containerInfoFactory(containerSymbol); @@ -74,9 +75,24 @@ public void Execute() { containerResolutionBuilder.DoWork(); } - containerResolutionBuilder.FunctionCycleTracker.DetectCycle(); + + _context.ReportDiagnostic(Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_00_00", + "Debug", + $"Resolution tree item count: {ResolutionTreeItem.Count} ({containerSymbol.FullName()})", + "Warning", DiagnosticSeverity.Warning, + true), + Location.None)); + var containerResolution = containerResolutionBuilder.Build(); + + _context.ReportDiagnostic(Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_00_01", + "Debug", + $"Starting code building", + "Warning", DiagnosticSeverity.Warning, + true), + Location.None)); + _containerGenerator.Generate(containerInfo, containerResolution); } else diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index 040a87c7..2d02ea59 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -3,7 +3,15 @@ namespace MrMeeseeks.DIE; -internal abstract record ResolutionTreeItem; +internal abstract record ResolutionTreeItem +{ + internal static int Count { get; set; } + + internal ResolutionTreeItem() + { + Count++; + } +} internal abstract record Resolvable( string Reference, diff --git a/Sample/Context.cs b/Sample/Context.cs index ff561e15..faed7797 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -1,12 +1,28 @@ using System; using System.IO; using MrMeeseeks.DIE.Configuration.Attributes; +using MrMeeseeks.DIE.Sample; namespace MrMeeseeks.DIE.Test.ConstructorChoice.WithParameter; -[ImplementationAggregation(typeof(FileInfo))] -[ConstructorChoice(typeof(FileInfo), typeof(string))] -[CreateFunction(typeof(Func), "Create")] +internal class Dependency : IContainerInstance {} + +internal class Parent +{ + internal Parent( + Dependency dependency0, + Dependency dependency1, + Dependency dependency2, + Dependency dependency3, + Dependency dependency4, + Dependency dependency5, + Dependency dependency6, + Dependency dependency7, + Dependency dependency8, + Dependency dependency9){} +} + +[CreateFunction(typeof(Parent), "Create")] internal sealed partial class Container { diff --git a/Test/Scoping/MultipleReferencesOfSameScopedInstance.cs b/Test/Scoping/MultipleReferencesOfSameScopedInstance.cs new file mode 100644 index 00000000..0af8b4e3 --- /dev/null +++ b/Test/Scoping/MultipleReferencesOfSameScopedInstance.cs @@ -0,0 +1,42 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Scoping.MultipleReferencesOfSameScopedInstance; + +internal class Dependency : IContainerInstance {} + +internal class Parent +{ + internal Parent( + Dependency dependency0, + Dependency dependency1, + Dependency dependency2, + Dependency dependency3, + Dependency dependency4, + Dependency dependency5, + Dependency dependency6, + Dependency dependency7, + Dependency dependency8, + Dependency dependency9) + { + + } +} + +[CreateFunction(typeof(Parent), "Create")] +internal sealed partial class Container +{ + +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var instance = container.Create(); + Assert.IsType(instance); + } +} \ No newline at end of file From eb318307ef8ed327fe0d88de18c85f0519693253 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Mon, 11 Jul 2022 20:45:21 +0200 Subject: [PATCH 097/162] Further debugging --- Main/CodeBuilding/ContainerGenerator.cs | 7 +++++++ Main/ExecuteImpl.cs | 23 +++++++++++++++++++-- Main/ResolutionTreeItem.cs | 27 +++++++++++++++++++------ 3 files changed, 49 insertions(+), 8 deletions(-) diff --git a/Main/CodeBuilding/ContainerGenerator.cs b/Main/CodeBuilding/ContainerGenerator.cs index 05f3ac53..91a5aa3a 100644 --- a/Main/CodeBuilding/ContainerGenerator.cs +++ b/Main/CodeBuilding/ContainerGenerator.cs @@ -39,6 +39,13 @@ public void Generate(IContainerInfo containerInfo, ContainerResolution container containerResolution.Scopes.Select(s => _scopeCodeBuilderFactory(containerInfo, s, containerResolution.TransientScopeInterface, containerResolution)).ToList()); var generatedContainer = containerCodeBuilder.Build(new StringBuilder()); + + _context.ReportDiagnostic(Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_00_01", + "Debug", + "Starting file creation", + "Warning", DiagnosticSeverity.Warning, + true), + Location.None)); var containerSource = CSharpSyntaxTree .ParseText(SourceText.From(generatedContainer.ToString(), Encoding.UTF8)) diff --git a/Main/ExecuteImpl.cs b/Main/ExecuteImpl.cs index 283e13f1..dd21eb67 100644 --- a/Main/ExecuteImpl.cs +++ b/Main/ExecuteImpl.cs @@ -60,7 +60,9 @@ public void Execute() .ToList(); foreach (var containerSymbol in containerClasses) { - ResolutionTreeItem.Count = 0; + ResolutionTreeItem.ResolutionTreeItemCount = 0; + Resolvable.ResolvableCount = 0; + Resolvable.TypeToCountMap.Clear(); try { var containerInfo = _containerInfoFactory(containerSymbol); @@ -79,11 +81,28 @@ public void Execute() _context.ReportDiagnostic(Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_00_00", "Debug", - $"Resolution tree item count: {ResolutionTreeItem.Count} ({containerSymbol.FullName()})", + $"Resolution tree item count: {ResolutionTreeItem.ResolutionTreeItemCount} ({containerSymbol.FullName()})", "Warning", DiagnosticSeverity.Warning, true), Location.None)); + _context.ReportDiagnostic(Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_00_00", + "Debug", + $"Resolution tree (Resolvable) item count: {Resolvable.ResolvableCount} ({containerSymbol.FullName()})", + "Warning", DiagnosticSeverity.Warning, + true), + Location.None)); + + foreach (var keyValuePair in Resolvable.TypeToCountMap.OrderByDescending(kvp => kvp.Value)) + { + _context.ReportDiagnostic(Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_00_00", + "Debug", + $"Count/Type: {keyValuePair.Value}/{keyValuePair.Key}", + "Warning", DiagnosticSeverity.Warning, + true), + Location.None)); + } + var containerResolution = containerResolutionBuilder.Build(); _context.ReportDiagnostic(Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_00_01", diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index 2d02ea59..7f67f4a5 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -5,17 +5,32 @@ namespace MrMeeseeks.DIE; internal abstract record ResolutionTreeItem { - internal static int Count { get; set; } + internal static int ResolutionTreeItemCount { get; set; } internal ResolutionTreeItem() { - Count++; + ResolutionTreeItemCount++; + } +} + +internal abstract record Resolvable : ResolutionTreeItem +{ + public string Reference { get; } + public string TypeFullName { get; } + internal static int ResolvableCount { get; set; } + internal static Dictionary TypeToCountMap { get; } = new(); + + internal Resolvable( + string Reference, + string TypeFullName) + { + this.Reference = Reference; + this.TypeFullName = TypeFullName; + ResolvableCount++; + if (!string.IsNullOrWhiteSpace(TypeFullName)) + TypeToCountMap[TypeFullName] = TypeToCountMap.TryGetValue(TypeFullName, out var count) ? count + 1 : 1; } } - -internal abstract record Resolvable( - string Reference, - string TypeFullName) : ResolutionTreeItem; internal record DeferringResolvable() : Resolvable("", "") { From 3344df58382143d349c9c25a9fff898f5f4b628a Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Mon, 11 Jul 2022 22:02:03 +0200 Subject: [PATCH 098/162] Logging Functions --- Main/ExecuteImpl.cs | 12 ++++++++++++ .../ContainerCreateFunctionResolutionBuilder.cs | 1 + .../Function/FunctionResolutionBuilder.cs | 6 ++++++ .../Function/LocalFunctionResolutionBuilder.cs | 1 + .../Function/RangedFunctionResolutionBuilder.cs | 1 + .../ScopeRootCreateFunctionResolutionBuilder.cs | 2 ++ 6 files changed, 23 insertions(+) diff --git a/Main/ExecuteImpl.cs b/Main/ExecuteImpl.cs index dd21eb67..c92e04d7 100644 --- a/Main/ExecuteImpl.cs +++ b/Main/ExecuteImpl.cs @@ -1,6 +1,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using MrMeeseeks.DIE.CodeBuilding; using MrMeeseeks.DIE.ResolutionBuilding; +using MrMeeseeks.DIE.ResolutionBuilding.Function; using MrMeeseeks.DIE.Validation.Range; namespace MrMeeseeks.DIE; @@ -63,6 +64,7 @@ public void Execute() ResolutionTreeItem.ResolutionTreeItemCount = 0; Resolvable.ResolvableCount = 0; Resolvable.TypeToCountMap.Clear(); + FunctionResolutionBuilder.FunctionLog.Clear(); try { var containerInfo = _containerInfoFactory(containerSymbol); @@ -102,6 +104,16 @@ public void Execute() true), Location.None)); } + + foreach (var s in FunctionResolutionBuilder.FunctionLog.OrderBy(s => s)) + { + _context.ReportDiagnostic(Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_00_00", + "Debug", + $"Function: {s}", + "Warning", DiagnosticSeverity.Warning, + true), + Location.None)); + } var containerResolution = containerResolutionBuilder.Build(); diff --git a/Main/ResolutionBuilding/Function/ContainerCreateFunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/ContainerCreateFunctionResolutionBuilder.cs index 676b2f35..fffbced4 100644 --- a/Main/ResolutionBuilding/Function/ContainerCreateFunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/ContainerCreateFunctionResolutionBuilder.cs @@ -35,6 +35,7 @@ public ContainerCreateFunctionResolutionBuilder( } protected override string Name { get; } + protected override string TypeForLog => "ContainerCreate"; protected override Resolvable CreateResolvable() => SwitchType(new SwitchTypeParameter( _returnType, diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs index ab20d05b..e3f4445e 100644 --- a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs @@ -113,7 +113,13 @@ internal FunctionResolutionBuilder( .ToList(); Resolvable = new(CreateResolvable); + + FunctionLog.Add($"{_rangeResolutionBaseBuilder.ErrorContext.Prefix}/{OriginalReturnType.FullName()}/{TypeForLog}/{string.Join(",", Parameters.Select(p => p.TypeFullName))}"); } + + protected abstract string TypeForLog { get; } + + internal static List FunctionLog = new(); private string ErrorMessage(IImmutableStack stack, ITypeSymbol currentType, string message) => $"[R:{_rangeResolutionBaseBuilder.ErrorContext.Prefix}][TS:{(stack.IsEmpty ? "empty" : stack.Peek().FullName())}][CT:{currentType.FullName()}] {message} [S:{(stack.IsEmpty ? "empty" : string.Join("<==", stack.Select(t => t.FullName())))}]"; diff --git a/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs index 7811579f..f4d14665 100644 --- a/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs @@ -36,6 +36,7 @@ public LocalFunctionResolutionBuilder( } protected override string Name { get; } + protected override string TypeForLog => "LocalFunction"; protected override Resolvable CreateResolvable() => SwitchType(new SwitchTypeParameter( _returnType, diff --git a/Main/ResolutionBuilding/Function/RangedFunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/RangedFunctionResolutionBuilder.cs index 42e38452..03bf242b 100644 --- a/Main/ResolutionBuilding/Function/RangedFunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/RangedFunctionResolutionBuilder.cs @@ -37,6 +37,7 @@ public RangedFunctionResolutionBuilder( } protected override string Name { get; } + protected override string TypeForLog => "ScopedInstance"; protected override Resolvable CreateResolvable() => CreateConstructorResolution( _forConstructorParameter with diff --git a/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs index 6434f19c..f517c81a 100644 --- a/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs @@ -35,6 +35,8 @@ public ScopeRootCreateFunctionResolutionBuilder( } protected override string Name { get; } + + protected override string TypeForLog => "ScopeRoot"; protected override Resolvable CreateResolvable() => SwitchImplementation( _parameter with From 11c1c2e1b41a0e78f2f917ab70e39151d7f5c7b7 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Wed, 13 Jul 2022 10:23:24 +0200 Subject: [PATCH 099/162] Reusing CreateFunction which have greatest common set of overrides --- Main/Main.csproj | 1 + .../Function/FunctionResolutionBuilder.cs | 16 ++++-- .../ScopeResolutionBuilder.cs | 18 ++++++- Sample/Context.cs | 38 ++++++++------ Test/Func/OverrideScoped.cs | 50 +++++++++++++++++++ 5 files changed, 102 insertions(+), 21 deletions(-) create mode 100644 Test/Func/OverrideScoped.cs diff --git a/Main/Main.csproj b/Main/Main.csproj index 8ee7d231..bbfcc2cf 100644 --- a/Main/Main.csproj +++ b/Main/Main.csproj @@ -35,6 +35,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs index e3f4445e..35093b8f 100644 --- a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs @@ -43,6 +43,7 @@ internal interface IFunctionResolutionBuilder : IResolutionBuilder CurrentParameters { get; } MultiSynchronicityFunctionCallResolution BuildFunctionCall( ImmutableSortedDictionary currentParameters, @@ -73,7 +74,7 @@ internal abstract partial class FunctionResolutionBuilder : IFunctionResolutionB public Lazy SynchronicityDecision => _synchronicityDecisionMaker.Decision; protected Lazy Resolvable { get; } - protected IReadOnlyList<(ITypeSymbol, ParameterResolution)> CurrentParameters { get; } + public IReadOnlyList<(ITypeSymbol, ParameterResolution)> CurrentParameters { get; } protected IReadOnlyList Parameters { get; } @@ -962,22 +963,29 @@ public MultiSynchronicityFunctionCallResolution BuildFunctionCall( OriginalReturnType.FullName(), Name, ownerReference, - Parameters.Zip(currentParameters, (p, cp) => (p.Reference, cp.Value.Item2.Reference)).ToList()) + CreateParameter()) { Await = false }, new(returnReference, _wellKnownTypes.Task1.Construct(OriginalReturnType).FullName(), OriginalReturnType.FullName(), Name, ownerReference, - Parameters.Zip(currentParameters, (p, cp) => (p.Reference, cp.Value.Item2.Reference)).ToList()), + CreateParameter()), new(returnReference, _wellKnownTypes.ValueTask1.Construct(OriginalReturnType).FullName(), OriginalReturnType.FullName(), Name, ownerReference, - Parameters.Zip(currentParameters, (p, cp) => (p.Reference, cp.Value.Item2.Reference)).ToList()), + CreateParameter()), SynchronicityDecision, _handle); + + IReadOnlyList<(string Name, string Reference)> CreateParameter() => + Parameters.Join( + currentParameters, + p => p.TypeFullName, + p => p.Value.Item2.TypeFullName, + (p, cp) => (p.Reference, cp.Value.Item2.Reference)).ToList(); } public MethodGroupResolution BuildMethodGroup() => new (Name, TypeFullName, null); diff --git a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs index d5ea95c6..6ba96718 100644 --- a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs @@ -116,8 +116,22 @@ public ScopeRootResolution AddCreateResolveFunction( key, out var function)) { - function = _scopeRootCreateFunctionResolutionBuilderFactory(this, parameter); - _scopeRootFunctionResolutions[key] = function; + if (_scopeRootFunctionResolutions + .Values + .Where(f => + SymbolEqualityComparer.Default.Equals(f.OriginalReturnType, rootType) + && f.CurrentParameters.All(cp => currentParameters.Any(p => + SymbolEqualityComparer.IncludeNullability.Equals(cp.Item1, p.Value.Item1)))) + .OrderByDescending(f => f.CurrentParameters.Count) + .FirstOrDefault() is { } greatestCommonParameterSetFunction) + { + function = greatestCommonParameterSetFunction; + } + else + { + function = _scopeRootCreateFunctionResolutionBuilderFactory(this, parameter); + _scopeRootFunctionResolutions[key] = function; + } } var scopeRootReference = RootReferenceGenerator.Generate("scopeRoot"); diff --git a/Sample/Context.cs b/Sample/Context.cs index faed7797..d1fc66b6 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -1,29 +1,37 @@ using System; -using System.IO; using MrMeeseeks.DIE.Configuration.Attributes; using MrMeeseeks.DIE.Sample; -namespace MrMeeseeks.DIE.Test.ConstructorChoice.WithParameter; +namespace MrMeeseeks.DIE.Test.Func.OverrideScoped; -internal class Dependency : IContainerInstance {} +internal class DependencyInner +{ + internal DependencyInner( + Lazy lazyParent, + string asdf) + { + + } +} + +internal class Dependency +{ + public int Value { get; } -internal class Parent + internal Dependency(int value, Func fac) => Value = value; +} + +internal class Parent : IScopeRoot { + public Dependency Dependency { get; } + internal Parent( - Dependency dependency0, - Dependency dependency1, - Dependency dependency2, - Dependency dependency3, - Dependency dependency4, - Dependency dependency5, - Dependency dependency6, - Dependency dependency7, - Dependency dependency8, - Dependency dependency9){} + Func fac) => + Dependency = fac(1); } [CreateFunction(typeof(Parent), "Create")] internal sealed partial class Container { - + private int DIE_Factory_int => 0; } \ No newline at end of file diff --git a/Test/Func/OverrideScoped.cs b/Test/Func/OverrideScoped.cs new file mode 100644 index 00000000..e641afd1 --- /dev/null +++ b/Test/Func/OverrideScoped.cs @@ -0,0 +1,50 @@ +using System; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Func.OverrideScoped; + +internal class DependencyInner +{ + internal DependencyInner( + Lazy lazyParent, + string asdf) + { + + } +} + +internal class Dependency +{ + public int Value { get; } + + internal Dependency(int value, Func fac) => Value = value; +} + +internal class Parent : IScopeRoot +{ + public Dependency Dependency { get; } + + internal Parent( + Func fac) => + Dependency = fac(1); +} + +[CreateFunction(typeof(Parent), "Create")] +internal sealed partial class Container +{ + private int DIE_Factory_int => 0; +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var parent = container.Create(); + Assert.IsType(parent); + Assert.Equal(1, parent.Dependency.Value); + } +} From f2669e97b9f86dc2085224f46cadab6a362c529f Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Wed, 13 Jul 2022 10:30:28 +0200 Subject: [PATCH 100/162] Reusing local functions with greatest common set of overrides as well --- .../RangeResolutionBaseBuilder.cs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs index 0f098f08..a6c2ba21 100644 --- a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs +++ b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs @@ -115,8 +115,22 @@ public IFunctionResolutionBuilder CreateLocalFunctionResolution(INamedTypeSymbol var key = $"{type.FullName()}:::{string.Join(":::", currentParameters.Select(p => p.Value.Item2.TypeFullName))}"; if (!LocalFunctions.TryGetValue(key, out var localFunction)) { - localFunction = _localFunctionResolutionBuilderFactory(this, type, currentParameters); - LocalFunctions[key] = localFunction; + if (LocalFunctions + .Values + .Where(f => + SymbolEqualityComparer.Default.Equals(f.OriginalReturnType, type) + && f.CurrentParameters.All(cp => currentParameters.Any(p => + SymbolEqualityComparer.IncludeNullability.Equals(cp.Item1, p.Value.Item1)))) + .OrderByDescending(f => f.CurrentParameters.Count) + .FirstOrDefault() is { } greatestCommonParameterSetFunction) + { + localFunction = greatestCommonParameterSetFunction; + } + else + { + localFunction = _localFunctionResolutionBuilderFactory(this, type, currentParameters); + LocalFunctions[key] = localFunction; + } } return localFunction; From 78bc5bc11e96e56e7e4abe03aa7417226f8d2c10 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Wed, 13 Jul 2022 11:42:33 +0200 Subject: [PATCH 101/162] Try to fix nullability with overrides --- Main/CodeBuilding/ContainerGenerator.cs | 7 ---- Main/ExecuteImpl.cs | 42 ++++--------------- .../Function/FunctionResolutionBuilder.cs | 2 +- Main/ResolutionTreeItem.cs | 13 +----- .../NamedTypeSymbolEqualityComparer.cs | 18 -------- 5 files changed, 9 insertions(+), 73 deletions(-) delete mode 100644 Main/Utility/NamedTypeSymbolEqualityComparer.cs diff --git a/Main/CodeBuilding/ContainerGenerator.cs b/Main/CodeBuilding/ContainerGenerator.cs index 91a5aa3a..05f3ac53 100644 --- a/Main/CodeBuilding/ContainerGenerator.cs +++ b/Main/CodeBuilding/ContainerGenerator.cs @@ -39,13 +39,6 @@ public void Generate(IContainerInfo containerInfo, ContainerResolution container containerResolution.Scopes.Select(s => _scopeCodeBuilderFactory(containerInfo, s, containerResolution.TransientScopeInterface, containerResolution)).ToList()); var generatedContainer = containerCodeBuilder.Build(new StringBuilder()); - - _context.ReportDiagnostic(Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_00_01", - "Debug", - "Starting file creation", - "Warning", DiagnosticSeverity.Warning, - true), - Location.None)); var containerSource = CSharpSyntaxTree .ParseText(SourceText.From(generatedContainer.ToString(), Encoding.UTF8)) diff --git a/Main/ExecuteImpl.cs b/Main/ExecuteImpl.cs index c92e04d7..7c56af21 100644 --- a/Main/ExecuteImpl.cs +++ b/Main/ExecuteImpl.cs @@ -61,9 +61,7 @@ public void Execute() .ToList(); foreach (var containerSymbol in containerClasses) { - ResolutionTreeItem.ResolutionTreeItemCount = 0; Resolvable.ResolvableCount = 0; - Resolvable.TypeToCountMap.Clear(); FunctionResolutionBuilder.FunctionLog.Clear(); try { @@ -81,13 +79,6 @@ public void Execute() } containerResolutionBuilder.FunctionCycleTracker.DetectCycle(); - _context.ReportDiagnostic(Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_00_00", - "Debug", - $"Resolution tree item count: {ResolutionTreeItem.ResolutionTreeItemCount} ({containerSymbol.FullName()})", - "Warning", DiagnosticSeverity.Warning, - true), - Location.None)); - _context.ReportDiagnostic(Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_00_00", "Debug", $"Resolution tree (Resolvable) item count: {Resolvable.ResolvableCount} ({containerSymbol.FullName()})", @@ -95,35 +86,16 @@ public void Execute() true), Location.None)); - foreach (var keyValuePair in Resolvable.TypeToCountMap.OrderByDescending(kvp => kvp.Value)) - { - _context.ReportDiagnostic(Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_00_00", - "Debug", - $"Count/Type: {keyValuePair.Value}/{keyValuePair.Key}", - "Warning", DiagnosticSeverity.Warning, - true), - Location.None)); - } - - foreach (var s in FunctionResolutionBuilder.FunctionLog.OrderBy(s => s)) - { - _context.ReportDiagnostic(Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_00_00", - "Debug", - $"Function: {s}", - "Warning", DiagnosticSeverity.Warning, - true), - Location.None)); - } + _context.ReportDiagnostic(Diagnostic.Create(new DiagnosticDescriptor( + $"{Constants.DieAbbreviation}_00_00", + "Debug", + $"Function Count: {FunctionResolutionBuilder.FunctionLog.Count}", + "Warning", DiagnosticSeverity.Warning, + true), + Location.None)); var containerResolution = containerResolutionBuilder.Build(); - _context.ReportDiagnostic(Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_00_01", - "Debug", - $"Starting code building", - "Warning", DiagnosticSeverity.Warning, - true), - Location.None)); - _containerGenerator.Generate(containerInfo, containerResolution); } else diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs index 35093b8f..cdb472c9 100644 --- a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs @@ -128,7 +128,7 @@ private string ErrorMessage(IImmutableStack stack, ITypeSymbol protected (Resolvable, ITaskConsumableResolution?) SwitchType(SwitchTypeParameter parameter) { var (type, currentFuncParameters, implementationStack) = parameter; - if (currentFuncParameters.FirstOrDefault(t => SymbolEqualityComparer.Default.Equals( + if (currentFuncParameters.FirstOrDefault(t => SymbolEqualityComparer.IncludeNullability.Equals( t.Value.Item1.OriginalDefinition, type.OriginalDefinition)) is { Value.Item1: not null, Value.Item2: not null } funcParameter) return (funcParameter.Value.Item2, null); diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index 7f67f4a5..bde4de46 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -3,22 +3,13 @@ namespace MrMeeseeks.DIE; -internal abstract record ResolutionTreeItem -{ - internal static int ResolutionTreeItemCount { get; set; } - - internal ResolutionTreeItem() - { - ResolutionTreeItemCount++; - } -} +internal abstract record ResolutionTreeItem { } internal abstract record Resolvable : ResolutionTreeItem { public string Reference { get; } public string TypeFullName { get; } internal static int ResolvableCount { get; set; } - internal static Dictionary TypeToCountMap { get; } = new(); internal Resolvable( string Reference, @@ -27,8 +18,6 @@ internal Resolvable( this.Reference = Reference; this.TypeFullName = TypeFullName; ResolvableCount++; - if (!string.IsNullOrWhiteSpace(TypeFullName)) - TypeToCountMap[TypeFullName] = TypeToCountMap.TryGetValue(TypeFullName, out var count) ? count + 1 : 1; } } diff --git a/Main/Utility/NamedTypeSymbolEqualityComparer.cs b/Main/Utility/NamedTypeSymbolEqualityComparer.cs deleted file mode 100644 index 871e2106..00000000 --- a/Main/Utility/NamedTypeSymbolEqualityComparer.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace MrMeeseeks.DIE.Utility; - -public class NamedTypeSymbolEqualityComparer : IEqualityComparer -{ - private readonly IEqualityComparer _innerEqualityComparer; - - public static readonly NamedTypeSymbolEqualityComparer Default = new (SymbolEqualityComparer.Default); - public static readonly NamedTypeSymbolEqualityComparer IncludeNullability = new (SymbolEqualityComparer.IncludeNullability); - - private NamedTypeSymbolEqualityComparer(IEqualityComparer innerEqualityComparer) => - _innerEqualityComparer = innerEqualityComparer; - - public bool Equals(INamedTypeSymbol? x, INamedTypeSymbol? y) => - _innerEqualityComparer.Equals(x, y); - - public int GetHashCode(INamedTypeSymbol? obj) => - _innerEqualityComparer.GetHashCode(obj); -} \ No newline at end of file From f1b351c3bb2372d44b96f2feaa6b89bfbc400bca Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Wed, 13 Jul 2022 14:56:09 +0200 Subject: [PATCH 102/162] Unifying function reduction to ranged functions as well --- .../RangedFunctionGroupResolutionBuilder.cs | 34 ++++++++-------- .../RangeResolutionBaseBuilder.cs | 32 ++++----------- .../ScopeResolutionBuilder.cs | 28 +++---------- Main/Utility/FunctionResolutionUtility.cs | 39 +++++++++++++++++++ 4 files changed, 70 insertions(+), 63 deletions(-) create mode 100644 Main/Utility/FunctionResolutionUtility.cs diff --git a/Main/ResolutionBuilding/Function/RangedFunctionGroupResolutionBuilder.cs b/Main/ResolutionBuilding/Function/RangedFunctionGroupResolutionBuilder.cs index c852f605..64e2693e 100644 --- a/Main/ResolutionBuilding/Function/RangedFunctionGroupResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/RangedFunctionGroupResolutionBuilder.cs @@ -1,3 +1,5 @@ +using MrMeeseeks.DIE.Utility; + namespace MrMeeseeks.DIE.ResolutionBuilding.Function; internal interface IRangedFunctionGroupResolutionBuilder @@ -54,22 +56,22 @@ internal RangedFunctionGroupResolutionBuilder( public IRangedFunctionResolutionBuilder GetInstanceFunction( ForConstructorParameter parameter, - Lazy synchronicityDecisionMaker) - { - var listedParameterTypes = string.Join(",", parameter.CurrentParameters.Select(p => p.Value.Item2.TypeFullName)); - if (!_overloads.TryGetValue(listedParameterTypes, out var function)) - { - function = _rangedFunctionResolutionBuilderFactory( - _rangeResolutionBaseBuilder, - _reference, - parameter, - synchronicityDecisionMaker.Value, - this); - _overloads[listedParameterTypes] = function; - _functionQueue.Add(function); - } - return function; - } + Lazy synchronicityDecisionMaker) => + FunctionResolutionUtility.GetOrCreateFunction( + _overloads, + parameter.ImplementationType, + parameter.CurrentParameters, + () => + { + var newFunction = _rangedFunctionResolutionBuilderFactory( + _rangeResolutionBaseBuilder, + _reference, + parameter, + synchronicityDecisionMaker.Value, + this); + _functionQueue.Add(newFunction); + return newFunction; + }); public bool HasWorkToDo => _functionQueue.Any(f => f.HasWorkToDo); diff --git a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs index a6c2ba21..0d0ceb9e 100644 --- a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs +++ b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs @@ -1,5 +1,6 @@ using MrMeeseeks.DIE.Configuration; using MrMeeseeks.DIE.ResolutionBuilding.Function; +using MrMeeseeks.DIE.Utility; namespace MrMeeseeks.DIE.ResolutionBuilding; @@ -110,31 +111,12 @@ public abstract ScopeRootResolution CreateScopeRootResolution( ImmutableSortedDictionary currentParameters); public abstract void RegisterDisposalType(DisposalType disposalType); - public IFunctionResolutionBuilder CreateLocalFunctionResolution(INamedTypeSymbol type, ImmutableSortedDictionary currentParameters) - { - var key = $"{type.FullName()}:::{string.Join(":::", currentParameters.Select(p => p.Value.Item2.TypeFullName))}"; - if (!LocalFunctions.TryGetValue(key, out var localFunction)) - { - if (LocalFunctions - .Values - .Where(f => - SymbolEqualityComparer.Default.Equals(f.OriginalReturnType, type) - && f.CurrentParameters.All(cp => currentParameters.Any(p => - SymbolEqualityComparer.IncludeNullability.Equals(cp.Item1, p.Value.Item1)))) - .OrderByDescending(f => f.CurrentParameters.Count) - .FirstOrDefault() is { } greatestCommonParameterSetFunction) - { - localFunction = greatestCommonParameterSetFunction; - } - else - { - localFunction = _localFunctionResolutionBuilderFactory(this, type, currentParameters); - LocalFunctions[key] = localFunction; - } - } - - return localFunction; - } + public IFunctionResolutionBuilder CreateLocalFunctionResolution(INamedTypeSymbol type, ImmutableSortedDictionary currentParameters) => + FunctionResolutionUtility.GetOrCreateFunction( + LocalFunctions, + type, + currentParameters, + () => _localFunctionResolutionBuilderFactory(this, type, currentParameters)); protected MultiSynchronicityFunctionCallResolution CreateRangedInstanceReferenceResolution( ForConstructorParameter parameter, diff --git a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs index 6ba96718..328dcfe2 100644 --- a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs @@ -1,5 +1,6 @@ using MrMeeseeks.DIE.Configuration; using MrMeeseeks.DIE.ResolutionBuilding.Function; +using MrMeeseeks.DIE.Utility; namespace MrMeeseeks.DIE.ResolutionBuilding; @@ -111,28 +112,11 @@ public ScopeRootResolution AddCreateResolveFunction( string transientInstanceScopeReference, ImmutableSortedDictionary currentParameters) { - var key = $"{rootType.FullName()}{(currentParameters.Any() ? $"_{string.Join(";", currentParameters)}" : "")}"; - if (!_scopeRootFunctionResolutions.TryGetValue( - key, - out var function)) - { - if (_scopeRootFunctionResolutions - .Values - .Where(f => - SymbolEqualityComparer.Default.Equals(f.OriginalReturnType, rootType) - && f.CurrentParameters.All(cp => currentParameters.Any(p => - SymbolEqualityComparer.IncludeNullability.Equals(cp.Item1, p.Value.Item1)))) - .OrderByDescending(f => f.CurrentParameters.Count) - .FirstOrDefault() is { } greatestCommonParameterSetFunction) - { - function = greatestCommonParameterSetFunction; - } - else - { - function = _scopeRootCreateFunctionResolutionBuilderFactory(this, parameter); - _scopeRootFunctionResolutions[key] = function; - } - } + var function = FunctionResolutionUtility.GetOrCreateFunction( + _scopeRootFunctionResolutions, + rootType, + currentParameters, + () => _scopeRootCreateFunctionResolutionBuilderFactory(this, parameter)); var scopeRootReference = RootReferenceGenerator.Generate("scopeRoot"); diff --git a/Main/Utility/FunctionResolutionUtility.cs b/Main/Utility/FunctionResolutionUtility.cs new file mode 100644 index 00000000..7e6a5d3f --- /dev/null +++ b/Main/Utility/FunctionResolutionUtility.cs @@ -0,0 +1,39 @@ +using MrMeeseeks.DIE.ResolutionBuilding.Function; + +namespace MrMeeseeks.DIE.Utility; + +internal static class FunctionResolutionUtility +{ + internal static T GetOrCreateFunction( + IDictionary functionMap, + INamedTypeSymbol type, + ImmutableSortedDictionary currentParameters, + Func functionFactory) + where T : IFunctionResolutionBuilder + { + var key = $"{type.FullName()}:::{string.Join(":::", currentParameters.Select(p => p.Value.Item2.TypeFullName))}"; + if (!functionMap.TryGetValue( + key, + out var function)) + { + if (functionMap + .Values + .Where(f => + SymbolEqualityComparer.Default.Equals(f.OriginalReturnType, type) + && f.CurrentParameters.All(cp => currentParameters.Any(p => + SymbolEqualityComparer.IncludeNullability.Equals(cp.Item1, p.Value.Item1)))) + .OrderByDescending(f => f.CurrentParameters.Count) + .FirstOrDefault() is { } greatestCommonParameterSetFunction) + { + function = greatestCommonParameterSetFunction; + } + else + { + function = functionFactory(); + functionMap[key] = function; + } + } + + return function; + } +} \ No newline at end of file From 779f8065105fed3b9f2ca9228f4f483057b25dc9 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Wed, 13 Jul 2022 15:09:56 +0200 Subject: [PATCH 103/162] Removed logging for debugging session --- Main/ExecuteImpl.cs | 18 ------------------ ...ContainerCreateFunctionResolutionBuilder.cs | 1 - .../Function/FunctionResolutionBuilder.cs | 6 ------ .../Function/LocalFunctionResolutionBuilder.cs | 1 - .../RangedFunctionResolutionBuilder.cs | 1 - ...ScopeRootCreateFunctionResolutionBuilder.cs | 2 -- Main/ResolutionTreeItem.cs | 18 ++---------------- 7 files changed, 2 insertions(+), 45 deletions(-) diff --git a/Main/ExecuteImpl.cs b/Main/ExecuteImpl.cs index 7c56af21..aeef5bf3 100644 --- a/Main/ExecuteImpl.cs +++ b/Main/ExecuteImpl.cs @@ -1,7 +1,6 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using MrMeeseeks.DIE.CodeBuilding; using MrMeeseeks.DIE.ResolutionBuilding; -using MrMeeseeks.DIE.ResolutionBuilding.Function; using MrMeeseeks.DIE.Validation.Range; namespace MrMeeseeks.DIE; @@ -61,8 +60,6 @@ public void Execute() .ToList(); foreach (var containerSymbol in containerClasses) { - Resolvable.ResolvableCount = 0; - FunctionResolutionBuilder.FunctionLog.Clear(); try { var containerInfo = _containerInfoFactory(containerSymbol); @@ -79,21 +76,6 @@ public void Execute() } containerResolutionBuilder.FunctionCycleTracker.DetectCycle(); - _context.ReportDiagnostic(Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_00_00", - "Debug", - $"Resolution tree (Resolvable) item count: {Resolvable.ResolvableCount} ({containerSymbol.FullName()})", - "Warning", DiagnosticSeverity.Warning, - true), - Location.None)); - - _context.ReportDiagnostic(Diagnostic.Create(new DiagnosticDescriptor( - $"{Constants.DieAbbreviation}_00_00", - "Debug", - $"Function Count: {FunctionResolutionBuilder.FunctionLog.Count}", - "Warning", DiagnosticSeverity.Warning, - true), - Location.None)); - var containerResolution = containerResolutionBuilder.Build(); _containerGenerator.Generate(containerInfo, containerResolution); diff --git a/Main/ResolutionBuilding/Function/ContainerCreateFunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/ContainerCreateFunctionResolutionBuilder.cs index fffbced4..676b2f35 100644 --- a/Main/ResolutionBuilding/Function/ContainerCreateFunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/ContainerCreateFunctionResolutionBuilder.cs @@ -35,7 +35,6 @@ public ContainerCreateFunctionResolutionBuilder( } protected override string Name { get; } - protected override string TypeForLog => "ContainerCreate"; protected override Resolvable CreateResolvable() => SwitchType(new SwitchTypeParameter( _returnType, diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs index cdb472c9..4c725b19 100644 --- a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs @@ -114,13 +114,7 @@ internal FunctionResolutionBuilder( .ToList(); Resolvable = new(CreateResolvable); - - FunctionLog.Add($"{_rangeResolutionBaseBuilder.ErrorContext.Prefix}/{OriginalReturnType.FullName()}/{TypeForLog}/{string.Join(",", Parameters.Select(p => p.TypeFullName))}"); } - - protected abstract string TypeForLog { get; } - - internal static List FunctionLog = new(); private string ErrorMessage(IImmutableStack stack, ITypeSymbol currentType, string message) => $"[R:{_rangeResolutionBaseBuilder.ErrorContext.Prefix}][TS:{(stack.IsEmpty ? "empty" : stack.Peek().FullName())}][CT:{currentType.FullName()}] {message} [S:{(stack.IsEmpty ? "empty" : string.Join("<==", stack.Select(t => t.FullName())))}]"; diff --git a/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs index f4d14665..7811579f 100644 --- a/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs @@ -36,7 +36,6 @@ public LocalFunctionResolutionBuilder( } protected override string Name { get; } - protected override string TypeForLog => "LocalFunction"; protected override Resolvable CreateResolvable() => SwitchType(new SwitchTypeParameter( _returnType, diff --git a/Main/ResolutionBuilding/Function/RangedFunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/RangedFunctionResolutionBuilder.cs index 03bf242b..42e38452 100644 --- a/Main/ResolutionBuilding/Function/RangedFunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/RangedFunctionResolutionBuilder.cs @@ -37,7 +37,6 @@ public RangedFunctionResolutionBuilder( } protected override string Name { get; } - protected override string TypeForLog => "ScopedInstance"; protected override Resolvable CreateResolvable() => CreateConstructorResolution( _forConstructorParameter with diff --git a/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs index f517c81a..6434f19c 100644 --- a/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs @@ -35,8 +35,6 @@ public ScopeRootCreateFunctionResolutionBuilder( } protected override string Name { get; } - - protected override string TypeForLog => "ScopeRoot"; protected override Resolvable CreateResolvable() => SwitchImplementation( _parameter with diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index bde4de46..82f5de38 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -3,23 +3,9 @@ namespace MrMeeseeks.DIE; -internal abstract record ResolutionTreeItem { } +internal abstract record ResolutionTreeItem; -internal abstract record Resolvable : ResolutionTreeItem -{ - public string Reference { get; } - public string TypeFullName { get; } - internal static int ResolvableCount { get; set; } - - internal Resolvable( - string Reference, - string TypeFullName) - { - this.Reference = Reference; - this.TypeFullName = TypeFullName; - ResolvableCount++; - } -} +internal abstract record Resolvable(string Reference, string TypeFullName) : ResolutionTreeItem; internal record DeferringResolvable() : Resolvable("", "") { From 61b66d2536538c4b1013a4c6c6d5a380262089d0 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Wed, 13 Jul 2022 18:25:42 +0200 Subject: [PATCH 104/162] Checking member name collisions during validation --- Main/Constants.cs | 6 +++ Main/Diagnostics.cs | 8 ++++ Main/Extensions/AttributeDataExtensions.cs | 7 +++ .../ContainerResolutionBuilder.cs | 14 +++--- Main/SourceGenerator.cs | 3 +- Main/Validation/Range/ValidateContainer.cs | 46 ++++++++++++++++++- Main/Validation/Range/ValidateRange.cs | 10 ++++ 7 files changed, 85 insertions(+), 9 deletions(-) create mode 100644 Main/Extensions/AttributeDataExtensions.cs diff --git a/Main/Constants.cs b/Main/Constants.cs index 7ca4a800..8c54b997 100644 --- a/Main/Constants.cs +++ b/Main/Constants.cs @@ -2,6 +2,7 @@ namespace MrMeeseeks.DIE; internal static class Constants { + // General internal const string DieAbbreviation = "DIE"; internal const string ThisKeyword = "this"; @@ -18,4 +19,9 @@ internal static class Constants internal const string UserDefinedConstructorParameters = $"{DieAbbreviation}_ConstrParam"; internal const string UserDefinedAddForDisposal = $"{DieAbbreviation}_AddForDisposal"; internal const string UserDefinedAddForDisposalAsync = $"{DieAbbreviation}_AddForDisposalAsync"; + + // Create Functions + internal const string CreateFunctionSuffix = ""; + internal const string CreateFunctionSuffixAsync = "Async"; + internal const string CreateFunctionSuffixValueAsync = "ValueAsync"; } \ No newline at end of file diff --git a/Main/Diagnostics.cs b/Main/Diagnostics.cs index bddc2dbd..8b8d75a3 100644 --- a/Main/Diagnostics.cs +++ b/Main/Diagnostics.cs @@ -31,6 +31,14 @@ public static Diagnostic ValidationContainer(INamedTypeSymbol container, string true), container.Locations.FirstOrDefault() ?? Location.None); + public static Diagnostic ValidationContainer(INamedTypeSymbol container, string specification, Location location) => + Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_67_00", + "Validation (Container)", + $"The Container \"{container.Name}\" isn't validly defined: {specification}", + "Error", DiagnosticSeverity.Error, + true), + location); + public static Diagnostic ValidationTransientScope(INamedTypeSymbol transientScope, INamedTypeSymbol parentContainer, string specification) => Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_67_01", "Validation (TransientScope)", diff --git a/Main/Extensions/AttributeDataExtensions.cs b/Main/Extensions/AttributeDataExtensions.cs new file mode 100644 index 00000000..3336d937 --- /dev/null +++ b/Main/Extensions/AttributeDataExtensions.cs @@ -0,0 +1,7 @@ +namespace MrMeeseeks.DIE.Extensions; + +internal static class AttributeDataExtensions +{ + internal static Location GetLocation(this AttributeData attributeData) => + attributeData.ApplicationSyntaxReference?.GetSyntax().GetLocation() ?? Location.None; +} \ No newline at end of file diff --git a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs index 46471b07..c5a58a28 100644 --- a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs @@ -171,7 +171,7 @@ public ContainerResolution Build() call.AsyncTask.Await = false; call.AsyncValueTask.Await = false; var publicSyncResolutionFunction = new RootResolutionFunction( - methodNamePrefix, + $"{methodNamePrefix}{Constants.CreateFunctionSuffix}", privateRootResolutionFunction.TypeFullName, "public", call, @@ -192,7 +192,7 @@ public ContainerResolution Build() taskCall.AsyncTask.Await = false; taskCall.AsyncValueTask.Await = false; var publicTaskResolutionFunction = new RootResolutionFunction( - $"{methodNamePrefix}Async", + $"{methodNamePrefix}{Constants.CreateFunctionSuffixAsync}", boundTaskTypeFullName, "public", new TaskFromSyncResolution( @@ -216,7 +216,7 @@ public ContainerResolution Build() valueTaskCall.AsyncTask.Await = false; valueTaskCall.AsyncValueTask.Await = false; var publicValueTaskResolutionFunction = new RootResolutionFunction( - $"{methodNamePrefix}ValueAsync", + $"{methodNamePrefix}{Constants.CreateFunctionSuffixValueAsync}", boundValueTaskTypeFullName, "public", new ValueTaskFromSyncResolution( @@ -239,7 +239,7 @@ public ContainerResolution Build() call.AsyncTask.Await = false; call.AsyncValueTask.Await = false; var publicTaskResolutionFunction = new RootResolutionFunction( - $"{methodNamePrefix}Async", + $"{methodNamePrefix}{Constants.CreateFunctionSuffixAsync}", actual.FullName(), "public", call, @@ -260,7 +260,7 @@ public ContainerResolution Build() valueCall.AsyncTask.Await = false; valueCall.AsyncValueTask.Await = false; var publicValueTaskResolutionFunction = new RootResolutionFunction( - $"{methodNamePrefix}ValueAsync", + $"{methodNamePrefix}{Constants.CreateFunctionSuffixValueAsync}", boundValueTaskTypeFullName, "public", new ValueTaskFromWrappedTaskResolution( @@ -288,7 +288,7 @@ public ContainerResolution Build() call.AsyncValueTask.Await = false; var wrappedTaskReference = RootReferenceGenerator.Generate(_wellKnownTypes.ValueTask); var publicTaskResolutionFunction = new RootResolutionFunction( - $"{methodNamePrefix}Async", + $"{methodNamePrefix}{Constants.CreateFunctionSuffixAsync}", boundTaskTypeFullName, "public", new TaskFromWrappedValueTaskResolution( @@ -307,7 +307,7 @@ public ContainerResolution Build() valueCall.AsyncTask.Await = false; valueCall.AsyncValueTask.Await = false; var publicValueTaskResolutionFunction = new RootResolutionFunction( - $"{methodNamePrefix}ValueAsync", + $"{methodNamePrefix}{Constants.CreateFunctionSuffixValueAsync}", actual1.FullName(), "public", valueCall, diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index 5b8fe76f..79809b8f 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -57,7 +57,8 @@ public void Execute(GeneratorExecutionContext context) validateUserDefinedConstrParam, validateUserDefinedFactoryMethod, validateUserDefinedFactoryField, - wellKnownTypes); + wellKnownTypes, + wellKnownTypesMiscellaneous); var attributeTypesFromAttributes = new TypesFromAttributes( context.Compilation.Assembly.GetAttributes(), wellKnownTypesAggregation, diff --git a/Main/Validation/Range/ValidateContainer.cs b/Main/Validation/Range/ValidateContainer.cs index 3cf87f60..1591dd83 100644 --- a/Main/Validation/Range/ValidateContainer.cs +++ b/Main/Validation/Range/ValidateContainer.cs @@ -1,3 +1,5 @@ +using MrMeeseeks.DIE.Configuration.Attributes; +using MrMeeseeks.DIE.Extensions; using MrMeeseeks.DIE.Validation.Range.UserDefined; namespace MrMeeseeks.DIE.Validation.Range; @@ -10,6 +12,7 @@ internal class ValidateContainer : ValidateRange, IValidateContainer { private readonly IValidateTransientScope _validateTransientScopeFactory; private readonly IValidateScope _validateScopeFactory; + private readonly WellKnownTypesMiscellaneous _wellKnownTypesMiscellaneous; internal ValidateContainer( IValidateTransientScope validateTransientScopeFactory, @@ -19,7 +22,8 @@ internal ValidateContainer( IValidateUserDefinedConstrParam validateUserDefinedConstrParam, IValidateUserDefinedFactoryMethod validateUserDefinedFactoryMethod, IValidateUserDefinedFactoryField validateUserDefinedFactoryField, - WellKnownTypes wellKnownTypes) + WellKnownTypes wellKnownTypes, + WellKnownTypesMiscellaneous wellKnownTypesMiscellaneous) : base( validateUserDefinedAddForDisposalSync, validateUserDefinedAddForDisposalAsync, @@ -30,6 +34,7 @@ internal ValidateContainer( { _validateTransientScopeFactory = validateTransientScopeFactory; _validateScopeFactory = validateScopeFactory; + _wellKnownTypesMiscellaneous = wellKnownTypesMiscellaneous; } public override IEnumerable Validate(INamedTypeSymbol rangeType, INamedTypeSymbol containerType) @@ -58,8 +63,47 @@ public override IEnumerable Validate(INamedTypeSymbol rangeType, INa .Where(nts => nts.Name.StartsWith(Constants.CustomScopeName))) foreach (var diagnostic in _validateScopeFactory.Validate(customScope, rangeType)) yield return diagnostic; + + var createFunctionAttributes = rangeType + .GetAttributes() + .Where(ad => + SymbolEqualityComparer.Default.Equals( + ad.AttributeClass, + _wellKnownTypesMiscellaneous.CreateFunctionAttribute)) + .ToImmutableArray(); + + if (!createFunctionAttributes.Any()) + yield return ValidationErrorDiagnostic(rangeType, containerType, $"The container has to have at least one attribute of type \"{nameof(CreateFunctionAttribute)}\"."); + + var takenMemberNames = new HashSet(); + takenMemberNames.UnionWith(rangeType.MemberNames); + + foreach (var createFunctionAttribute in createFunctionAttributes) + { + var location = createFunctionAttribute.GetLocation(); + if (createFunctionAttribute.ConstructorArguments.Length == 2 + && createFunctionAttribute.ConstructorArguments[1].Value is string functionName) + { + if (functionName == nameof(IDisposable.Dispose)) + yield return ValidationErrorDiagnostic(rangeType, $"Create function isn't allowed to have the name \"{nameof(IDisposable.Dispose)}\", because a method with that name may have to be generated by the container.", location); + if (functionName == nameof(IAsyncDisposable.DisposeAsync)) + yield return ValidationErrorDiagnostic(rangeType, $"Create function isn't allowed to have the name \"{nameof(IAsyncDisposable.DisposeAsync)}\", because a method with that name will be generated by the container.", location); + + foreach (var concreteFunctionName in new [] { $"{functionName}{Constants.CreateFunctionSuffix}", $"{functionName}{Constants.CreateFunctionSuffixAsync}", $"{functionName}{Constants.CreateFunctionSuffixValueAsync}"}) + { + if (takenMemberNames.Contains(concreteFunctionName)) + yield return ValidationErrorDiagnostic(rangeType, $"Create function's name \"{concreteFunctionName}\" collides with one of the other members of the container class.", location); + takenMemberNames.Add(concreteFunctionName); + } + } + else + yield return ValidationErrorDiagnostic(rangeType, "Attribute doesn't have expected constructor arguments.", location); + } } protected override Diagnostic ValidationErrorDiagnostic(INamedTypeSymbol rangeType, INamedTypeSymbol _, string specification) => Diagnostics.ValidationContainer(rangeType, specification); + + private Diagnostic ValidationErrorDiagnostic(INamedTypeSymbol rangeType, string specification, Location location) => + Diagnostics.ValidationContainer(rangeType, specification, location); } \ No newline at end of file diff --git a/Main/Validation/Range/ValidateRange.cs b/Main/Validation/Range/ValidateRange.cs index 764b16eb..0a0dc90f 100644 --- a/Main/Validation/Range/ValidateRange.cs +++ b/Main/Validation/Range/ValidateRange.cs @@ -85,10 +85,20 @@ public virtual IEnumerable Validate(INamedTypeSymbol rangeType, INam SymbolEqualityComparer.Default.Equals(nts, _wellKnownTypes.Disposable))) yield return ValidationErrorDiagnostic(rangeType, containerType, $"Isn't allowed to implement the interface {_wellKnownTypes.Disposable.FullName()}. It'll be generated by DIE."); + if (rangeType + .MemberNames + .Contains(nameof(IDisposable.Dispose))) + yield return ValidationErrorDiagnostic(rangeType, containerType, $"Isn't allowed to contain an user-defined member \"{nameof(IDisposable.Dispose)}\", because a method with that name may have to be generated by the container."); + if (rangeType.AllInterfaces.Any(nts => SymbolEqualityComparer.Default.Equals(nts, _wellKnownTypes.AsyncDisposable))) yield return ValidationErrorDiagnostic(rangeType, containerType, $"Isn't allowed to implement the interface {_wellKnownTypes.AsyncDisposable.FullName()}. It'll be generated by DIE."); + if (rangeType + .MemberNames + .Contains(nameof(IAsyncDisposable.DisposeAsync))) + yield return ValidationErrorDiagnostic(rangeType, containerType, $"Isn't allowed to contain an user-defined member \"{nameof(IAsyncDisposable.DisposeAsync)}\", because a method with that name will be generated by the container."); + foreach (var diagnostic in ValidateAddForDisposal(Constants.UserDefinedAddForDisposal, true)) yield return diagnostic; foreach (var diagnostic in ValidateAddForDisposal(Constants.UserDefinedAddForDisposalAsync, false)) From cc04dcdbbf8c1351520065627364d9377a27a52e Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Thu, 14 Jul 2022 18:08:37 +0200 Subject: [PATCH 105/162] Adjustment for value types that are ranged --- Main/CodeBuilding/RangeCodeBaseBuilder.cs | 20 +++++++---- Main/Configuration/Attributes/Choice.cs | 8 ----- .../Configuration/Attributes/Miscellaneous.cs | 8 +++++ .../RangedFunctionGroupResolutionBuilder.cs | 5 ++- Main/ResolutionTreeItem.cs | 3 +- Main/SourceGenerator.cs | 6 ++-- Main/UserDefinedElements.cs | 4 +-- .../ValidateUserDefinedConstrParamMethod.cs | 12 +++---- Main/WellKnownTypesChoice.cs | 12 ++----- Main/WellKnownTypesMiscellaneous.cs | 6 ++++ Test/CustomEmbedding/ConstructorParameter.cs | 2 +- .../ConstructorParameterInScope.cs | 2 +- .../ConstructorParameterInTransientScope.cs | 2 +- ...ConstructorParameterWithAsyncDependency.cs | 2 +- ...ctorParameterWithAsyncDependencyInScope.cs | 2 +- ...eterWithAsyncDependencyInTransientScope.cs | 2 +- .../ConstructorParameterWithDependency.cs | 2 +- ...nstructorParameterWithDependencyInScope.cs | 2 +- ...ParameterWithDependencyInTransientScope.cs | 2 +- Test/Struct/RangedInScope.cs | 34 +++++++++++++++++++ 20 files changed, 90 insertions(+), 46 deletions(-) create mode 100644 Test/Struct/RangedInScope.cs diff --git a/Main/CodeBuilding/RangeCodeBaseBuilder.cs b/Main/CodeBuilding/RangeCodeBaseBuilder.cs index 2d577bc4..f203cb0d 100644 --- a/Main/CodeBuilding/RangeCodeBaseBuilder.cs +++ b/Main/CodeBuilding/RangeCodeBaseBuilder.cs @@ -461,12 +461,17 @@ private StringBuilder GenerateResolutions( private StringBuilder GenerateRangedInstanceFunction(StringBuilder stringBuilder, RangedInstanceFunctionGroupResolution rangedInstanceFunctionGroupResolution) { + var isRefType = rangedInstanceFunctionGroupResolution.IsCreatedForStructs is null; stringBuilder = stringBuilder .AppendLine( - $"private {rangedInstanceFunctionGroupResolution.TypeFullName}? {rangedInstanceFunctionGroupResolution.FieldReference};") + $"private {rangedInstanceFunctionGroupResolution.TypeFullName}{(isRefType ? "?" : "")} {rangedInstanceFunctionGroupResolution.FieldReference};") .AppendLine( $"private {WellKnownTypes.SemaphoreSlim.FullName()} {rangedInstanceFunctionGroupResolution.LockReference} = new {WellKnownTypes.SemaphoreSlim.FullName()}(1);"); - + + if (!isRefType) + stringBuilder = stringBuilder.AppendLine( + $"private bool {rangedInstanceFunctionGroupResolution.IsCreatedForStructs};"); + foreach (var overload in rangedInstanceFunctionGroupResolution.Overloads) { var isAsync = @@ -475,8 +480,10 @@ private StringBuilder GenerateRangedInstanceFunction(StringBuilder stringBuilder overload.Parameter.Select(p => $"{p.TypeFullName} {p.Reference}")); stringBuilder = stringBuilder.AppendLine( $"public {(isAsync ? "async " : "")}{overload.TypeFullName} {overload.Reference}({parameters})") - .AppendLine($"{{").AppendLine( - $"if (!object.ReferenceEquals({rangedInstanceFunctionGroupResolution.FieldReference}, null)) return {rangedInstanceFunctionGroupResolution.FieldReference};") + .AppendLine($"{{") + .AppendLine(isRefType + ? $"if (!object.ReferenceEquals({rangedInstanceFunctionGroupResolution.FieldReference}, null)) return {rangedInstanceFunctionGroupResolution.FieldReference};" + : $"if ({rangedInstanceFunctionGroupResolution.IsCreatedForStructs}) return {rangedInstanceFunctionGroupResolution.FieldReference};") .AppendLine($"{(isAsync ? "await " : "")}this.{rangedInstanceFunctionGroupResolution.LockReference}.Wait{(isAsync ? "Async" : "")}();") .AppendLine($"try") .AppendLine($"{{"); @@ -485,8 +492,9 @@ private StringBuilder GenerateRangedInstanceFunction(StringBuilder stringBuilder .AppendLine( $"if (this.{_rangeResolution.DisposalHandling.DisposedPropertyReference}) throw new {WellKnownTypes.ObjectDisposedException}(nameof({_rangeResolution.DisposalHandling.RangeName}));"); stringBuilder = stringBuilder - .AppendLine( - $"if (!object.ReferenceEquals({rangedInstanceFunctionGroupResolution.FieldReference}, null)) return {rangedInstanceFunctionGroupResolution.FieldReference};"); + .AppendLine(isRefType + ? $"if (!object.ReferenceEquals({rangedInstanceFunctionGroupResolution.FieldReference}, null)) return {rangedInstanceFunctionGroupResolution.FieldReference};" + : $"if ({rangedInstanceFunctionGroupResolution.IsCreatedForStructs}) return {rangedInstanceFunctionGroupResolution.FieldReference};"); stringBuilder = GenerateResolutionFunctionContent(stringBuilder, overload.Resolvable); diff --git a/Main/Configuration/Attributes/Choice.cs b/Main/Configuration/Attributes/Choice.cs index f7525c4c..18212036 100644 --- a/Main/Configuration/Attributes/Choice.cs +++ b/Main/Configuration/Attributes/Choice.cs @@ -91,12 +91,4 @@ public ImplementationCollectionChoiceAttribute(Type type, params Type[] implemen public class FilterImplementationCollectionChoiceAttribute : Attribute { public FilterImplementationCollectionChoiceAttribute(Type type) {} -} - -[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] -public class CustomConstructorParameterChoiceAttribute : Attribute -{ - public CustomConstructorParameterChoiceAttribute(Type type) - { - } } \ No newline at end of file diff --git a/Main/Configuration/Attributes/Miscellaneous.cs b/Main/Configuration/Attributes/Miscellaneous.cs index ee7faa6f..64ddcd49 100644 --- a/Main/Configuration/Attributes/Miscellaneous.cs +++ b/Main/Configuration/Attributes/Miscellaneous.cs @@ -9,6 +9,14 @@ public CustomScopeForRootTypesAttribute(params Type[] types) } } +[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] +public class CustomConstructorParameterAttribute : Attribute +{ + public CustomConstructorParameterAttribute(Type type) + { + } +} + [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class TypeInitializerAttribute : Attribute { diff --git a/Main/ResolutionBuilding/Function/RangedFunctionGroupResolutionBuilder.cs b/Main/ResolutionBuilding/Function/RangedFunctionGroupResolutionBuilder.cs index 64e2693e..12bca2cd 100644 --- a/Main/ResolutionBuilding/Function/RangedFunctionGroupResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/RangedFunctionGroupResolutionBuilder.cs @@ -28,6 +28,7 @@ private readonly Func< private readonly string _typeFullName; private readonly string _fieldReference; private readonly string _lockReference; + private readonly string? _isCreatedForStructs; private readonly Dictionary _overloads = new(); private readonly List _functionQueue = new(); @@ -52,6 +53,7 @@ internal RangedFunctionGroupResolutionBuilder( _fieldReference = rootReferenceGenerator.Generate($"_{label.ToLower()}InstanceField", implementationType, decorationSuffix); _lockReference = rootReferenceGenerator.Generate($"_{label.ToLower()}InstanceLock{decorationSuffix}"); + _isCreatedForStructs = implementationType.IsValueType ? rootReferenceGenerator.Generate("isCreated") : null; } public IRangedFunctionResolutionBuilder GetInstanceFunction( @@ -94,5 +96,6 @@ public RangedInstanceFunctionGroupResolution Build() => functionResolution.SynchronicityDecision)) .ToList(), _fieldReference, - _lockReference); + _lockReference, + _isCreatedForStructs); } \ No newline at end of file diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index 82f5de38..f0b4aa78 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -57,7 +57,8 @@ internal record RangedInstanceFunctionGroupResolution( string TypeFullName, IReadOnlyList Overloads, string FieldReference, - string LockReference); + string LockReference, + string? IsCreatedForStructs); internal record MethodGroupResolution( string Reference, diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index 79809b8f..635a23a7 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -28,7 +28,7 @@ public void Execute(GeneratorExecutionContext context) var diagLogger = new DiagLogger(errorDescriptionInsteadOfBuildFailure, context); var validateUserDefinedAddForDisposalSync = new ValidateUserDefinedAddForDisposalSync(wellKnownTypes); var validateUserDefinedAddForDisposalAsync = new ValidateUserDefinedAddForDisposalAsync(wellKnownTypes); - var validateUserDefinedConstrParam = new ValidateUserDefinedConstrParam(wellKnownTypesChoice); + var validateUserDefinedConstrParam = new ValidateUserDefinedConstrParam(wellKnownTypesMiscellaneous); var validateUserDefinedFactoryField = new ValidateUserDefinedFactoryField(); var validateUserDefinedFactoryMethod = new ValidateUserDefinedFactoryMethod(); var validateTransientScope = new ValidateTransientScope( @@ -103,7 +103,7 @@ IContainerResolutionBuilder ResolutionTreeFactory(IContainerInfo ci) RangedFunctionGroupResolutionBuilderFactory, FunctionResolutionSynchronicityDecisionMakerFactory, LocalFunctionResolutionBuilderFactory, - new UserDefinedElements(ci.ContainerType, ci.ContainerType, wellKnownTypes, wellKnownTypesChoice), + new UserDefinedElements(ci.ContainerType, ci.ContainerType, wellKnownTypes, wellKnownTypesMiscellaneous), functionCycleTracker); IScopeManager ScopeManagerFactory( @@ -121,7 +121,7 @@ IScopeManager ScopeManagerFactory( wellKnownTypesChoice, wellKnownTypesMiscellaneous), tfa => new CheckTypeProperties(new CurrentlyConsideredTypes(tfa, implementationTypeSetCache), wellKnownTypes), - st => new UserDefinedElements(st, ci.ContainerType, wellKnownTypes, wellKnownTypesChoice), + st => new UserDefinedElements(st, ci.ContainerType, wellKnownTypes, wellKnownTypesMiscellaneous), new EmptyUserDefinedElements(), wellKnownTypesMiscellaneous); diff --git a/Main/UserDefinedElements.cs b/Main/UserDefinedElements.cs index d1232100..93fb58b1 100644 --- a/Main/UserDefinedElements.cs +++ b/Main/UserDefinedElements.cs @@ -34,7 +34,7 @@ public UserDefinedElements( // dependencies WellKnownTypes wellKnownTypes, - WellKnownTypesChoice wellKnownTypesChoice) + WellKnownTypesMiscellaneous wellKnownTypesMiscellaneous) { var validationErrors = new List(); var dieMembers = scopeType.GetMembers() @@ -126,7 +126,7 @@ public UserDefinedElements( { var type = m.GetAttributes() .Where(ad => SymbolEqualityComparer.Default.Equals(ad.AttributeClass, - wellKnownTypesChoice.CustomConstructorParameterChoiceAttribute)) + wellKnownTypesMiscellaneous.CustomConstructorParameterAttribute)) .Select(ad => { if (ad.ConstructorArguments.Length != 1) diff --git a/Main/Validation/Range/UserDefined/ValidateUserDefinedConstrParamMethod.cs b/Main/Validation/Range/UserDefined/ValidateUserDefinedConstrParamMethod.cs index 5e9cf1a5..f0fb9eff 100644 --- a/Main/Validation/Range/UserDefined/ValidateUserDefinedConstrParamMethod.cs +++ b/Main/Validation/Range/UserDefined/ValidateUserDefinedConstrParamMethod.cs @@ -7,12 +7,10 @@ internal interface IValidateUserDefinedConstrParam : IValidateUserDefinedMethod internal class ValidateUserDefinedConstrParam : ValidateUserDefinedMethod, IValidateUserDefinedConstrParam { - private readonly WellKnownTypesChoice _wellKnownTypesChoice; + private readonly WellKnownTypesMiscellaneous _wellKnownTypesMiscellaneous; - internal ValidateUserDefinedConstrParam(WellKnownTypesChoice wellKnownTypesChoice) - { - _wellKnownTypesChoice = wellKnownTypesChoice; - } + internal ValidateUserDefinedConstrParam(WellKnownTypesMiscellaneous wellKnownTypesMiscellaneous) => + _wellKnownTypesMiscellaneous = wellKnownTypesMiscellaneous; public override IEnumerable Validate(IMethodSymbol method, INamedTypeSymbol rangeType, INamedTypeSymbol containerType) { @@ -75,8 +73,8 @@ public override IEnumerable Validate(IMethodSymbol method, INamedTyp if (method .GetAttributes() - .Count(ad => SymbolEqualityComparer.Default.Equals(ad.AttributeClass, _wellKnownTypesChoice.CustomConstructorParameterChoiceAttribute)) + .Count(ad => SymbolEqualityComparer.Default.Equals(ad.AttributeClass, _wellKnownTypesMiscellaneous.CustomConstructorParameterAttribute)) != 1) - yield return ValidationErrorDiagnostic(method, rangeType, containerType, $"Has to have exactly one attribute of type \"{_wellKnownTypesChoice.CustomConstructorParameterChoiceAttribute.FullName()}\"."); + yield return ValidationErrorDiagnostic(method, rangeType, containerType, $"Has to have exactly one attribute of type \"{_wellKnownTypesMiscellaneous.CustomConstructorParameterAttribute.FullName()}\"."); } } \ No newline at end of file diff --git a/Main/WellKnownTypesChoice.cs b/Main/WellKnownTypesChoice.cs index 2f801db3..a5c32b0f 100644 --- a/Main/WellKnownTypesChoice.cs +++ b/Main/WellKnownTypesChoice.cs @@ -16,8 +16,7 @@ internal record WellKnownTypesChoice( INamedTypeSymbol FilterConstructorChoiceAttribute, INamedTypeSymbol FilterPropertyChoiceAttribute, INamedTypeSymbol FilterImplementationChoiceAttribute, - INamedTypeSymbol FilterImplementationCollectionChoiceAttribute, - INamedTypeSymbol CustomConstructorParameterChoiceAttribute) + INamedTypeSymbol FilterImplementationCollectionChoiceAttribute) { internal static bool TryCreate(Compilation compilation, out WellKnownTypesChoice wellKnownTypes) { @@ -63,9 +62,6 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypesChoice var filterImplementationCollectionChoiceAttribute = compilation .GetTypeByMetadataName(typeof(FilterImplementationCollectionChoiceAttribute).FullName ?? ""); - var customConstructorParameterChoiceAttribute = compilation - .GetTypeByMetadataName(typeof(CustomConstructorParameterChoiceAttribute).FullName ?? ""); - if (implementationChoiceAttribute is not null && implementationCollectionChoiceAttribute is not null && genericParameterSubstitutesChoiceAttribute is not null @@ -79,8 +75,7 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypesChoice && filterConstructorChoiceAttribute is not null && filterPropertyChoiceAttribute is not null && filterImplementationChoiceAttribute is not null - && filterImplementationCollectionChoiceAttribute is not null - && customConstructorParameterChoiceAttribute is not null) + && filterImplementationCollectionChoiceAttribute is not null) { wellKnownTypes = new WellKnownTypesChoice( @@ -97,8 +92,7 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypesChoice FilterConstructorChoiceAttribute: filterConstructorChoiceAttribute, FilterPropertyChoiceAttribute: filterPropertyChoiceAttribute, FilterImplementationChoiceAttribute: filterImplementationChoiceAttribute, - FilterImplementationCollectionChoiceAttribute: filterImplementationCollectionChoiceAttribute, - CustomConstructorParameterChoiceAttribute: customConstructorParameterChoiceAttribute); + FilterImplementationCollectionChoiceAttribute: filterImplementationCollectionChoiceAttribute); return true; } diff --git a/Main/WellKnownTypesMiscellaneous.cs b/Main/WellKnownTypesMiscellaneous.cs index fd46569f..e3deb195 100644 --- a/Main/WellKnownTypesMiscellaneous.cs +++ b/Main/WellKnownTypesMiscellaneous.cs @@ -6,6 +6,7 @@ internal record WellKnownTypesMiscellaneous( INamedTypeSymbol TypeInitializerAttribute, INamedTypeSymbol FilterTypeInitializerAttribute, INamedTypeSymbol CustomScopeForRootTypesAttribute, + INamedTypeSymbol CustomConstructorParameterAttribute, INamedTypeSymbol CreateFunctionAttribute, INamedTypeSymbol ErrorDescriptionInsteadOfBuildFailureAttribute, INamedTypeSymbol DieExceptionKind) @@ -15,6 +16,9 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypesMiscel var customScopeForRootTypesAttribute = compilation .GetTypeByMetadataName(typeof(CustomScopeForRootTypesAttribute).FullName ?? ""); + var customConstructorParameterAttribute = compilation + .GetTypeByMetadataName(typeof(CustomConstructorParameterAttribute).FullName ?? ""); + var typeInitializerAttribute = compilation .GetTypeByMetadataName(typeof(TypeInitializerAttribute).FullName ?? ""); @@ -33,6 +37,7 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypesMiscel if (typeInitializerAttribute is not null && filterTypeInitializerAttribute is not null && customScopeForRootTypesAttribute is not null + && customConstructorParameterAttribute is not null && createFunctionAttribute is not null && errorDescriptionInsteadOfBuildFailureAttribute is not null && dieExceptionKind is not null) @@ -42,6 +47,7 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypesMiscel TypeInitializerAttribute: typeInitializerAttribute, FilterTypeInitializerAttribute: filterTypeInitializerAttribute, CustomScopeForRootTypesAttribute: customScopeForRootTypesAttribute, + CustomConstructorParameterAttribute: customConstructorParameterAttribute, CreateFunctionAttribute: createFunctionAttribute, ErrorDescriptionInsteadOfBuildFailureAttribute: errorDescriptionInsteadOfBuildFailureAttribute, DieExceptionKind: dieExceptionKind); diff --git a/Test/CustomEmbedding/ConstructorParameter.cs b/Test/CustomEmbedding/ConstructorParameter.cs index 98eabd49..ad323ad4 100644 --- a/Test/CustomEmbedding/ConstructorParameter.cs +++ b/Test/CustomEmbedding/ConstructorParameter.cs @@ -14,7 +14,7 @@ internal class Dependency [CreateFunction(typeof(Dependency), "Create")] internal sealed partial class Container { - [CustomConstructorParameterChoice(typeof(Dependency))] + [CustomConstructorParameter(typeof(Dependency))] private void DIE_ConstrParam_Dependency(out int number) => number = 69; } diff --git a/Test/CustomEmbedding/ConstructorParameterInScope.cs b/Test/CustomEmbedding/ConstructorParameterInScope.cs index 3eeac8ee..c58899a8 100644 --- a/Test/CustomEmbedding/ConstructorParameterInScope.cs +++ b/Test/CustomEmbedding/ConstructorParameterInScope.cs @@ -24,7 +24,7 @@ internal sealed partial class Container { private sealed partial class DIE_DefaultScope { - [CustomConstructorParameterChoice(typeof(Dependency))] + [CustomConstructorParameter(typeof(Dependency))] private void DIE_ConstrParam_Dependency(out int number) => number = 69; } } diff --git a/Test/CustomEmbedding/ConstructorParameterInTransientScope.cs b/Test/CustomEmbedding/ConstructorParameterInTransientScope.cs index eb2fc072..d906e2ba 100644 --- a/Test/CustomEmbedding/ConstructorParameterInTransientScope.cs +++ b/Test/CustomEmbedding/ConstructorParameterInTransientScope.cs @@ -24,7 +24,7 @@ internal sealed partial class Container { private sealed partial class DIE_DefaultTransientScope { - [CustomConstructorParameterChoice(typeof(Dependency))] + [CustomConstructorParameter(typeof(Dependency))] private void DIE_ConstrParam_Dependency(out int number) => number = 69; } } diff --git a/Test/CustomEmbedding/ConstructorParameterWithAsyncDependency.cs b/Test/CustomEmbedding/ConstructorParameterWithAsyncDependency.cs index fdc5a499..c63e767c 100644 --- a/Test/CustomEmbedding/ConstructorParameterWithAsyncDependency.cs +++ b/Test/CustomEmbedding/ConstructorParameterWithAsyncDependency.cs @@ -20,7 +20,7 @@ internal class OtherDependency : IValueTaskTypeInitializer [CreateFunction(typeof(Dependency), "Create")] internal sealed partial class Container { - [CustomConstructorParameterChoice(typeof(Dependency))] + [CustomConstructorParameter(typeof(Dependency))] private void DIE_ConstrParam_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; } diff --git a/Test/CustomEmbedding/ConstructorParameterWithAsyncDependencyInScope.cs b/Test/CustomEmbedding/ConstructorParameterWithAsyncDependencyInScope.cs index 1e8b0813..924eb4b3 100644 --- a/Test/CustomEmbedding/ConstructorParameterWithAsyncDependencyInScope.cs +++ b/Test/CustomEmbedding/ConstructorParameterWithAsyncDependencyInScope.cs @@ -30,7 +30,7 @@ internal sealed partial class Container { private sealed partial class DIE_DefaultScope { - [CustomConstructorParameterChoice(typeof(Dependency))] + [CustomConstructorParameter(typeof(Dependency))] private void DIE_ConstrParam_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; } } diff --git a/Test/CustomEmbedding/ConstructorParameterWithAsyncDependencyInTransientScope.cs b/Test/CustomEmbedding/ConstructorParameterWithAsyncDependencyInTransientScope.cs index 0470c9fd..f1ecf414 100644 --- a/Test/CustomEmbedding/ConstructorParameterWithAsyncDependencyInTransientScope.cs +++ b/Test/CustomEmbedding/ConstructorParameterWithAsyncDependencyInTransientScope.cs @@ -30,7 +30,7 @@ internal sealed partial class Container { private sealed partial class DIE_DefaultTransientScope { - [CustomConstructorParameterChoice(typeof(Dependency))] + [CustomConstructorParameter(typeof(Dependency))] private void DIE_ConstrParam_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; } } diff --git a/Test/CustomEmbedding/ConstructorParameterWithDependency.cs b/Test/CustomEmbedding/ConstructorParameterWithDependency.cs index 64234a6e..f4edb130 100644 --- a/Test/CustomEmbedding/ConstructorParameterWithDependency.cs +++ b/Test/CustomEmbedding/ConstructorParameterWithDependency.cs @@ -19,7 +19,7 @@ internal class OtherDependency [CreateFunction(typeof(Dependency), "Create")] internal sealed partial class Container { - [CustomConstructorParameterChoice(typeof(Dependency))] + [CustomConstructorParameter(typeof(Dependency))] private void DIE_ConstrParam_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; } diff --git a/Test/CustomEmbedding/ConstructorParameterWithDependencyInScope.cs b/Test/CustomEmbedding/ConstructorParameterWithDependencyInScope.cs index 1aabdbd5..e29057ed 100644 --- a/Test/CustomEmbedding/ConstructorParameterWithDependencyInScope.cs +++ b/Test/CustomEmbedding/ConstructorParameterWithDependencyInScope.cs @@ -29,7 +29,7 @@ internal sealed partial class Container { private sealed partial class DIE_DefaultScope { - [CustomConstructorParameterChoice(typeof(Dependency))] + [CustomConstructorParameter(typeof(Dependency))] private void DIE_ConstrParam_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; } } diff --git a/Test/CustomEmbedding/ConstructorParameterWithDependencyInTransientScope.cs b/Test/CustomEmbedding/ConstructorParameterWithDependencyInTransientScope.cs index 55a55981..aa668aa7 100644 --- a/Test/CustomEmbedding/ConstructorParameterWithDependencyInTransientScope.cs +++ b/Test/CustomEmbedding/ConstructorParameterWithDependencyInTransientScope.cs @@ -29,7 +29,7 @@ internal sealed partial class Container { private sealed partial class DIE_DefaultTransientScope { - [CustomConstructorParameterChoice(typeof(Dependency))] + [CustomConstructorParameter(typeof(Dependency))] private void DIE_ConstrParam_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; } } diff --git a/Test/Struct/RangedInScope.cs b/Test/Struct/RangedInScope.cs new file mode 100644 index 00000000..901c0b61 --- /dev/null +++ b/Test/Struct/RangedInScope.cs @@ -0,0 +1,34 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Struct.RangedInScope; + +internal struct Dependency : IScopeInstance +{ + public int Value { get; set; } + + internal Dependency(int value) => + Value = value; +} + +[CreateFunction(typeof(Dependency), "Create")] +internal sealed partial class Container +{ + private int DIE_Factory_int => 23; +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var value = container.Create(); + Assert.IsType(value); + Assert.Equal(23, value.Value); + value.Value = 69; + var valueAgain = container.Create(); + Assert.Equal(23, valueAgain.Value); + } +} \ No newline at end of file From 9a8341b5836b1009f26b42932f741e45735668df Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Tue, 19 Jul 2022 16:03:45 +0200 Subject: [PATCH 106/162] Fixing transient instances --- ...ransientScopeInterfaceResolutionBuilder.cs | 78 +++++++++++-------- 1 file changed, 47 insertions(+), 31 deletions(-) diff --git a/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs b/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs index 8d88feb9..2763da99 100644 --- a/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs +++ b/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs @@ -105,40 +105,56 @@ private MultiSynchronicityFunctionCallResolution CreateRangedInstanceReferenceRe var (reference, handle) = tuple; - var key = $"{referenceKey}:::{string.Join(":::", currentParameters.Select(p => p.Value.Item1.FullName()))}"; - if (!_rangedInstanceReferenceResolutions.TryGetValue(key, out var interfaceDeclaration)) - { - var queueItem = new RangedInstanceResolutionsQueueItem( - parameter, - label, - reference, + var key = $"{referenceKey}:::{string.Join(":::", currentParameters.Select(p => p.Value.Item2.TypeFullName))}"; + if (!_rangedInstanceReferenceResolutions.TryGetValue( key, - handle); - - _pastQueuedItems.Add(queueItem); - - var synchronicityDecisionMaker = _synchronicityDecisionMakerFactory(); - _synchronicityDecisionMakers[key] = synchronicityDecisionMaker; - - foreach (var implementation in _implementations) + out var interfaceDeclaration)) + { + if (_rangedInstanceReferenceResolutions + .Values + .Where(f => + f.TypeFullName == implementationType.FullName(SymbolDisplayMiscellaneousOptions.None) + && f.Parameter.All(cp => currentParameters.Any(p => + cp.TypeFullName == p.Value.Item2.TypeFullName))) + .OrderByDescending(f => f.Parameter.Count) + .FirstOrDefault() is { } greatestCommonParameterSetFunction) { - var multiSynchronicityFunctionCallResolution = implementation.EnqueueRangedInstanceResolution( - queueItem.Parameter, - queueItem.Label, - queueItem.Reference, - new (() => synchronicityDecisionMaker)); - _functionCycleTracker.TrackFunctionCall(handle, multiSynchronicityFunctionCallResolution.FunctionResolutionBuilderHandle); + interfaceDeclaration = greatestCommonParameterSetFunction; + } + else + { + var queueItem = new RangedInstanceResolutionsQueueItem( + parameter, + label, + reference, + key, + handle); + + _pastQueuedItems.Add(queueItem); + + var synchronicityDecisionMaker = _synchronicityDecisionMakerFactory(); + _synchronicityDecisionMakers[key] = synchronicityDecisionMaker; + + foreach (var implementation in _implementations) + { + var multiSynchronicityFunctionCallResolution = implementation.EnqueueRangedInstanceResolution( + queueItem.Parameter, + queueItem.Label, + queueItem.Reference, + new (() => synchronicityDecisionMaker)); + _functionCycleTracker.TrackFunctionCall(handle, multiSynchronicityFunctionCallResolution.FunctionResolutionBuilderHandle); + } + + interfaceDeclaration = new InterfaceFunctionDeclarationResolution( + reference, + implementationType.FullName(), + _wellKnownTypes.Task1.Construct(implementationType).FullName(), + _wellKnownTypes.ValueTask1.Construct(implementationType).FullName(), + currentParameters.Select(t => + new ParameterResolution(_rootReferenceGenerator.Generate(t.Value.Item1), t.Value.Item1.FullName())).ToList(), + synchronicityDecisionMaker.Decision); + _rangedInstanceReferenceResolutions[key] = interfaceDeclaration; } - - interfaceDeclaration = new InterfaceFunctionDeclarationResolution( - reference, - implementationType.FullName(), - _wellKnownTypes.Task1.Construct(implementationType).FullName(), - _wellKnownTypes.ValueTask1.Construct(implementationType).FullName(), - currentParameters.Select(t => - new ParameterResolution(_rootReferenceGenerator.Generate(t.Value.Item1), t.Value.Item1.FullName())).ToList(), - synchronicityDecisionMaker.Decision); - _rangedInstanceReferenceResolutions[key] = interfaceDeclaration; } var returnReference = _rootReferenceGenerator.Generate("ret"); From 4bf2cbac7e513f4431eb49aa7325853bb804ab76 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Tue, 19 Jul 2022 19:45:42 +0200 Subject: [PATCH 107/162] Fix of fix :D --- .../TransientScopeInterfaceResolutionBuilder.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs b/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs index 2763da99..cdeb203e 100644 --- a/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs +++ b/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs @@ -111,15 +111,15 @@ private MultiSynchronicityFunctionCallResolution CreateRangedInstanceReferenceRe out var interfaceDeclaration)) { if (_rangedInstanceReferenceResolutions - .Values - .Where(f => - f.TypeFullName == implementationType.FullName(SymbolDisplayMiscellaneousOptions.None) - && f.Parameter.All(cp => currentParameters.Any(p => + .Where(kvp => + kvp.Value.TypeFullName == implementationType.FullName(SymbolDisplayMiscellaneousOptions.None) + && kvp.Value.Parameter.All(cp => currentParameters.Any(p => cp.TypeFullName == p.Value.Item2.TypeFullName))) - .OrderByDescending(f => f.Parameter.Count) - .FirstOrDefault() is { } greatestCommonParameterSetFunction) + .OrderByDescending(kvp => kvp.Value.Parameter.Count) + .FirstOrDefault() is { Key: { } reducedKey, Value: { } greatestCommonParameterSetFunction }) { interfaceDeclaration = greatestCommonParameterSetFunction; + _synchronicityDecisionMakers[key] = _synchronicityDecisionMakers[reducedKey]; } else { From a73208e7267b4ebff811e10681a7f9ba5299cc97 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Mon, 25 Jul 2022 08:45:47 +0200 Subject: [PATCH 108/162] Made transient scope interface and its adapter class for the container private That way they won't show up in IntelliSense --- Main/CodeBuilding/ContainerCodeBuilder.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Main/CodeBuilding/ContainerCodeBuilder.cs b/Main/CodeBuilding/ContainerCodeBuilder.cs index d3a608c4..e32f6cf1 100644 --- a/Main/CodeBuilding/ContainerCodeBuilder.cs +++ b/Main/CodeBuilding/ContainerCodeBuilder.cs @@ -74,7 +74,7 @@ public override StringBuilder Build(StringBuilder stringBuilder) _containerResolution); stringBuilder = stringBuilder - .AppendLine($"internal interface {_containerResolution.TransientScopeInterface.Name}") + .AppendLine($"private interface {_containerResolution.TransientScopeInterface.Name}") .AppendLine($"{{"); stringBuilder = _containerResolution.TransientScopeInterface.Functions.Aggregate( @@ -86,7 +86,7 @@ public override StringBuilder Build(StringBuilder stringBuilder) .AppendLine($"}}"); stringBuilder = stringBuilder - .AppendLine($"internal class {_containerResolution.TransientScopeInterface.ContainerAdapterName} : {_containerResolution.TransientScopeInterface.Name}") + .AppendLine($"private class {_containerResolution.TransientScopeInterface.ContainerAdapterName} : {_containerResolution.TransientScopeInterface.Name}") .AppendLine($"{{") .AppendLine($"private {_containerInfo.FullName} _container;") .AppendLine($"internal {_containerResolution.TransientScopeInterface.ContainerAdapterName}({_containerInfo.FullName} container) => _container = container;"); From 0179d5d1709246bfeaf3e31e10c2fbd7de2a2960 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sun, 31 Jul 2022 18:07:02 +0200 Subject: [PATCH 109/162] Validating the easiest (but most) attributes --- Main/Configuration/TypesFromAttributes.cs | 169 ++++++++++++------ Main/DiagLogger.cs | 15 +- Main/Diagnostics.cs | 19 ++ Main/ExecuteImpl.cs | 19 +- Main/ResolutionBuilding/ScopeManager.cs | 16 +- Main/SourceGenerator.cs | 63 +++++-- .../Attributes/ValidateAttributes.cs | 17 ++ 7 files changed, 215 insertions(+), 103 deletions(-) create mode 100644 Main/Validation/Attributes/ValidateAttributes.cs diff --git a/Main/Configuration/TypesFromAttributes.cs b/Main/Configuration/TypesFromAttributes.cs index 69b52104..1ed77f61 100644 --- a/Main/Configuration/TypesFromAttributes.cs +++ b/Main/Configuration/TypesFromAttributes.cs @@ -1,4 +1,5 @@ using MrMeeseeks.DIE.Extensions; +using MrMeeseeks.DIE.Validation.Attributes; namespace MrMeeseeks.DIE.Configuration; @@ -69,84 +70,99 @@ internal class TypesFromAttributes : ScopeTypesFromAttributes internal TypesFromAttributes( // parameter IReadOnlyList attributeData, + INamedTypeSymbol? rangeType, + INamedTypeSymbol? containerType, // dependencies + IValidateAttributes validateAttributes, WellKnownTypesAggregation wellKnownTypesAggregation, WellKnownTypesChoice wellKnownTypesChoice, WellKnownTypesMiscellaneous wellKnownTypesMiscellaneous) - : base(attributeData, wellKnownTypesAggregation, wellKnownTypesChoice, wellKnownTypesMiscellaneous) + : base(attributeData, rangeType, containerType, validateAttributes, wellKnownTypesAggregation, wellKnownTypesChoice, wellKnownTypesMiscellaneous) { - ContainerInstanceAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.ContainerInstanceAbstractionAggregationAttribute); - TransientScopeInstanceAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.TransientScopeInstanceAbstractionAggregationAttribute); - TransientScopeRootAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.TransientScopeRootAbstractionAggregationAttribute); - ScopeRootAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.ScopeRootAbstractionAggregationAttribute); - ContainerInstanceImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.ContainerInstanceImplementationAggregationAttribute); - TransientScopeInstanceImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.TransientScopeInstanceImplementationAggregationAttribute); - TransientScopeRootImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.TransientScopeRootImplementationAggregationAttribute); - ScopeRootImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.ScopeRootImplementationAggregationAttribute); - FilterContainerInstanceAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.FilterContainerInstanceAbstractionAggregationAttribute); - FilterTransientScopeInstanceAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.FilterTransientScopeInstanceAbstractionAggregationAttribute); - FilterTransientScopeRootAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.FilterTransientScopeRootAbstractionAggregationAttribute); - FilterScopeRootAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.FilterScopeRootAbstractionAggregationAttribute); - FilterContainerInstanceImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.FilterContainerInstanceImplementationAggregationAttribute); - FilterTransientScopeInstanceImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.FilterTransientScopeInstanceImplementationAggregationAttribute); - FilterTransientScopeRootImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.FilterTransientScopeRootImplementationAggregationAttribute); - FilterScopeRootImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.FilterScopeRootImplementationAggregationAttribute); + ContainerInstanceAbstraction = GetAbstractionTypesFromAttribute(wellKnownTypesAggregation.ContainerInstanceAbstractionAggregationAttribute); + TransientScopeInstanceAbstraction = GetAbstractionTypesFromAttribute(wellKnownTypesAggregation.TransientScopeInstanceAbstractionAggregationAttribute); + TransientScopeRootAbstraction = GetAbstractionTypesFromAttribute(wellKnownTypesAggregation.TransientScopeRootAbstractionAggregationAttribute); + ScopeRootAbstraction = GetAbstractionTypesFromAttribute(wellKnownTypesAggregation.ScopeRootAbstractionAggregationAttribute); + ContainerInstanceImplementation = GetImplementationTypesFromAttribute(wellKnownTypesAggregation.ContainerInstanceImplementationAggregationAttribute); + TransientScopeInstanceImplementation = GetImplementationTypesFromAttribute(wellKnownTypesAggregation.TransientScopeInstanceImplementationAggregationAttribute); + TransientScopeRootImplementation = GetImplementationTypesFromAttribute(wellKnownTypesAggregation.TransientScopeRootImplementationAggregationAttribute); + ScopeRootImplementation = GetImplementationTypesFromAttribute(wellKnownTypesAggregation.ScopeRootImplementationAggregationAttribute); + FilterContainerInstanceAbstraction = GetAbstractionTypesFromAttribute(wellKnownTypesAggregation.FilterContainerInstanceAbstractionAggregationAttribute); + FilterTransientScopeInstanceAbstraction = GetAbstractionTypesFromAttribute(wellKnownTypesAggregation.FilterTransientScopeInstanceAbstractionAggregationAttribute); + FilterTransientScopeRootAbstraction = GetAbstractionTypesFromAttribute(wellKnownTypesAggregation.FilterTransientScopeRootAbstractionAggregationAttribute); + FilterScopeRootAbstraction = GetAbstractionTypesFromAttribute(wellKnownTypesAggregation.FilterScopeRootAbstractionAggregationAttribute); + FilterContainerInstanceImplementation = GetImplementationTypesFromAttribute(wellKnownTypesAggregation.FilterContainerInstanceImplementationAggregationAttribute); + FilterTransientScopeInstanceImplementation = GetImplementationTypesFromAttribute(wellKnownTypesAggregation.FilterTransientScopeInstanceImplementationAggregationAttribute); + FilterTransientScopeRootImplementation = GetImplementationTypesFromAttribute(wellKnownTypesAggregation.FilterTransientScopeRootImplementationAggregationAttribute); + FilterScopeRootImplementation = GetImplementationTypesFromAttribute(wellKnownTypesAggregation.FilterScopeRootImplementationAggregationAttribute); } } internal class ScopeTypesFromAttributes : ITypesFromAttributes { + private readonly INamedTypeSymbol? _rangeType; + private readonly INamedTypeSymbol? _containerType; + private readonly IValidateAttributes _validateAttributes; + protected readonly List _warnings = new(); + protected readonly List _errors = new(); + internal ScopeTypesFromAttributes( // parameter IReadOnlyList attributeData, + INamedTypeSymbol? rangeType, + INamedTypeSymbol? containerType, // dependencies + IValidateAttributes validateAttributes, WellKnownTypesAggregation wellKnownTypesAggregation, WellKnownTypesChoice wellKnownTypesChoice, WellKnownTypesMiscellaneous wellKnownTypesMiscellaneous) { + _rangeType = rangeType; + _containerType = containerType; + _validateAttributes = validateAttributes; AttributeDictionary = attributeData .GroupBy(ad => ad.AttributeClass, SymbolEqualityComparer.Default) .ToDictionary(g => g.Key, g => g); - Implementation = GetTypesFromAttribute(wellKnownTypesAggregation.ImplementationAggregationAttribute); - TransientAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.TransientAbstractionAggregationAttribute); - SyncTransientAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.SyncTransientAbstractionAggregationAttribute); - AsyncTransientAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.AsyncTransientAbstractionAggregationAttribute); + Implementation = GetImplementationTypesFromAttribute(wellKnownTypesAggregation.ImplementationAggregationAttribute); + TransientAbstraction = GetAbstractionTypesFromAttribute(wellKnownTypesAggregation.TransientAbstractionAggregationAttribute); + SyncTransientAbstraction = GetAbstractionTypesFromAttribute(wellKnownTypesAggregation.SyncTransientAbstractionAggregationAttribute); + AsyncTransientAbstraction = GetAbstractionTypesFromAttribute(wellKnownTypesAggregation.AsyncTransientAbstractionAggregationAttribute); ContainerInstanceAbstraction = ImmutableHashSet.Empty; TransientScopeInstanceAbstraction = ImmutableHashSet.Empty; - ScopeInstanceAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.ScopeInstanceAbstractionAggregationAttribute); + ScopeInstanceAbstraction = GetAbstractionTypesFromAttribute(wellKnownTypesAggregation.ScopeInstanceAbstractionAggregationAttribute); TransientScopeRootAbstraction = ImmutableHashSet.Empty; ScopeRootAbstraction = ImmutableHashSet.Empty; - DecoratorAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.DecoratorAbstractionAggregationAttribute); - CompositeAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.CompositeAbstractionAggregationAttribute); - TransientImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.TransientImplementationAggregationAttribute); - SyncTransientImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.SyncTransientImplementationAggregationAttribute); - AsyncTransientImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.AsyncTransientImplementationAggregationAttribute); + DecoratorAbstraction = GetAbstractionTypesFromAttribute(wellKnownTypesAggregation.DecoratorAbstractionAggregationAttribute); + CompositeAbstraction = GetAbstractionTypesFromAttribute(wellKnownTypesAggregation.CompositeAbstractionAggregationAttribute); + TransientImplementation = GetImplementationTypesFromAttribute(wellKnownTypesAggregation.TransientImplementationAggregationAttribute); + SyncTransientImplementation = GetImplementationTypesFromAttribute(wellKnownTypesAggregation.SyncTransientImplementationAggregationAttribute); + AsyncTransientImplementation = GetImplementationTypesFromAttribute(wellKnownTypesAggregation.AsyncTransientImplementationAggregationAttribute); ContainerInstanceImplementation = ImmutableHashSet.Empty; TransientScopeInstanceImplementation = ImmutableHashSet.Empty; - ScopeInstanceImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.ScopeInstanceImplementationAggregationAttribute); + ScopeInstanceImplementation = GetImplementationTypesFromAttribute(wellKnownTypesAggregation.ScopeInstanceImplementationAggregationAttribute); TransientScopeRootImplementation = ImmutableHashSet.Empty; ScopeRootImplementation = ImmutableHashSet.Empty; - FilterImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.FilterImplementationAggregationAttribute); - FilterTransientAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.FilterTransientAbstractionAggregationAttribute); - FilterSyncTransientAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.FilterSyncTransientAbstractionAggregationAttribute); - FilterAsyncTransientAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.FilterAsyncTransientAbstractionAggregationAttribute); + FilterImplementation = GetImplementationTypesFromAttribute(wellKnownTypesAggregation.FilterImplementationAggregationAttribute); + FilterTransientAbstraction = GetAbstractionTypesFromAttribute(wellKnownTypesAggregation.FilterTransientAbstractionAggregationAttribute); + FilterSyncTransientAbstraction = GetAbstractionTypesFromAttribute(wellKnownTypesAggregation.FilterSyncTransientAbstractionAggregationAttribute); + FilterAsyncTransientAbstraction = GetAbstractionTypesFromAttribute(wellKnownTypesAggregation.FilterAsyncTransientAbstractionAggregationAttribute); FilterContainerInstanceAbstraction = ImmutableHashSet.Empty; FilterTransientScopeInstanceAbstraction = ImmutableHashSet.Empty; - FilterScopeInstanceAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.FilterScopeInstanceAbstractionAggregationAttribute); + FilterScopeInstanceAbstraction = GetAbstractionTypesFromAttribute(wellKnownTypesAggregation.FilterScopeInstanceAbstractionAggregationAttribute); FilterTransientScopeRootAbstraction = ImmutableHashSet.Empty; FilterScopeRootAbstraction = ImmutableHashSet.Empty; - FilterDecoratorAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.FilterDecoratorAbstractionAggregationAttribute); - FilterCompositeAbstraction = GetTypesFromAttribute(wellKnownTypesAggregation.FilterCompositeAbstractionAggregationAttribute); - FilterTransientImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.FilterTransientImplementationAggregationAttribute); - FilterSyncTransientImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.FilterSyncTransientImplementationAggregationAttribute); - FilterAsyncTransientImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.FilterAsyncTransientImplementationAggregationAttribute); + FilterDecoratorAbstraction = GetAbstractionTypesFromAttribute(wellKnownTypesAggregation.FilterDecoratorAbstractionAggregationAttribute); + FilterCompositeAbstraction = GetAbstractionTypesFromAttribute(wellKnownTypesAggregation.FilterCompositeAbstractionAggregationAttribute); + FilterTransientImplementation = GetImplementationTypesFromAttribute(wellKnownTypesAggregation.FilterTransientImplementationAggregationAttribute); + FilterSyncTransientImplementation = GetImplementationTypesFromAttribute(wellKnownTypesAggregation.FilterSyncTransientImplementationAggregationAttribute); + FilterAsyncTransientImplementation = GetImplementationTypesFromAttribute(wellKnownTypesAggregation.FilterAsyncTransientImplementationAggregationAttribute); FilterContainerInstanceImplementation = ImmutableHashSet.Empty; FilterTransientScopeInstanceImplementation = ImmutableHashSet.Empty; - FilterScopeInstanceImplementation = GetTypesFromAttribute(wellKnownTypesAggregation.FilterScopeInstanceImplementationAggregationAttribute); + FilterScopeInstanceImplementation = GetImplementationTypesFromAttribute(wellKnownTypesAggregation.FilterScopeInstanceImplementationAggregationAttribute); FilterTransientScopeRootImplementation = ImmutableHashSet.Empty; FilterScopeRootImplementation = ImmutableHashSet.Empty; @@ -504,35 +520,66 @@ internal ScopeTypesFromAttributes( }) .OfType<(INamedTypeSymbol, IReadOnlyList)>()); - FilterImplementationChoices = GetTypesFromAttribute(wellKnownTypesChoice.FilterImplementationChoiceAttribute); + FilterImplementationChoices = GetImplementationTypesFromAttribute(wellKnownTypesChoice.FilterImplementationChoiceAttribute); - FilterImplementationCollectionChoices = GetTypesFromAttribute(wellKnownTypesChoice.FilterImplementationCollectionChoiceAttribute); + FilterImplementationCollectionChoices = GetImplementationTypesFromAttribute(wellKnownTypesChoice.FilterImplementationCollectionChoiceAttribute); } private IReadOnlyDictionary> AttributeDictionary { get; } - protected IImmutableSet GetTypesFromAttribute( + protected IImmutableSet GetAbstractionTypesFromAttribute( INamedTypeSymbol attribute) { return ImmutableHashSet.CreateRange( - (AttributeDictionary.TryGetValue(attribute, out var attributes) ? attributes : Enumerable.Empty()) - .SelectMany(ad => ad.ConstructorArguments - .Where(tc => tc.Kind == TypedConstantKind.Type) - .OfType() - .Concat(ad.ConstructorArguments.SelectMany(ca => ca.Kind is TypedConstantKind.Array - ? (IEnumerable)ca.Values - : Array.Empty()))) - .Select(tc => !CheckValidType(tc, out var type) ? null : type) - .Where(t => t is not null) - .OfType() - .Select(t => t.OriginalDefinition)); - - bool CheckValidType(TypedConstant typedConstant, out INamedTypeSymbol type) - { - type = (typedConstant.Value as INamedTypeSymbol)!; - return typedConstant.Value is not null; - } + GetTypesFromAttribute(attribute) + .Where(t => + { + var ret = _validateAttributes.ValidateAbstraction(t.Item2); + + _warnings.Add(Diagnostics.ValidationConfigurationAttribute( + t.Item1, + _rangeType, + _containerType, + $"Given type \"{t.Item2.FullName()}\" isn't a valid abstraction type. It'll be ignored.")); + + return ret; + }) + .Select(t => t.Item2)); } + + protected IImmutableSet GetImplementationTypesFromAttribute( + INamedTypeSymbol attribute) + { + return ImmutableHashSet.CreateRange( + GetTypesFromAttribute(attribute) + .Where(t => + { + var ret = _validateAttributes.ValidateImplementation(t.Item2); + + _warnings.Add(Diagnostics.ValidationConfigurationAttribute( + t.Item1, + _rangeType, + _containerType, + $"Given type \"{t.Item2.FullName()}\" isn't a valid implementation type. It'll be ignored.")); + + return ret; + }) + .Select(t => t.Item2)); + } + + private IEnumerable<(AttributeData, INamedTypeSymbol)> GetTypesFromAttribute( + INamedTypeSymbol attribute) => + (AttributeDictionary.TryGetValue(attribute, out var attributes) ? attributes : Enumerable.Empty()) + .SelectMany(ad => ad.ConstructorArguments + .Where(tc => tc.Kind == TypedConstantKind.Type) + .Select(tc => (ad, tc)) + .Concat(ad.ConstructorArguments.SelectMany(ca => ca.Kind is TypedConstantKind.Array + ? (IEnumerable<(AttributeData, TypedConstant)>)ca.Values.Select(tc => (ad, tc)) + : Array.Empty<(AttributeData, TypedConstant)>()))) + .Select(t => t.Item2.Value is INamedTypeSymbol type + ? (t.Item1, type.OriginalDefinition) + : ((AttributeData, INamedTypeSymbol)?)null) + .OfType<(AttributeData, INamedTypeSymbol)>(); public IImmutableSet Implementation { get; } public IImmutableSet TransientAbstraction { get; } @@ -592,4 +639,8 @@ bool CheckValidType(TypedConstant typedConstant, out INamedTypeSymbol type) public IImmutableSet FilterAssemblyImplementations { get; } public IImmutableSet FilterImplementationChoices { get; } public IImmutableSet FilterImplementationCollectionChoices { get; } + + public IReadOnlyList Warnings => _warnings; + + public IReadOnlyList Errors => _errors; } \ No newline at end of file diff --git a/Main/DiagLogger.cs b/Main/DiagLogger.cs index f707a687..66e393fe 100644 --- a/Main/DiagLogger.cs +++ b/Main/DiagLogger.cs @@ -3,7 +3,6 @@ internal interface IDiagLogger { void Error(DieException exception); - void Error(Diagnostic diagnostic); void Log(Diagnostic diagnostic); } @@ -26,24 +25,24 @@ public void Error(DieException exception) switch (exception) { case ImplementationCycleDieException implementationCycle: - _context.ReportDiagnostic(Diagnostics.CircularReferenceInsideFactory(implementationCycle)); + Log(Diagnostics.CircularReferenceInsideFactory(implementationCycle)); break; case FunctionCycleDieException: - _context.ReportDiagnostic(Diagnostics.CircularReferenceAmongFactories); + Log(Diagnostics.CircularReferenceAmongFactories); break; - case ValidationDieException: + case ValidationDieException validationDieException: + foreach (var error in validationDieException.Diagnostics) + Log(error); break; case CompilationDieException slippedResolution: - _context.ReportDiagnostic(slippedResolution.Diagnostic); + Log(slippedResolution.Diagnostic); break; default: - _context.ReportDiagnostic(Diagnostics.UnexpectedDieException(exception)); + Log(Diagnostics.UnexpectedDieException(exception)); break; } } - public void Error(Diagnostic diagnostic) => _context.ReportDiagnostic(diagnostic); - public void Log(Diagnostic diagnostic) { if (!_ignoreErrors || diagnostic.Severity != DiagnosticSeverity.Error) diff --git a/Main/Diagnostics.cs b/Main/Diagnostics.cs index 8b8d75a3..2984ca6c 100644 --- a/Main/Diagnostics.cs +++ b/Main/Diagnostics.cs @@ -1,3 +1,5 @@ +using MrMeeseeks.DIE.Extensions; + namespace MrMeeseeks.DIE; public static class Diagnostics @@ -68,6 +70,23 @@ public static Diagnostic ValidationUserDefinedElement(ISymbol userDefinedElement userDefinedElement.Locations.FirstOrDefault() ?? Location.None); } + public static Diagnostic ValidationConfigurationAttribute(AttributeData attributeData, INamedTypeSymbol? parentRange, INamedTypeSymbol? parentContainer, string specification) + { + var rangeDescription = parentRange is null && parentContainer is null + ? "assembly level" + : parentRange is null || parentContainer is null + ? "default Range" + : SymbolEqualityComparer.Default.Equals(parentRange, parentContainer) + ? $"parent-Container \"{parentContainer.Name}\"" + : $"Range \"{parentRange.Name}\" in parent-Container \"{parentContainer.Name}\""; + return Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_67_03", + "Validation (Configuration Attribute)", + $"The configuration attribute \"{attributeData.AttributeClass?.Name}\" (of {rangeDescription}) isn't validly defined: {specification}", + "Error", DiagnosticSeverity.Error, + true), + attributeData.GetLocation()); + } + public static Diagnostic UnexpectedDieException(DieException exception) { return Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_66_00", diff --git a/Main/ExecuteImpl.cs b/Main/ExecuteImpl.cs index aeef5bf3..82c4fb6e 100644 --- a/Main/ExecuteImpl.cs +++ b/Main/ExecuteImpl.cs @@ -82,21 +82,9 @@ public void Execute() } else { - throw new ValidationDieException(validationDiagnostics); } } - catch (ValidationDieException validationDieException) - { - if (_errorDescriptionInsteadOfBuildFailure) - _containerDieExceptionGenerator.Generate( - containerSymbol.ContainingNamespace.FullName(), - containerSymbol.Name, - validationDieException); - else - foreach (var validationDiagnostic in validationDieException.Diagnostics) - _diagLogger.Log(validationDiagnostic); - } catch (DieException dieException) { if (_errorDescriptionInsteadOfBuildFailure) @@ -109,12 +97,7 @@ public void Execute() } catch (Exception exception) { - if (_errorDescriptionInsteadOfBuildFailure) - { - // ignore - } - else - _diagLogger.Error(Diagnostics.UnexpectedException(exception)); + _diagLogger.Log(Diagnostics.UnexpectedException(exception)); } } } diff --git a/Main/ResolutionBuilding/ScopeManager.cs b/Main/ResolutionBuilding/ScopeManager.cs index 63e4e5fa..ce853762 100644 --- a/Main/ResolutionBuilding/ScopeManager.cs +++ b/Main/ResolutionBuilding/ScopeManager.cs @@ -40,7 +40,7 @@ private readonly Func< ICheckTypeProperties, IErrorContext, ITransientScopeResolutionBuilder> _transientScopeResolutionBuilderFactory; - private readonly Func, ScopeTypesFromAttributes> _scopeTypesFromAttributesFactory; + private readonly Func, ScopeTypesFromAttributes> _scopeTypesFromAttributesFactory; private readonly Func, ICheckTypeProperties> _checkTypePropertiesFactory; private readonly Func _userProvidedScopeElementsFactory; private readonly Lazy _defaultScopeBuilder; @@ -73,7 +73,7 @@ public ScopeManager( ICheckTypeProperties, IErrorContext, IScopeResolutionBuilder> scopeResolutionBuilderFactory, - Func, ScopeTypesFromAttributes> scopeTypesFromAttributesFactory, + Func, ScopeTypesFromAttributes> scopeTypesFromAttributesFactory, Func, ICheckTypeProperties> checkTypePropertiesFactory, Func userProvidedScopeElementsFactory, IUserDefinedElements emptyUserDefinedElements, @@ -92,7 +92,9 @@ public ScopeManager( () => { var defaultScopeType = containerInfo.ContainerType.GetTypeMembers(Constants.DefaultScopeName).FirstOrDefault(); - var defaultScopeTypesFromAttributes = _scopeTypesFromAttributesFactory(defaultScopeType?.GetAttributes() ?? ImmutableArray.Empty); + var defaultScopeTypesFromAttributes = _scopeTypesFromAttributesFactory( + defaultScopeType, + defaultScopeType?.GetAttributes() ?? ImmutableArray.Empty); return _scopeResolutionBuilderFactory( Constants.DefaultScopeName, _containerResolutionBuilder, @@ -109,7 +111,9 @@ defaultScopeType is {} () => { var defaultTransientScopeType = containerInfo.ContainerType.GetTypeMembers(Constants.DefaultTransientScopeName).FirstOrDefault(); - var defaultTransientScopeTypesFromAttributes = _scopeTypesFromAttributesFactory(defaultTransientScopeType?.GetAttributes() ?? ImmutableArray.Empty); + var defaultTransientScopeTypesFromAttributes = _scopeTypesFromAttributesFactory( + defaultTransientScopeType, + defaultTransientScopeType?.GetAttributes() ?? ImmutableArray.Empty); var ret = _transientScopeResolutionBuilderFactory( Constants.DefaultTransientScopeName, _containerResolutionBuilder, @@ -182,7 +186,7 @@ public IScopeResolutionBuilder GetScopeBuilder(INamedTypeSymbol scopeRootType) if (!_scopeRootTypeToScopeType.TryGetValue(scopeRootType, out var scopeType)) return _defaultScopeBuilder.Value; - var scopeTypesFromAttributes = _scopeTypesFromAttributesFactory(scopeType.GetAttributes()); + var scopeTypesFromAttributes = _scopeTypesFromAttributesFactory(scopeType, scopeType.GetAttributes()); var ret = _scopeResolutionBuilderFactory( scopeType.Name, _containerResolutionBuilder, @@ -203,7 +207,7 @@ public ITransientScopeResolutionBuilder GetTransientScopeBuilder(INamedTypeSymbo if (!_transientScopeRootTypeToScopeType.TryGetValue(transientScopeRootType, out var transientScopeType)) return _defaultTransientScopeBuilder.Value; - var scopeTypesFromAttributes = _scopeTypesFromAttributesFactory(transientScopeType.GetAttributes()); + var scopeTypesFromAttributes = _scopeTypesFromAttributesFactory(transientScopeType, transientScopeType.GetAttributes()); var ret = _transientScopeResolutionBuilderFactory( transientScopeType.Name, _containerResolutionBuilder, diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index 635a23a7..20e2307f 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -2,6 +2,7 @@ using MrMeeseeks.DIE.Configuration; using MrMeeseeks.DIE.ResolutionBuilding; using MrMeeseeks.DIE.ResolutionBuilding.Function; +using MrMeeseeks.DIE.Validation.Attributes; using MrMeeseeks.DIE.Validation.Range; using MrMeeseeks.DIE.Validation.Range.UserDefined; @@ -31,6 +32,7 @@ public void Execute(GeneratorExecutionContext context) var validateUserDefinedConstrParam = new ValidateUserDefinedConstrParam(wellKnownTypesMiscellaneous); var validateUserDefinedFactoryField = new ValidateUserDefinedFactoryField(); var validateUserDefinedFactoryMethod = new ValidateUserDefinedFactoryMethod(); + var validateAttributes = new ValidateAttributes(); var validateTransientScope = new ValidateTransientScope( validateUserDefinedAddForDisposalSync, validateUserDefinedAddForDisposalAsync, @@ -59,11 +61,23 @@ public void Execute(GeneratorExecutionContext context) validateUserDefinedFactoryField, wellKnownTypes, wellKnownTypesMiscellaneous); - var attributeTypesFromAttributes = new TypesFromAttributes( + var assemblyTypesFromAttributes = new TypesFromAttributes( context.Compilation.Assembly.GetAttributes(), + null, + null, + validateAttributes, wellKnownTypesAggregation, wellKnownTypesChoice, wellKnownTypesMiscellaneous); + + foreach (var diagnostic in assemblyTypesFromAttributes + .Warnings + .Concat(assemblyTypesFromAttributes.Errors)) + diagLogger.Log(diagnostic); + + if (assemblyTypesFromAttributes.Errors.Any()) + return; + var containerGenerator = new ContainerGenerator(context, diagLogger, ContainerCodeBuilderFactory, TransientScopeCodeBuilderFactory, ScopeCodeBuilderFactory); var referenceGeneratorFactory = new ReferenceGeneratorFactory(ReferenceGeneratorFactory); var containerDieExceptionGenerator = new ContainerDieExceptionGenerator(context, wellKnownTypesMiscellaneous); @@ -81,13 +95,24 @@ public void Execute(GeneratorExecutionContext context) IContainerResolutionBuilder ResolutionTreeFactory(IContainerInfo ci) { + var containerTypesFromAttributes = new TypesFromAttributes( + ci.ContainerType.GetAttributes(), + ci.ContainerType, + ci.ContainerType, + validateAttributes, + wellKnownTypesAggregation, + wellKnownTypesChoice, + wellKnownTypesMiscellaneous); + + foreach (var diagnostic in containerTypesFromAttributes.Warnings) + diagLogger.Log(diagnostic); + + if (containerTypesFromAttributes.Errors.Any()) + throw new ValidationDieException(containerTypesFromAttributes.Errors.ToImmutableArray()); + var containerTypesFromAttributesList = ImmutableList.Create( - (ITypesFromAttributes) attributeTypesFromAttributes, - new TypesFromAttributes( - ci.ContainerType.GetAttributes(), - wellKnownTypesAggregation, - wellKnownTypesChoice, - wellKnownTypesMiscellaneous)); + (ITypesFromAttributes) assemblyTypesFromAttributes, + containerTypesFromAttributes); var functionCycleTracker = new FunctionCycleTracker(); @@ -115,11 +140,25 @@ IScopeManager ScopeManagerFactory( containerTypesFromAttributesList, TransientScopeResolutionBuilderFactory, ScopeResolutionBuilderFactory, - ad => new ScopeTypesFromAttributes( - ad, - wellKnownTypesAggregation, - wellKnownTypesChoice, - wellKnownTypesMiscellaneous), + (rangeType, ad) => + { + var scopeTypesFromAttributes = new ScopeTypesFromAttributes( + ad, + rangeType, + ci.ContainerType, + validateAttributes, + wellKnownTypesAggregation, + wellKnownTypesChoice, + wellKnownTypesMiscellaneous); + + foreach (var diagnostic in scopeTypesFromAttributes.Warnings) + diagLogger.Log(diagnostic); + + if (scopeTypesFromAttributes.Errors.Any()) + throw new ValidationDieException(scopeTypesFromAttributes.Errors.ToImmutableArray()); + + return scopeTypesFromAttributes; + }, tfa => new CheckTypeProperties(new CurrentlyConsideredTypes(tfa, implementationTypeSetCache), wellKnownTypes), st => new UserDefinedElements(st, ci.ContainerType, wellKnownTypes, wellKnownTypesMiscellaneous), new EmptyUserDefinedElements(), diff --git a/Main/Validation/Attributes/ValidateAttributes.cs b/Main/Validation/Attributes/ValidateAttributes.cs new file mode 100644 index 00000000..f1ffabe2 --- /dev/null +++ b/Main/Validation/Attributes/ValidateAttributes.cs @@ -0,0 +1,17 @@ +namespace MrMeeseeks.DIE.Validation.Attributes; + +internal interface IValidateAttributes +{ + bool ValidateAbstraction(INamedTypeSymbol type); + bool ValidateImplementation(INamedTypeSymbol type); +} + +internal class ValidateAttributes : IValidateAttributes +{ + public bool ValidateAbstraction(INamedTypeSymbol type) => + type.TypeKind == TypeKind.Interface || type.IsReferenceType; + + public bool ValidateImplementation(INamedTypeSymbol type) => + type.IsValueType + || type.IsReferenceType && !type.IsAbstract && type.TypeKind != TypeKind.Interface; +} \ No newline at end of file From f647ea7cdd8e10b4897a31b13d3da65b433ef47b Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Mon, 1 Aug 2022 08:53:18 +0200 Subject: [PATCH 110/162] Fixed issue with situation "one implementation multiple decorated interfaces with each multiple decorators (sequences)" --- Main/Configuration/Attributes/Choice.cs | 4 +- Main/Configuration/CheckTypeProperties.cs | 25 ++++-- .../Configuration/CurrentlyConsideredTypes.cs | 51 +++++++---- Main/Configuration/TypesFromAttributes.cs | 31 ++++--- Test/Async/Wrapped/DecorationChaining.cs | 2 +- Test/Composite/Decorated.cs | 4 +- Test/Decorator/Multi.cs | 2 +- ...OneImplementationTwoDecoratedInterfaces.cs | 87 +++++++++++++++++++ Test/Decorator/SequenceEdgeCase.cs | 6 +- Test/Generics/Configuration/Decorator.cs | 2 +- .../InterfaceGenericDecorator.cs | 2 +- .../ScopeSpecificAttributes/Decorator.cs | 10 +-- 12 files changed, 174 insertions(+), 52 deletions(-) create mode 100644 Test/Decorator/OneImplementationTwoDecoratedInterfaces.cs diff --git a/Main/Configuration/Attributes/Choice.cs b/Main/Configuration/Attributes/Choice.cs index 18212036..8589c147 100644 --- a/Main/Configuration/Attributes/Choice.cs +++ b/Main/Configuration/Attributes/Choice.cs @@ -28,13 +28,13 @@ public FilterGenericParameterChoiceAttribute(Type unboundGenericType, string gen [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class DecoratorSequenceChoiceAttribute : Attribute { - public DecoratorSequenceChoiceAttribute(Type decoratedType, params Type[] types) {} + public DecoratorSequenceChoiceAttribute(Type interfaceType, Type decoratedType, params Type[] types) {} } [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class FilterDecoratorSequenceChoiceAttribute : Attribute { - public FilterDecoratorSequenceChoiceAttribute(Type decoratedType) {} + public FilterDecoratorSequenceChoiceAttribute(Type interfaceType, Type decoratedType) {} } [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] diff --git a/Main/Configuration/CheckTypeProperties.cs b/Main/Configuration/CheckTypeProperties.cs index 9e431fa7..e7465ebf 100644 --- a/Main/Configuration/CheckTypeProperties.cs +++ b/Main/Configuration/CheckTypeProperties.cs @@ -137,13 +137,26 @@ when typeToChoseFrom.InstanceConstructors.SingleOrDefault(c => c.Parameters.Leng public IReadOnlyList GetSequenceFor(INamedTypeSymbol interfaceType, INamedTypeSymbol implementationType) { IEnumerable sequence = Array.Empty(); - if (_currentlyConsideredTypes.DecoratorImplementationSequenceChoices.TryGetValue(implementationType.UnboundIfGeneric(), out var implementationSequence)) - sequence = implementationSequence; - else if (_currentlyConsideredTypes.DecoratorInterfaceSequenceChoices.TryGetValue(interfaceType.UnboundIfGeneric(), out var interfaceSequence)) - sequence = interfaceSequence; - else if (_currentlyConsideredTypes.InterfaceToDecorators.TryGetValue(interfaceType.UnboundIfGeneric(), out var allDecorators) - && allDecorators.Count == 1) + bool found = false; + if (_currentlyConsideredTypes.DecoratorSequenceChoices.TryGetValue(interfaceType.UnboundIfGeneric(), + out var sequenceMap)) + { + if (sequenceMap.TryGetValue(implementationType.UnboundIfGeneric(), out var implementationSequence)) + { + sequence = implementationSequence; + found = true; + } + else if (sequenceMap.TryGetValue(implementationType.UnboundIfGeneric(), out var interfaceSequence)) + { + sequence = interfaceSequence; + found = true; + } + } + + if (!found && _currentlyConsideredTypes.InterfaceToDecorators.TryGetValue(interfaceType.UnboundIfGeneric(), out var allDecorators) + && allDecorators.Count == 1) sequence = allDecorators; + return sequence .Select(imp => { diff --git a/Main/Configuration/CurrentlyConsideredTypes.cs b/Main/Configuration/CurrentlyConsideredTypes.cs index 7ddd14f0..47d98b89 100644 --- a/Main/Configuration/CurrentlyConsideredTypes.cs +++ b/Main/Configuration/CurrentlyConsideredTypes.cs @@ -17,8 +17,7 @@ internal interface ICurrentlyConsideredTypes IReadOnlyDictionary InterfaceToComposite { get; } IReadOnlyDictionary ImplementationToConstructorChoice { get; } IReadOnlyDictionary> InterfaceToDecorators { get; } - IReadOnlyDictionary> DecoratorInterfaceSequenceChoices { get; } - IReadOnlyDictionary> DecoratorImplementationSequenceChoices { get; } + IReadOnlyDictionary>> DecoratorSequenceChoices { get; } IReadOnlyDictionary> ImplementationMap { get; } IReadOnlyDictionary ImplementationToInitializer { get; } IReadOnlyDictionary<(INamedTypeSymbol, ITypeParameterSymbol), IReadOnlyList> GenericParameterSubstitutesChoices { get; } @@ -291,24 +290,28 @@ public CurrentlyConsideredTypes( }, SymbolEqualityComparer.Default) .ToDictionary(g => g.Key, g => (IReadOnlyList) g.ToList(), SymbolEqualityComparer.Default); - var decoratorSequenceChoices = new Dictionary>(SymbolEqualityComparer.Default); + var decoratorSequenceChoices = new Dictionary(SymbolEqualityComparer.Default); foreach (var types in typesFromAttributes) { - foreach (var filterDecoratorSequenceChoice in types.FilterDecoratorSequenceChoices) - decoratorSequenceChoices.Remove(filterDecoratorSequenceChoice); + foreach (var (interfaceType, decoratedType) in types.FilterDecoratorSequenceChoices) + if (decoratorSequenceChoices.TryGetValue(interfaceType, out var sequenceMap)) + sequenceMap.Remove(decoratedType); - foreach (var (decoratedType, decoratorSequence) in types.DecoratorSequenceChoices) - decoratorSequenceChoices[decoratedType] = decoratorSequence; + foreach (var (interfaceType, decoratedType, decoratorSequence) in types.DecoratorSequenceChoices) + { + if (!decoratorSequenceChoices.TryGetValue(interfaceType, out var sequenceMap)) + { + sequenceMap = new DecoratorSequenceMap(); + decoratorSequenceChoices[interfaceType] = sequenceMap; + } + sequenceMap.Add(decoratedType, decoratorSequence); + } } - DecoratorInterfaceSequenceChoices = decoratorSequenceChoices - .Where(kvp => kvp.Key.TypeKind == TypeKind.Interface) - .ToDictionary(kvp => kvp.Key, kvp => kvp.Value); - - DecoratorImplementationSequenceChoices = decoratorSequenceChoices - .Where(kvp => kvp.Key.TypeKind is TypeKind.Class or TypeKind.Struct) - .ToDictionary(kvp => kvp.Key, kvp => kvp.Value); + DecoratorSequenceChoices = decoratorSequenceChoices + .Where(kvp => kvp.Value.Any) + .ToDictionary(kvp => kvp.Key, kvp => kvp.Value.ToReadOnlyDictionary()); var initializers = new Dictionary(SymbolEqualityComparer.Default); @@ -459,8 +462,7 @@ IImmutableSet GetSetOfTypesWithProperties( public IReadOnlyDictionary InterfaceToComposite { get; } public IReadOnlyDictionary ImplementationToConstructorChoice { get; } public IReadOnlyDictionary> InterfaceToDecorators { get; } - public IReadOnlyDictionary> DecoratorInterfaceSequenceChoices { get; } - public IReadOnlyDictionary> DecoratorImplementationSequenceChoices { get; } + public IReadOnlyDictionary>> DecoratorSequenceChoices { get; } public IReadOnlyDictionary> ImplementationMap { get; } public IReadOnlyDictionary ImplementationToInitializer { get; } public IReadOnlyDictionary<(INamedTypeSymbol, ITypeParameterSymbol), IReadOnlyList> GenericParameterSubstitutesChoices { get; } @@ -468,4 +470,21 @@ IImmutableSet GetSetOfTypesWithProperties( public IReadOnlyDictionary> PropertyChoices { get; } public IReadOnlyDictionary ImplementationChoices { get; } public IReadOnlyDictionary> ImplementationCollectionChoices { get; } + + private class DecoratorSequenceMap + { + private readonly Dictionary> _map = new(SymbolEqualityComparer.Default); + + public void Add(INamedTypeSymbol decoratedType, IReadOnlyList decoratorSequence) => + _map[decoratedType] = decoratorSequence; + + public void Remove(INamedTypeSymbol decoratedType) => + _map.Remove(decoratedType); + + public bool Any => + _map.Any(); + + public IReadOnlyDictionary> ToReadOnlyDictionary() => + _map; + } } \ No newline at end of file diff --git a/Main/Configuration/TypesFromAttributes.cs b/Main/Configuration/TypesFromAttributes.cs index 1ed77f61..889c86e9 100644 --- a/Main/Configuration/TypesFromAttributes.cs +++ b/Main/Configuration/TypesFromAttributes.cs @@ -24,7 +24,7 @@ internal interface ITypesFromAttributes IImmutableSet ScopeInstanceImplementation { get; } IImmutableSet TransientScopeRootImplementation { get; } IImmutableSet ScopeRootImplementation { get; } - IImmutableSet<(INamedTypeSymbol, IReadOnlyList)> DecoratorSequenceChoices { get; } + IImmutableSet<(INamedTypeSymbol, INamedTypeSymbol, IReadOnlyList)> DecoratorSequenceChoices { get; } IImmutableSet<(INamedTypeSymbol, IMethodSymbol)> ConstructorChoices { get; } IImmutableSet<(INamedTypeSymbol, IMethodSymbol)> TypeInitializers { get; } IImmutableSet<(INamedTypeSymbol, ITypeParameterSymbol, IReadOnlyList)> GenericParameterSubstitutesChoices { get; } @@ -53,7 +53,7 @@ internal interface ITypesFromAttributes IImmutableSet FilterScopeInstanceImplementation { get; } IImmutableSet FilterTransientScopeRootImplementation { get; } IImmutableSet FilterScopeRootImplementation { get; } - IImmutableSet FilterDecoratorSequenceChoices { get; } + IImmutableSet<(INamedTypeSymbol, INamedTypeSymbol)> FilterDecoratorSequenceChoices { get; } IImmutableSet FilterConstructorChoices { get; } IImmutableSet FilterTypeInitializers { get; } IImmutableSet<(INamedTypeSymbol, ITypeParameterSymbol)> FilterGenericParameterSubstitutesChoices { get; } @@ -172,21 +172,22 @@ internal ScopeTypesFromAttributes( : Enumerable.Empty()) .Select(ad => { - if (ad.ConstructorArguments.Length < 2) + if (ad.ConstructorArguments.Length < 3) return null; - var decoratedType = ad.ConstructorArguments[0].Value as INamedTypeSymbol; + var interfaceType = ad.ConstructorArguments[0].Value as INamedTypeSymbol; + var decoratedType = ad.ConstructorArguments[1].Value as INamedTypeSymbol; var decorators = ad - .ConstructorArguments[1] + .ConstructorArguments[2] .Values .Select(tc => tc.Value) .OfType() .ToList(); - return decoratedType is null + return decoratedType is null || interfaceType is null ? null - : ((INamedTypeSymbol, IReadOnlyList)?) (decoratedType, decorators); + : ((INamedTypeSymbol, INamedTypeSymbol, IReadOnlyList)?) (interfaceType, decoratedType, decorators); }) - .OfType<(INamedTypeSymbol, IReadOnlyList)>()); + .OfType<(INamedTypeSymbol, INamedTypeSymbol, IReadOnlyList)>()); FilterDecoratorSequenceChoices = ImmutableHashSet.CreateRange( (AttributeDictionary.TryGetValue(wellKnownTypesChoice.FilterDecoratorSequenceChoiceAttribute, out var filterDecoratorSequenceChoiceAttributes) @@ -194,12 +195,14 @@ internal ScopeTypesFromAttributes( : Enumerable.Empty()) .Select(ad => { - if (ad.ConstructorArguments.Length != 1) - return null; + if (ad.ConstructorArguments.Length != 2 + || ad.ConstructorArguments[0].Value is not INamedTypeSymbol interfaceType + || ad.ConstructorArguments[1].Value is not INamedTypeSymbol decoratedType) + return ((INamedTypeSymbol, INamedTypeSymbol)?) null; - return ad.ConstructorArguments[0].Value as INamedTypeSymbol; + return (interfaceType, decoratedType); }) - .OfType()); + .OfType<(INamedTypeSymbol, INamedTypeSymbol)>()); ConstructorChoices = ImmutableHashSet.CreateRange( (AttributeDictionary.TryGetValue(wellKnownTypesChoice.ConstructorChoiceAttribute, out var constructorChoiceAttributes) @@ -600,7 +603,7 @@ protected IImmutableSet GetImplementationTypesFromAttribute( public IImmutableSet ScopeInstanceImplementation { get; } public IImmutableSet TransientScopeRootImplementation { get; protected init; } public IImmutableSet ScopeRootImplementation { get; protected init; } - public IImmutableSet<(INamedTypeSymbol, IReadOnlyList)> DecoratorSequenceChoices { get; } + public IImmutableSet<(INamedTypeSymbol, INamedTypeSymbol, IReadOnlyList)> DecoratorSequenceChoices { get; } public IImmutableSet<(INamedTypeSymbol, IMethodSymbol)> ConstructorChoices { get; } public IImmutableSet<(INamedTypeSymbol, IMethodSymbol)> TypeInitializers { get; } public IImmutableSet<(INamedTypeSymbol, ITypeParameterSymbol, IReadOnlyList)> GenericParameterSubstitutesChoices { get; } @@ -629,7 +632,7 @@ protected IImmutableSet GetImplementationTypesFromAttribute( public IImmutableSet FilterScopeInstanceImplementation { get; } public IImmutableSet FilterTransientScopeRootImplementation { get; protected init; } public IImmutableSet FilterScopeRootImplementation { get; protected init; } - public IImmutableSet FilterDecoratorSequenceChoices { get; } + public IImmutableSet<(INamedTypeSymbol, INamedTypeSymbol)> FilterDecoratorSequenceChoices { get; } public IImmutableSet FilterConstructorChoices { get; } public IImmutableSet FilterTypeInitializers { get; } public IImmutableSet<(INamedTypeSymbol, ITypeParameterSymbol)> FilterGenericParameterSubstitutesChoices { get; } diff --git a/Test/Async/Wrapped/DecorationChaining.cs b/Test/Async/Wrapped/DecorationChaining.cs index a13f9b40..a70d2503 100644 --- a/Test/Async/Wrapped/DecorationChaining.cs +++ b/Test/Async/Wrapped/DecorationChaining.cs @@ -48,7 +48,7 @@ async ValueTask IValueTaskTypeInitializer.InitializeAsync() } [CreateFunction(typeof(Task), "Create")] -[DecoratorSequenceChoice(typeof(IInterface), typeof(DecoratorA), typeof(DecoratorB))] +[DecoratorSequenceChoice(typeof(IInterface), typeof(IInterface), typeof(DecoratorA), typeof(DecoratorB))] internal sealed partial class Container { } diff --git a/Test/Composite/Decorated.cs b/Test/Composite/Decorated.cs index 8394aa0c..9022d72f 100644 --- a/Test/Composite/Decorated.cs +++ b/Test/Composite/Decorated.cs @@ -52,8 +52,8 @@ public Composite(IReadOnlyList composites) => public IInterface Decorated => this; } -[DecoratorSequenceChoice(typeof(IInterface), typeof(DecoratorA), typeof(DecoratorB))] -[DecoratorSequenceChoice(typeof(Composite), typeof(DecoratorB))] +[DecoratorSequenceChoice(typeof(IInterface), typeof(IInterface), typeof(DecoratorA), typeof(DecoratorB))] +[DecoratorSequenceChoice(typeof(IInterface), typeof(Composite), typeof(DecoratorB))] [CreateFunction(typeof(IInterface), "CreateDep")] [CreateFunction(typeof(IReadOnlyList), "CreateCollection")] internal sealed partial class Container diff --git a/Test/Decorator/Multi.cs b/Test/Decorator/Multi.cs index e481449e..ea365fe5 100644 --- a/Test/Decorator/Multi.cs +++ b/Test/Decorator/Multi.cs @@ -31,7 +31,7 @@ public DecoratorB(IInterface decorated) => } [CreateFunction(typeof(IInterface), "Create")] -[DecoratorSequenceChoice(typeof(IInterface), typeof(DecoratorA), typeof(DecoratorB))] +[DecoratorSequenceChoice(typeof(IInterface), typeof(IInterface), typeof(DecoratorA), typeof(DecoratorB))] internal sealed partial class Container { diff --git a/Test/Decorator/OneImplementationTwoDecoratedInterfaces.cs b/Test/Decorator/OneImplementationTwoDecoratedInterfaces.cs new file mode 100644 index 00000000..5df7c80d --- /dev/null +++ b/Test/Decorator/OneImplementationTwoDecoratedInterfaces.cs @@ -0,0 +1,87 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Decorator.OneImplementationTwoDecoratedInterfaces; + +internal interface IInterfaceA +{ + IInterfaceA DecoratedA { get; } +} + +internal interface IInterfaceB +{ + IInterfaceB DecoratedB { get; } +} + +internal class Dependency : IInterfaceA, IInterfaceB +{ + public IInterfaceA DecoratedA => this; + public IInterfaceB DecoratedB => this; +} + +internal class DecoratorAA : IInterfaceA, IDecorator +{ + public IInterfaceA DecoratedA { get; } + + internal DecoratorAA(IInterfaceA decorated) => DecoratedA = decorated; +} + +internal class DecoratorAB : IInterfaceA, IDecorator +{ + public IInterfaceA DecoratedA { get; } + + internal DecoratorAB(IInterfaceA decorated) => DecoratedA = decorated; +} + +internal class DecoratorBA : IInterfaceB, IDecorator +{ + public IInterfaceB DecoratedB { get; } + + internal DecoratorBA(IInterfaceB decorated) => DecoratedB = decorated; +} + +internal class DecoratorBB : IInterfaceB, IDecorator +{ + public IInterfaceB DecoratedB { get; } + + internal DecoratorBB(IInterfaceB decorated) => DecoratedB = decorated; +} + +internal class Parent +{ + public IInterfaceA DependencyA { get; } + public IInterfaceB DependencyB { get; } + + internal Parent( + IInterfaceA dependencyA, + IInterfaceB dependencyB) + { + DependencyA = dependencyA; + DependencyB = dependencyB; + } +} + + +[CreateFunction(typeof(Parent), "Create")] +[DecoratorSequenceChoice(typeof(IInterfaceA), typeof(Dependency), typeof(DecoratorAA), typeof(DecoratorAB))] +[DecoratorSequenceChoice(typeof(IInterfaceB), typeof(Dependency), typeof(DecoratorBA), typeof(DecoratorBB))] +internal sealed partial class Container +{ +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var parent = container.Create(); + Assert.IsType(parent.DependencyA.DecoratedA); + Assert.IsType(parent.DependencyA.DecoratedA.DecoratedA); + Assert.IsType(parent.DependencyA.DecoratedA.DecoratedA.DecoratedA); + Assert.IsType(parent.DependencyB.DecoratedB); + Assert.IsType(parent.DependencyB.DecoratedB.DecoratedB); + Assert.IsType(parent.DependencyB.DecoratedB.DecoratedB.DecoratedB); + } +} \ No newline at end of file diff --git a/Test/Decorator/SequenceEdgeCase.cs b/Test/Decorator/SequenceEdgeCase.cs index f62bedb0..18b6922b 100644 --- a/Test/Decorator/SequenceEdgeCase.cs +++ b/Test/Decorator/SequenceEdgeCase.cs @@ -45,17 +45,17 @@ internal class ScopeRoot1 : IScopeRoot [CreateFunction(typeof(ScopeRoot0), "Create0")] [CreateFunction(typeof(ScopeRoot1), "Create1")] [CreateFunction(typeof(IInterface), "CreateFromContainerAsSanityCheck")] -[DecoratorSequenceChoice(typeof(IInterface))] +[DecoratorSequenceChoice(typeof(IInterface), typeof(IInterface))] internal sealed partial class Container { - [DecoratorSequenceChoice(typeof(IInterface), typeof(DecoratorA), typeof(DecoratorB))] + [DecoratorSequenceChoice(typeof(IInterface), typeof(IInterface), typeof(DecoratorA), typeof(DecoratorB))] [CustomScopeForRootTypes(typeof(ScopeRoot0))] private sealed partial class DIE_Scope_0 { } - [DecoratorSequenceChoice(typeof(IInterface), typeof(DecoratorA))] + [DecoratorSequenceChoice(typeof(IInterface), typeof(IInterface), typeof(DecoratorA))] [CustomScopeForRootTypes(typeof(ScopeRoot1))] private sealed partial class DIE_Scope_1 { diff --git a/Test/Generics/Configuration/Decorator.cs b/Test/Generics/Configuration/Decorator.cs index e6b1f9f4..d8eaf8ab 100644 --- a/Test/Generics/Configuration/Decorator.cs +++ b/Test/Generics/Configuration/Decorator.cs @@ -34,7 +34,7 @@ internal DecoratorB( [GenericParameterChoice(typeof(DecoratorA<>), "T0", typeof(int))] [GenericParameterChoice(typeof(DecoratorB<>), "T0", typeof(string))] -[DecoratorSequenceChoice(typeof(IInterface), typeof(DecoratorA<>), typeof(DecoratorB<>))] +[DecoratorSequenceChoice(typeof(IInterface), typeof(IInterface), typeof(DecoratorA<>), typeof(DecoratorB<>))] [CreateFunction(typeof(IInterface), "Create")] internal sealed partial class Container { diff --git a/Test/Generics/Configuration/InterfaceGenericDecorator.cs b/Test/Generics/Configuration/InterfaceGenericDecorator.cs index 3569137e..5310006e 100644 --- a/Test/Generics/Configuration/InterfaceGenericDecorator.cs +++ b/Test/Generics/Configuration/InterfaceGenericDecorator.cs @@ -34,7 +34,7 @@ internal DecoratorB( [GenericParameterChoice(typeof(DecoratorA<,>), "T0", typeof(int))] [GenericParameterChoice(typeof(DecoratorB<,>), "T0", typeof(string))] -[DecoratorSequenceChoice(typeof(IInterface<>), typeof(DecoratorA<,>), typeof(DecoratorB<,>))] +[DecoratorSequenceChoice(typeof(IInterface<>), typeof(IInterface<>), typeof(DecoratorA<,>), typeof(DecoratorB<,>))] [CreateFunction(typeof(IInterface), "Create")] internal sealed partial class Container { diff --git a/Test/Scoping/ScopeSpecificAttributes/Decorator.cs b/Test/Scoping/ScopeSpecificAttributes/Decorator.cs index 948fda17..bcc85d14 100644 --- a/Test/Scoping/ScopeSpecificAttributes/Decorator.cs +++ b/Test/Scoping/ScopeSpecificAttributes/Decorator.cs @@ -94,29 +94,29 @@ internal ScopeRoot(IInterface dep) [CreateFunction(typeof(TransientScopeRootSpecific), "Create2")] [CreateFunction(typeof(ScopeRoot), "Create3")] [CreateFunction(typeof(ScopeRootSpecific), "Create4")] -[DecoratorSequenceChoice(typeof(IInterface), typeof(ContainerDecorator))] +[DecoratorSequenceChoice(typeof(IInterface), typeof(IInterface), typeof(ContainerDecorator))] internal sealed partial class Container { - [DecoratorSequenceChoice(typeof(IInterface), typeof(TransientScopeDecorator))] + [DecoratorSequenceChoice(typeof(IInterface), typeof(IInterface), typeof(TransientScopeDecorator))] private sealed partial class DIE_DefaultTransientScope { } - [DecoratorSequenceChoice(typeof(IInterface), typeof(TransientScopeSpecificDecorator))] + [DecoratorSequenceChoice(typeof(IInterface), typeof(IInterface), typeof(TransientScopeSpecificDecorator))] [CustomScopeForRootTypes(typeof(TransientScopeRootSpecific))] private sealed partial class DIE_TransientScope_A { } - [DecoratorSequenceChoice(typeof(IInterface), typeof(ScopeDecorator))] + [DecoratorSequenceChoice(typeof(IInterface), typeof(IInterface), typeof(ScopeDecorator))] private sealed partial class DIE_DefaultScope { } - [DecoratorSequenceChoice(typeof(IInterface), typeof(ScopeSpecificDecorator))] + [DecoratorSequenceChoice(typeof(IInterface), typeof(IInterface), typeof(ScopeSpecificDecorator))] [CustomScopeForRootTypes(typeof(ScopeRootSpecific))] private sealed partial class DIE_Scope_A { From 949e073f8963812f11c4dada9e42475823fb34b8 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Mon, 1 Aug 2022 11:17:45 +0200 Subject: [PATCH 111/162] Build a test for the reduction case --- .../ContainerResolutionBuilder.cs | 58 +++++++---------- ...ontainerCreateFunctionResolutionBuilder.cs | 54 --------------- .../Function/FunctionResolutionBuilder.cs | 3 +- Main/SourceGenerator.cs | 12 ---- Test/Func/ReductionCase.cs | 65 +++++++++++++++++++ 5 files changed, 89 insertions(+), 103 deletions(-) delete mode 100644 Main/ResolutionBuilding/Function/ContainerCreateFunctionResolutionBuilder.cs create mode 100644 Test/Func/ReductionCase.cs diff --git a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs index c5a58a28..adcd51a7 100644 --- a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs @@ -18,10 +18,9 @@ internal class ContainerResolutionBuilder : RangeResolutionBaseBuilder, IContain { private readonly ITransientScopeInterfaceResolutionBuilder _transientScopeInterfaceResolutionBuilder; private readonly WellKnownTypes _wellKnownTypes; - private readonly Func _createFunctionResolutionBuilderFactory; private readonly Func _synchronicityDecisionMakerFactory; - private readonly List<(IContainerCreateFunctionResolutionBuilder CreateFunction, string MethodNamePrefix)> _rootResolutions = new (); + private readonly List<(IFunctionResolutionBuilder CreateFunction, string MethodNamePrefix)> _rootResolutions = new (); private readonly string _transientScopeAdapterReference; private readonly IScopeManager _scopeManager; @@ -37,7 +36,6 @@ internal ContainerResolutionBuilder( ICheckTypeProperties checkTypeProperties, WellKnownTypes wellKnownTypes, Func scopeManagerFactory, - Func createFunctionResolutionBuilderFactory, Func rangedFunctionGroupResolutionBuilderFactory, Func synchronicityDecisionMakerFactory, Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory, @@ -55,7 +53,6 @@ internal ContainerResolutionBuilder( { _transientScopeInterfaceResolutionBuilder = transientScopeInterfaceResolutionBuilder; _wellKnownTypes = wellKnownTypes; - _createFunctionResolutionBuilderFactory = createFunctionResolutionBuilderFactory; _synchronicityDecisionMakerFactory = synchronicityDecisionMakerFactory; FunctionCycleTracker = functionCycleTracker; _scopeManager = scopeManagerFactory(this, transientScopeInterfaceResolutionBuilder); @@ -71,7 +68,7 @@ internal ContainerResolutionBuilder( public void AddCreateResolveFunctions(IReadOnlyList<(INamedTypeSymbol, string)> createFunctionData) { foreach (var (typeSymbol, methodNamePrefix) in createFunctionData) - _rootResolutions.Add((_createFunctionResolutionBuilderFactory(this, typeSymbol), methodNamePrefix)); + _rootResolutions.Add((CreateLocalFunctionResolution(typeSymbol, ImmutableSortedDictionary.Empty), methodNamePrefix)); } public MultiSynchronicityFunctionCallResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter, string containerReference) => @@ -132,7 +129,7 @@ public void DoWork() { while (HasWorkToDo) { - foreach ((IContainerCreateFunctionResolutionBuilder createFunction, _) in _rootResolutions.Where(r => r.CreateFunction.HasWorkToDo).ToList()) + foreach ((IFunctionResolutionBuilder createFunction, _) in _rootResolutions.Where(r => r.CreateFunction.HasWorkToDo).ToList()) { createFunction.DoWork(); } @@ -145,20 +142,20 @@ public void DoWork() public ContainerResolution Build() { + var localFunctions = LocalFunctions + .Values + .Select(lf => lf.Build()) + .Select(f => new LocalFunctionResolution( + f.Reference, + f.TypeFullName, + f.Resolvable, + f.Parameter, + f.SynchronicityDecision)) + .ToList(); + var rootFunctions = new List(); foreach (var (createFunction, methodNamePrefix) in _rootResolutions) { - var privateFunctionResolution = createFunction.Build(); - var privateRootResolutionFunction = new RootResolutionFunction( - privateFunctionResolution.Reference, - privateFunctionResolution.TypeFullName, - "private", - privateFunctionResolution.Resolvable, - privateFunctionResolution.Parameter, - privateFunctionResolution.SynchronicityDecision); - - rootFunctions.Add(privateRootResolutionFunction); - // Create function stays sync if (createFunction.OriginalReturnType.Equals( createFunction.ActualReturnType, @@ -172,10 +169,10 @@ public ContainerResolution Build() call.AsyncValueTask.Await = false; var publicSyncResolutionFunction = new RootResolutionFunction( $"{methodNamePrefix}{Constants.CreateFunctionSuffix}", - privateRootResolutionFunction.TypeFullName, + createFunction.OriginalReturnType.FullName(), "public", call, - privateRootResolutionFunction.Parameter, + createFunction.Parameters, SynchronicityDecision.Sync); rootFunctions.Add(publicSyncResolutionFunction); @@ -199,7 +196,7 @@ public ContainerResolution Build() taskCall, wrappedTaskReference, boundTaskTypeFullName), - privateRootResolutionFunction.Parameter, + createFunction.Parameters, SynchronicityDecision.Sync); rootFunctions.Add(publicTaskResolutionFunction); @@ -223,7 +220,7 @@ public ContainerResolution Build() valueTaskCall, wrappedValueTaskReference, boundValueTaskTypeFullName), - privateRootResolutionFunction.Parameter, + createFunction.Parameters, SynchronicityDecision.Sync); rootFunctions.Add(publicValueTaskResolutionFunction); @@ -243,7 +240,7 @@ public ContainerResolution Build() actual.FullName(), "public", call, - privateRootResolutionFunction.Parameter, + createFunction.Parameters, SynchronicityDecision.Sync); rootFunctions.Add(publicTaskResolutionFunction); @@ -267,7 +264,7 @@ public ContainerResolution Build() valueCall, wrappedValueTaskReference, boundValueTaskTypeFullName), - privateRootResolutionFunction.Parameter, + createFunction.Parameters, SynchronicityDecision.Sync); rootFunctions.Add(publicValueTaskResolutionFunction); @@ -295,7 +292,7 @@ public ContainerResolution Build() call, wrappedTaskReference, boundTaskTypeFullName), - privateRootResolutionFunction.Parameter, + createFunction.Parameters, SynchronicityDecision.Sync); rootFunctions.Add(publicTaskResolutionFunction); @@ -311,23 +308,12 @@ public ContainerResolution Build() actual1.FullName(), "public", valueCall, - privateRootResolutionFunction.Parameter, + createFunction.Parameters, SynchronicityDecision.Sync); rootFunctions.Add(publicValueTaskResolutionFunction); } } - - var localFunctions = LocalFunctions - .Values - .Select(lf => lf.Build()) - .Select(f => new LocalFunctionResolution( - f.Reference, - f.TypeFullName, - f.Resolvable, - f.Parameter, - f.SynchronicityDecision)) - .ToList(); var (transientScopeResolutions, scopeResolutions) = _scopeManager.Build(); diff --git a/Main/ResolutionBuilding/Function/ContainerCreateFunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/ContainerCreateFunctionResolutionBuilder.cs deleted file mode 100644 index 676b2f35..00000000 --- a/Main/ResolutionBuilding/Function/ContainerCreateFunctionResolutionBuilder.cs +++ /dev/null @@ -1,54 +0,0 @@ -namespace MrMeeseeks.DIE.ResolutionBuilding.Function; - -internal interface IContainerCreateFunctionResolutionBuilder : IFunctionResolutionBuilder -{ -} - -internal class ContainerCreateFunctionResolutionBuilder : FunctionResolutionBuilder, IContainerCreateFunctionResolutionBuilder -{ - private readonly INamedTypeSymbol _returnType; - - public ContainerCreateFunctionResolutionBuilder( - // parameter - IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, - INamedTypeSymbol returnType, - IFunctionResolutionSynchronicityDecisionMaker synchronicityDecisionMaker, - - // dependencies - WellKnownTypes wellKnownTypes, - IReferenceGeneratorFactory referenceGeneratorFactory, - IFunctionCycleTracker functionCycleTracker) - : base( - rangeResolutionBaseBuilder, - returnType, - ImmutableSortedDictionary.Empty, - synchronicityDecisionMaker, - new object(), - - wellKnownTypes, - referenceGeneratorFactory, - functionCycleTracker) - { - _returnType = returnType; - - Name = RootReferenceGenerator.Generate("Create"); - } - - protected override string Name { get; } - - protected override Resolvable CreateResolvable() => SwitchType(new SwitchTypeParameter( - _returnType, - ImmutableSortedDictionary.Empty, - ImmutableStack.Empty)).Item1; - - public override FunctionResolution Build() - { - AdjustForSynchronicity(); - return new( - Name, - TypeFullName, - Resolvable.Value, - Array.Empty(), - SynchronicityDecision.Value); - } -} \ No newline at end of file diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs index 4c725b19..e3210f90 100644 --- a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs @@ -43,6 +43,7 @@ internal interface IFunctionResolutionBuilder : IResolutionBuilder Parameters { get; } IReadOnlyList<(ITypeSymbol, ParameterResolution)> CurrentParameters { get; } MultiSynchronicityFunctionCallResolution BuildFunctionCall( @@ -76,7 +77,7 @@ internal abstract partial class FunctionResolutionBuilder : IFunctionResolutionB public IReadOnlyList<(ITypeSymbol, ParameterResolution)> CurrentParameters { get; } - protected IReadOnlyList Parameters { get; } + public IReadOnlyList Parameters { get; } public INamedTypeSymbol OriginalReturnType { get; } public INamedTypeSymbol? ActualReturnType { get; protected set; } diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index 20e2307f..ce8c1156 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -124,7 +124,6 @@ IContainerResolutionBuilder ResolutionTreeFactory(IContainerInfo ci) new CheckTypeProperties(new CurrentlyConsideredTypes(containerTypesFromAttributesList, implementationTypeSetCache), wellKnownTypes), wellKnownTypes, ScopeManagerFactory, - ContainerCreateFunctionResolutionBuilderFactory, RangedFunctionGroupResolutionBuilderFactory, FunctionResolutionSynchronicityDecisionMakerFactory, LocalFunctionResolutionBuilderFactory, @@ -222,17 +221,6 @@ ILocalFunctionResolutionBuilder LocalFunctionResolutionBuilderFactory( referenceGeneratorFactory, functionCycleTracker); - IContainerCreateFunctionResolutionBuilder ContainerCreateFunctionResolutionBuilderFactory( - IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, - INamedTypeSymbol returnType) => new ContainerCreateFunctionResolutionBuilder( - rangeResolutionBaseBuilder, - returnType, - FunctionResolutionSynchronicityDecisionMakerFactory(), - - wellKnownTypes, - referenceGeneratorFactory, - functionCycleTracker); - IScopeRootCreateFunctionResolutionBuilder ScopeRootCreateFunctionResolutionBuilderFactory( IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, SwitchImplementationParameter parameter) => new ScopeRootCreateFunctionResolutionBuilder( diff --git a/Test/Func/ReductionCase.cs b/Test/Func/ReductionCase.cs new file mode 100644 index 00000000..7a6161b5 --- /dev/null +++ b/Test/Func/ReductionCase.cs @@ -0,0 +1,65 @@ +using System; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Func.ReductionCase; + +internal class DependencyA +{ + public int Value { get; } + public DependencyB Dependency { get; } + + internal DependencyA( + int value, + Func dependencyB) + { + Value = value; + Dependency = dependencyB(23); + } +} + + +internal class DependencyB +{ + private readonly Lazy _parentFactory; + public int Value { get; } + public Parent Parent => _parentFactory.Value; + + internal DependencyB( + int value, + Lazy parentFactory) + { + _parentFactory = parentFactory; + Value = value; + } +} + +internal class Parent +{ + public DependencyA Dependency { get; } + + internal Parent( + DependencyA dependencyA) => + Dependency = dependencyA; +} + +[CreateFunction(typeof(Parent), "Create")] +internal sealed partial class Container +{ + private int DIE_Factory_int => 0; +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var parent = container.Create(); + Assert.IsType(parent); + Assert.True(0 == parent.Dependency.Value); + Assert.True(23 == parent.Dependency.Dependency.Value); + Assert.True(0 == parent.Dependency.Dependency.Parent.Dependency.Value); + } +} From 8dd71c6faa45370b231454d7fb369186ae90b2de Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Mon, 1 Aug 2022 12:00:49 +0200 Subject: [PATCH 112/162] Same with transient scope instances --- .../Function/FunctionResolutionBuilder.cs | 4 -- ...ransientScopeInterfaceResolutionBuilder.cs | 8 ++- .../TransientScopeResolutionBuilder.cs | 2 +- Test/Func/ReductionCaseTransientScope.cs | 65 +++++++++++++++++++ 4 files changed, 71 insertions(+), 8 deletions(-) create mode 100644 Test/Func/ReductionCaseTransientScope.cs diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs index e3210f90..fc74aa9c 100644 --- a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs @@ -49,8 +49,6 @@ internal interface IFunctionResolutionBuilder : IResolutionBuilder currentParameters, string? ownerReference); - - MethodGroupResolution BuildMethodGroup(); } internal abstract partial class FunctionResolutionBuilder : IFunctionResolutionBuilder @@ -983,8 +981,6 @@ public MultiSynchronicityFunctionCallResolution BuildFunctionCall( (p, cp) => (p.Reference, cp.Value.Item2.Reference)).ToList(); } - public MethodGroupResolution BuildMethodGroup() => new (Name, TypeFullName, null); - public bool HasWorkToDo => !Resolvable.IsValueCreated; protected abstract Resolvable CreateResolvable(); diff --git a/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs b/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs index cdeb203e..43f64c30 100644 --- a/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs +++ b/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs @@ -4,6 +4,7 @@ namespace MrMeeseeks.DIE.ResolutionBuilding; internal interface ITransientScopeInterfaceResolutionBuilder { + string Name { get; } void AddImplementation(ITransientScopeImplementationResolutionBuilder implementation); MultiSynchronicityFunctionCallResolution CreateTransientScopeInstanceReferenceResolution( ForConstructorParameter parameter, @@ -33,7 +34,6 @@ internal class TransientScopeInterfaceResolutionBuilder : ITransientScopeInterfa private readonly IFunctionCycleTracker _functionCycleTracker; private readonly Func _synchronicityDecisionMakerFactory; - private readonly string _name; private readonly string _containerAdapterName; @@ -48,12 +48,14 @@ public TransientScopeInterfaceResolutionBuilder( _synchronicityDecisionMakerFactory = synchronicityDecisionMakerFactory; _rootReferenceGenerator = referenceGeneratorFactory.Create(); - _name = _rootReferenceGenerator.Generate("ITransientScope"); + Name = _rootReferenceGenerator.Generate("ITransientScope"); _containerAdapterName = _rootReferenceGenerator.Generate("ContainerTransientScopeAdapter"); } + public string Name { get; } + public void AddImplementation(ITransientScopeImplementationResolutionBuilder implementation) { foreach (var (parameter, label, reference, key, handle) in _pastQueuedItems) @@ -77,7 +79,7 @@ public MultiSynchronicityFunctionCallResolution CreateTransientScopeInstanceRefe public TransientScopeInterfaceResolution Build() => new( _rangedInstanceReferenceResolutions.Values.ToList(), - _name, + Name, _containerAdapterName); private MultiSynchronicityFunctionCallResolution CreateRangedInstanceReferenceResolution( diff --git a/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs b/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs index 9ce9ce33..ad44195b 100644 --- a/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs @@ -65,7 +65,7 @@ public override MultiSynchronicityFunctionCallResolution CreateContainerInstance _containerResolutionBuilder.CreateContainerInstanceReferenceResolution(parameter, _containerReference); public override MultiSynchronicityFunctionCallResolution CreateTransientScopeInstanceReferenceResolution(ForConstructorParameter parameter) => - _transientScopeInterfaceResolutionBuilder.CreateTransientScopeInstanceReferenceResolution(parameter, Constants.ThisKeyword); + _transientScopeInterfaceResolutionBuilder.CreateTransientScopeInstanceReferenceResolution(parameter, $"({Constants.ThisKeyword} as {_transientScopeInterfaceResolutionBuilder.Name})"); public override TransientScopeRootResolution CreateTransientScopeRootResolution( SwitchImplementationParameter parameter, diff --git a/Test/Func/ReductionCaseTransientScope.cs b/Test/Func/ReductionCaseTransientScope.cs new file mode 100644 index 00000000..cece1ba6 --- /dev/null +++ b/Test/Func/ReductionCaseTransientScope.cs @@ -0,0 +1,65 @@ +using System; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Func.ReductionCaseTransientScope; + +internal class DependencyA : ITransientScopeInstance +{ + public int Value { get; } + public DependencyB Dependency { get; } + + internal DependencyA( + int value, + Func dependencyB) + { + Value = value; + Dependency = dependencyB(23); + } +} + + +internal class DependencyB : ITransientScopeInstance +{ + private readonly Lazy _parentFactory; + public int Value { get; } + public Parent Parent => _parentFactory.Value; + + internal DependencyB( + int value, + Lazy parentFactory) + { + _parentFactory = parentFactory; + Value = value; + } +} + +internal class Parent : ITransientScopeRoot +{ + public DependencyA Dependency { get; } + + internal Parent( + DependencyA dependencyA) => + Dependency = dependencyA; +} + +[CreateFunction(typeof(Parent), "Create")] +internal sealed partial class Container +{ + private int DIE_Factory_int => 0; +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var parent = container.Create(); + Assert.IsType(parent); + Assert.True(0 == parent.Dependency.Value); + Assert.True(23 == parent.Dependency.Dependency.Value); + Assert.True(0 == parent.Dependency.Dependency.Parent.Dependency.Value); + } +} From 9f8b35cc85468055958b2d5511d9a65a84a78d91 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Mon, 1 Aug 2022 12:06:50 +0200 Subject: [PATCH 113/162] Fixing struct handling of ranged instances --- Main/CodeBuilding/RangeCodeBaseBuilder.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Main/CodeBuilding/RangeCodeBaseBuilder.cs b/Main/CodeBuilding/RangeCodeBaseBuilder.cs index f203cb0d..36b589c7 100644 --- a/Main/CodeBuilding/RangeCodeBaseBuilder.cs +++ b/Main/CodeBuilding/RangeCodeBaseBuilder.cs @@ -500,7 +500,11 @@ private StringBuilder GenerateRangedInstanceFunction(StringBuilder stringBuilder stringBuilder = stringBuilder .AppendLine( - $"this.{rangedInstanceFunctionGroupResolution.FieldReference} = {overload.Resolvable.Reference};") + $"this.{rangedInstanceFunctionGroupResolution.FieldReference} = {overload.Resolvable.Reference};"); + if (!isRefType) + stringBuilder = stringBuilder.AppendLine( + $"{rangedInstanceFunctionGroupResolution.IsCreatedForStructs} = true;"); + stringBuilder = stringBuilder .AppendLine($"}}") .AppendLine($"finally") .AppendLine($"{{") From 411fb0e7f6909fbf37161a626e48b3f069271ed6 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Mon, 1 Aug 2022 18:16:31 +0200 Subject: [PATCH 114/162] Refactoring --- Main/CodeBuilding/ContainerCodeBuilder.cs | 6 ++-- Main/CodeBuilding/RangeCodeBaseBuilder.cs | 19 +++++++--- Main/CodeBuilding/ScopeCodeBuilder.cs | 2 ++ .../CodeBuilding/TransientScopeCodeBuilder.cs | 2 ++ Main/Constants.cs | 3 ++ .../ContainerResolutionBuilder.cs | 22 +++++++++--- .../Function/FunctionResolutionBuilder.cs | 6 ++-- .../LocalFunctionResolutionBuilder.cs | 4 +++ .../RangedFunctionGroupResolutionBuilder.cs | 14 ++++++-- .../RangedFunctionResolutionBuilder.cs | 3 +- ...copeRootCreateFunctionResolutionBuilder.cs | 1 + .../RangeResolutionBaseBuilder.cs | 36 +++++++++++++------ .../ScopeResolutionBuilder.cs | 10 ++++-- .../TransientScopeResolutionBuilder.cs | 13 +++++-- Main/ResolutionTreeItem.cs | 17 ++++----- Main/SourceGenerator.cs | 8 +++-- 16 files changed, 123 insertions(+), 43 deletions(-) diff --git a/Main/CodeBuilding/ContainerCodeBuilder.cs b/Main/CodeBuilding/ContainerCodeBuilder.cs index e32f6cf1..7db1b9a3 100644 --- a/Main/CodeBuilding/ContainerCodeBuilder.cs +++ b/Main/CodeBuilding/ContainerCodeBuilder.cs @@ -54,6 +54,8 @@ protected override StringBuilder GenerateDisposalFunction_TransientScopeDisposal return stringBuilder; } + protected override bool ExplicitTransientScopeInstanceImplementation => false; + public override StringBuilder Build(StringBuilder stringBuilder) { var disposableImplementation = _containerResolution.DisposalType switch @@ -80,7 +82,7 @@ public override StringBuilder Build(StringBuilder stringBuilder) stringBuilder = _containerResolution.TransientScopeInterface.Functions.Aggregate( stringBuilder, (sb, f) => sb.AppendLine( - $"{SelectFullName(f)} {f.Reference}({string.Join(", ", f.Parameter.Select(p => $"{p.TypeFullName} {p.Reference}"))});")); + $"{Constants.PublicKeyword} {SelectFullName(f)} {f.Reference}({string.Join(", ", f.Parameter.Select(p => $"{p.TypeFullName} {p.Reference}"))});")); stringBuilder = stringBuilder .AppendLine($"}}"); @@ -94,7 +96,7 @@ public override StringBuilder Build(StringBuilder stringBuilder) stringBuilder = _containerResolution.TransientScopeInterface.Functions.Aggregate( stringBuilder, (sb, f) => sb.AppendLine( - $"public {SelectFullName(f)} {f.Reference}({string.Join(", ", f.Parameter.Select(p => $"{p.TypeFullName} {p.Reference}"))}) =>") + $"{Constants.PublicKeyword} {SelectFullName(f)} {f.Reference}({string.Join(", ", f.Parameter.Select(p => $"{p.TypeFullName} {p.Reference}"))}) =>") .AppendLine($"_container.{f.Reference}({string.Join(", ", f.Parameter.Select(p => p.Reference))});")); stringBuilder = stringBuilder diff --git a/Main/CodeBuilding/RangeCodeBaseBuilder.cs b/Main/CodeBuilding/RangeCodeBaseBuilder.cs index 36b589c7..70e12594 100644 --- a/Main/CodeBuilding/RangeCodeBaseBuilder.cs +++ b/Main/CodeBuilding/RangeCodeBaseBuilder.cs @@ -192,7 +192,7 @@ private StringBuilder GenerateResolutionFunction( { var parameter = string.Join(",", resolution.Parameter.Select(r => $"{r.TypeFullName} {r.Reference}")); stringBuilder = stringBuilder - .AppendLine($"private {(localFunctionResolution.SynchronicityDecision is SynchronicityDecision.AsyncTask or SynchronicityDecision.AsyncValueTask ? "async " : "")}{resolution.TypeFullName} {resolution.Reference}({parameter})") + .AppendLine($"{resolution.AccessModifier} {(localFunctionResolution.SynchronicityDecision is SynchronicityDecision.AsyncTask or SynchronicityDecision.AsyncValueTask ? "async " : "")}{resolution.TypeFullName} {resolution.Reference}({parameter})") .AppendLine($"{{"); if (_containerResolution.DisposalType != DisposalType.None) stringBuilder = stringBuilder @@ -459,6 +459,8 @@ private StringBuilder GenerateResolutions( return stringBuilder; } + protected abstract bool ExplicitTransientScopeInstanceImplementation { get; } + private StringBuilder GenerateRangedInstanceFunction(StringBuilder stringBuilder, RangedInstanceFunctionGroupResolution rangedInstanceFunctionGroupResolution) { var isRefType = rangedInstanceFunctionGroupResolution.IsCreatedForStructs is null; @@ -478,9 +480,18 @@ private StringBuilder GenerateRangedInstanceFunction(StringBuilder stringBuilder overload.SynchronicityDecision is SynchronicityDecision.AsyncTask or SynchronicityDecision.AsyncValueTask; var parameters = string.Join(", ", overload.Parameter.Select(p => $"{p.TypeFullName} {p.Reference}")); - stringBuilder = stringBuilder.AppendLine( - $"public {(isAsync ? "async " : "")}{overload.TypeFullName} {overload.Reference}({parameters})") - .AppendLine($"{{") + if (rangedInstanceFunctionGroupResolution.IsTransientScopeInstance + && ExplicitTransientScopeInstanceImplementation) + { + stringBuilder = stringBuilder.AppendLine( + $"{(isAsync ? "async " : "")}{overload.TypeFullName} {_containerResolution.TransientScopeInterface.Name}.{overload.Reference}({parameters})"); + } + else + { + stringBuilder = stringBuilder.AppendLine( + $"{Constants.PrivateKeyword} {(isAsync ? "async " : "")}{overload.TypeFullName} {overload.Reference}({parameters})"); + } + stringBuilder = stringBuilder.AppendLine($"{{") .AppendLine(isRefType ? $"if (!object.ReferenceEquals({rangedInstanceFunctionGroupResolution.FieldReference}, null)) return {rangedInstanceFunctionGroupResolution.FieldReference};" : $"if ({rangedInstanceFunctionGroupResolution.IsCreatedForStructs}) return {rangedInstanceFunctionGroupResolution.FieldReference};") diff --git a/Main/CodeBuilding/ScopeCodeBuilder.cs b/Main/CodeBuilding/ScopeCodeBuilder.cs index c0f6c787..5370a52e 100644 --- a/Main/CodeBuilding/ScopeCodeBuilder.cs +++ b/Main/CodeBuilding/ScopeCodeBuilder.cs @@ -18,6 +18,8 @@ internal class ScopeCodeBuilder : RangeCodeBaseBuilder, IScopeCodeBuilder protected override StringBuilder GenerateDisposalFunction_TransientScopeDisposal(StringBuilder stringBuilder) => stringBuilder; + protected override bool ExplicitTransientScopeInstanceImplementation => false; + public override StringBuilder Build(StringBuilder stringBuilder) { if (!_scopeResolution.RootResolutions.Any() && !_scopeResolution.RangedInstanceFunctionGroups.Any()) diff --git a/Main/CodeBuilding/TransientScopeCodeBuilder.cs b/Main/CodeBuilding/TransientScopeCodeBuilder.cs index 2730567d..cbe48720 100644 --- a/Main/CodeBuilding/TransientScopeCodeBuilder.cs +++ b/Main/CodeBuilding/TransientScopeCodeBuilder.cs @@ -30,6 +30,8 @@ protected override StringBuilder GenerateDisposalFunction_TransientScopeDisposal return stringBuilder; } + protected override bool ExplicitTransientScopeInstanceImplementation => true; + public override StringBuilder Build(StringBuilder stringBuilder) { if (!_transientScopeResolution.RootResolutions.Any() && !_transientScopeResolution.RangedInstanceFunctionGroups.Any()) diff --git a/Main/Constants.cs b/Main/Constants.cs index 8c54b997..19587f96 100644 --- a/Main/Constants.cs +++ b/Main/Constants.cs @@ -5,6 +5,9 @@ internal static class Constants // General internal const string DieAbbreviation = "DIE"; internal const string ThisKeyword = "this"; + internal const string PublicKeyword = "public"; + internal const string InternalKeyword = "internal"; + internal const string PrivateKeyword = "private"; // Ranges internal const string ScopeName = "Scope"; diff --git a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs index adcd51a7..2cf5a810 100644 --- a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs @@ -36,9 +36,14 @@ internal ContainerResolutionBuilder( ICheckTypeProperties checkTypeProperties, WellKnownTypes wellKnownTypes, Func scopeManagerFactory, - Func rangedFunctionGroupResolutionBuilderFactory, + Func rangedFunctionGroupResolutionBuilderFactory, Func synchronicityDecisionMakerFactory, - Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory, + Func< + IRangeResolutionBaseBuilder, + INamedTypeSymbol, + ImmutableSortedDictionary, + string, + ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory, IUserDefinedElements userDefinedElement, IFunctionCycleTracker functionCycleTracker) : base( @@ -68,7 +73,11 @@ internal ContainerResolutionBuilder( public void AddCreateResolveFunctions(IReadOnlyList<(INamedTypeSymbol, string)> createFunctionData) { foreach (var (typeSymbol, methodNamePrefix) in createFunctionData) - _rootResolutions.Add((CreateLocalFunctionResolution(typeSymbol, ImmutableSortedDictionary.Empty), methodNamePrefix)); + _rootResolutions.Add((CreateLocalFunctionResolution( + typeSymbol, + ImmutableSortedDictionary.Empty, + Constants.PrivateKeyword), + methodNamePrefix)); } public MultiSynchronicityFunctionCallResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter, string containerReference) => @@ -77,7 +86,8 @@ public MultiSynchronicityFunctionCallResolution CreateContainerInstanceReference "Container", null, containerReference, - new (_synchronicityDecisionMakerFactory)); + new (_synchronicityDecisionMakerFactory), + false); public IFunctionCycleTracker FunctionCycleTracker { get; } @@ -148,6 +158,7 @@ public ContainerResolution Build() .Select(f => new LocalFunctionResolution( f.Reference, f.TypeFullName, + f.AccessModifier, f.Resolvable, f.Parameter, f.SynchronicityDecision)) @@ -352,5 +363,6 @@ public MultiSynchronicityFunctionCallResolution EnqueueRangedInstanceResolution( label, reference, "Doesn't Matter, because for interface", - synchronicityDecisionMaker); + synchronicityDecisionMaker, + true); } \ No newline at end of file diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs index fc74aa9c..d47cee4e 100644 --- a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs @@ -233,7 +233,8 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup var newLocalFunction = _rangeResolutionBaseBuilder.CreateLocalFunctionResolution( genericType, - currentParameters); + currentParameters, + Constants.PrivateKeyword); var constructorInjection = new LazyResolution( RootReferenceGenerator.Generate(namedTypeSymbol), @@ -281,7 +282,8 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup var newLocalFunction = _rangeResolutionBaseBuilder.CreateLocalFunctionResolution( returnType, - nextCurrentParameters); + nextCurrentParameters, + Constants.PrivateKeyword); return ( new FuncResolution( diff --git a/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs index 7811579f..59876b07 100644 --- a/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs @@ -7,6 +7,7 @@ internal interface ILocalFunctionResolutionBuilder : IFunctionResolutionBuilder internal class LocalFunctionResolutionBuilder : FunctionResolutionBuilder, ILocalFunctionResolutionBuilder { private readonly INamedTypeSymbol _returnType; + private readonly string _accessModifier; public LocalFunctionResolutionBuilder( // parameter @@ -14,6 +15,7 @@ public LocalFunctionResolutionBuilder( INamedTypeSymbol returnType, ImmutableSortedDictionary parameters, IFunctionResolutionSynchronicityDecisionMaker synchronicityDecisionMaker, + string accessModifier, // dependencies WellKnownTypes wellKnownTypes, @@ -31,6 +33,7 @@ public LocalFunctionResolutionBuilder( functionCycleTracker) { _returnType = returnType; + _accessModifier = accessModifier; Name = RootReferenceGenerator.Generate("Create", _returnType); } @@ -51,6 +54,7 @@ public override FunctionResolution Build() return new( Name, TypeFullName, + _accessModifier, Resolvable.Value, Parameters, SynchronicityDecision.Value); diff --git a/Main/ResolutionBuilding/Function/RangedFunctionGroupResolutionBuilder.cs b/Main/ResolutionBuilding/Function/RangedFunctionGroupResolutionBuilder.cs index 12bca2cd..932af639 100644 --- a/Main/ResolutionBuilding/Function/RangedFunctionGroupResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/RangedFunctionGroupResolutionBuilder.cs @@ -16,6 +16,7 @@ internal interface IRangedFunctionGroupResolutionBuilder internal class RangedFunctionGroupResolutionBuilder : IRangedFunctionGroupResolutionBuilder { private readonly IRangeResolutionBaseBuilder _rangeResolutionBaseBuilder; + private readonly bool _isTransientScopeInstance; private readonly Func< IRangeResolutionBaseBuilder, @@ -40,12 +41,20 @@ internal RangedFunctionGroupResolutionBuilder( INamedTypeSymbol implementationType, string decorationSuffix, IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, + bool isTransientScopeInstance, // dependencies IReferenceGeneratorFactory referenceGeneratorFactory, - Func rangedFunctionResolutionBuilderFactory) + Func< + IRangeResolutionBaseBuilder, + string, + ForConstructorParameter, + IFunctionResolutionSynchronicityDecisionMaker, + object, + IRangedFunctionResolutionBuilder> rangedFunctionResolutionBuilderFactory) { _rangeResolutionBaseBuilder = rangeResolutionBaseBuilder; + _isTransientScopeInstance = isTransientScopeInstance; _rangedFunctionResolutionBuilderFactory = rangedFunctionResolutionBuilderFactory; var rootReferenceGenerator = referenceGeneratorFactory.Create(); _reference = reference ?? rootReferenceGenerator.Generate($"Get{label}Instance", implementationType, decorationSuffix); @@ -97,5 +106,6 @@ public RangedInstanceFunctionGroupResolution Build() => .ToList(), _fieldReference, _lockReference, - _isCreatedForStructs); + _isCreatedForStructs, + _isTransientScopeInstance); } \ No newline at end of file diff --git a/Main/ResolutionBuilding/Function/RangedFunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/RangedFunctionResolutionBuilder.cs index 42e38452..885cad0a 100644 --- a/Main/ResolutionBuilding/Function/RangedFunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/RangedFunctionResolutionBuilder.cs @@ -32,7 +32,7 @@ public RangedFunctionResolutionBuilder( functionCycleTracker) { _forConstructorParameter = forConstructorParameter; - + Name = reference; } @@ -55,6 +55,7 @@ public override FunctionResolution Build() return new( Name, TypeFullName, + Constants.PrivateKeyword, Resolvable.Value, Parameters, SynchronicityDecision.Value); diff --git a/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs index 6434f19c..03f729d0 100644 --- a/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs @@ -53,6 +53,7 @@ public override FunctionResolution Build() return new( Name, TypeFullName, + Constants.InternalKeyword, Resolvable.Value, Parameters, SynchronicityDecision.Value); diff --git a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs index 0d0ceb9e..635613d9 100644 --- a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs +++ b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs @@ -34,7 +34,8 @@ ScopeRootResolution CreateScopeRootResolution( IFunctionResolutionBuilder CreateLocalFunctionResolution( INamedTypeSymbol type, - ImmutableSortedDictionary currentParameters); + ImmutableSortedDictionary currentParameters, + string accessModifier); } internal abstract class RangeResolutionBaseBuilder : IRangeResolutionBaseBuilder @@ -47,8 +48,13 @@ internal abstract class RangeResolutionBaseBuilder : IRangeResolutionBaseBuilder protected IMethodSymbol? AddForDisposalAsync { get; } private readonly WellKnownTypes _wellKnownTypes; - private readonly Func _rangedFunctionGroupResolutionBuilderFactory; - private readonly Func, ILocalFunctionResolutionBuilder> _localFunctionResolutionBuilderFactory; + private readonly Func _rangedFunctionGroupResolutionBuilderFactory; + private readonly Func< + IRangeResolutionBaseBuilder, + INamedTypeSymbol, + ImmutableSortedDictionary, + string, + ILocalFunctionResolutionBuilder> _localFunctionResolutionBuilderFactory; private readonly Func _synchronicityDecisionMakerFactory; protected readonly IReferenceGenerator RootReferenceGenerator; @@ -68,9 +74,14 @@ protected RangeResolutionBaseBuilder( // dependencies WellKnownTypes wellKnownTypes, IReferenceGeneratorFactory referenceGeneratorFactory, - Func rangedFunctionGroupResolutionBuilderFactory, + Func rangedFunctionGroupResolutionBuilderFactory, Func synchronicityDecisionMakerFactory, - Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) + Func< + IRangeResolutionBaseBuilder, + INamedTypeSymbol, + ImmutableSortedDictionary, + string, + ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) { CheckTypeProperties = checkTypeProperties; UserDefinedElements = userDefinedElements; @@ -98,7 +109,8 @@ public MultiSynchronicityFunctionCallResolution CreateScopeInstanceReferenceReso "Scope", null, Constants.ThisKeyword, - new (_synchronicityDecisionMakerFactory)); + new (_synchronicityDecisionMakerFactory), + false); public abstract TransientScopeRootResolution CreateTransientScopeRootResolution( SwitchImplementationParameter parameter, @@ -111,19 +123,23 @@ public abstract ScopeRootResolution CreateScopeRootResolution( ImmutableSortedDictionary currentParameters); public abstract void RegisterDisposalType(DisposalType disposalType); - public IFunctionResolutionBuilder CreateLocalFunctionResolution(INamedTypeSymbol type, ImmutableSortedDictionary currentParameters) => + public IFunctionResolutionBuilder CreateLocalFunctionResolution( + INamedTypeSymbol type, + ImmutableSortedDictionary currentParameters, + string accessModifier) => FunctionResolutionUtility.GetOrCreateFunction( LocalFunctions, type, currentParameters, - () => _localFunctionResolutionBuilderFactory(this, type, currentParameters)); + () => _localFunctionResolutionBuilderFactory(this, type, currentParameters, accessModifier)); protected MultiSynchronicityFunctionCallResolution CreateRangedInstanceReferenceResolution( ForConstructorParameter parameter, string label, string? reference, string owningObjectReference, - Lazy synchronicityDecisionMaker) + Lazy synchronicityDecisionMaker, + bool isTransientScopeInstance) { var (implementationType, currentParameters, _) = parameter; InterfaceExtension? interfaceExtension = parameter switch @@ -136,7 +152,7 @@ protected MultiSynchronicityFunctionCallResolution CreateRangedInstanceReference if (!RangedInstanceReferenceResolutions.TryGetValue(key, out var functionGroup)) { var decorationSuffix = interfaceExtension?.RangedNameSuffix() ?? ""; - functionGroup = _rangedFunctionGroupResolutionBuilderFactory(label, reference, implementationType, decorationSuffix, this); + functionGroup = _rangedFunctionGroupResolutionBuilderFactory(label, reference, implementationType, decorationSuffix, this, isTransientScopeInstance); RangedInstanceReferenceResolutions[key] = functionGroup; } diff --git a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs index 328dcfe2..c9e990a6 100644 --- a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs @@ -41,9 +41,14 @@ internal ScopeResolutionBuilder( WellKnownTypes wellKnownTypes, IReferenceGeneratorFactory referenceGeneratorFactory, Func scopeRootCreateFunctionResolutionBuilderFactory, - Func rangedFunctionGroupResolutionBuilderFactory, + Func rangedFunctionGroupResolutionBuilderFactory, Func synchronicityDecisionMakerFactory, - Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) + Func< + IRangeResolutionBaseBuilder, + INamedTypeSymbol, + ImmutableSortedDictionary, + string, + ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) : base( name, checkTypeProperties, @@ -160,6 +165,7 @@ public ScopeResolution Build() => .Select(f => new LocalFunctionResolution( f.Reference, f.TypeFullName, + f.AccessModifier, f.Resolvable, f.Parameter, f.SynchronicityDecision)) diff --git a/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs b/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs index ad44195b..3d6d5e8e 100644 --- a/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs @@ -37,9 +37,14 @@ internal TransientScopeResolutionBuilder( WellKnownTypes wellKnownTypes, IReferenceGeneratorFactory referenceGeneratorFactory, Func scopeRootCreateFunctionResolutionBuilderFactory, - Func rangedFunctionGroupResolutionBuilderFactory, + Func rangedFunctionGroupResolutionBuilderFactory, Func synchronicityDecisionMakerFactory, - Func, ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) + Func< + IRangeResolutionBaseBuilder, + INamedTypeSymbol, + ImmutableSortedDictionary, + string, + ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) : base( name, checkTypeProperties, @@ -155,6 +160,7 @@ public TransientScopeResolution Build() => .Select(f => new LocalFunctionResolution( f.Reference, f.TypeFullName, + f.AccessModifier, f.Resolvable, f.Parameter, f.SynchronicityDecision)) @@ -176,5 +182,6 @@ public MultiSynchronicityFunctionCallResolution EnqueueRangedInstanceResolution( label, reference, "Doesn't Matter, because for interface", - synchronicityDecisionMaker); + synchronicityDecisionMaker, + true); } \ No newline at end of file diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index f0b4aa78..928cd379 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -24,6 +24,7 @@ internal record ProxyResolvable( internal record FunctionResolution( string Reference, string TypeFullName, + string AccessModifier, Resolvable Resolvable, IReadOnlyList Parameter, SynchronicityDecision SynchronicityDecision) : Resolvable(Reference, TypeFullName); @@ -35,15 +36,16 @@ internal record RootResolutionFunction( Resolvable Resolvable, IReadOnlyList Parameter, SynchronicityDecision SynchronicityDecision) - : FunctionResolution(Reference, TypeFullName, Resolvable, Parameter, SynchronicityDecision); + : FunctionResolution(Reference, TypeFullName, AccessModifier, Resolvable, Parameter, SynchronicityDecision); internal record LocalFunctionResolution( string Reference, string TypeFullName, + string AccessModifier, Resolvable Resolvable, IReadOnlyList Parameter, SynchronicityDecision SynchronicityDecision) - : FunctionResolution(Reference, TypeFullName, Resolvable, Parameter, SynchronicityDecision); + : FunctionResolution(Reference, TypeFullName, AccessModifier, Resolvable, Parameter, SynchronicityDecision); internal record RangedInstanceFunctionResolution( string Reference, @@ -51,20 +53,15 @@ internal record RangedInstanceFunctionResolution( Resolvable Resolvable, IReadOnlyList Parameter, SynchronicityDecision SynchronicityDecision) - : FunctionResolution(Reference, TypeFullName, Resolvable, Parameter, SynchronicityDecision); + : FunctionResolution(Reference, TypeFullName, Constants.PrivateKeyword, Resolvable, Parameter, SynchronicityDecision); internal record RangedInstanceFunctionGroupResolution( string TypeFullName, IReadOnlyList Overloads, string FieldReference, string LockReference, - string? IsCreatedForStructs); - -internal record MethodGroupResolution( - string Reference, - string TypeFullName, - string? OwnerReference) - : Resolvable(Reference, TypeFullName); + string? IsCreatedForStructs, + bool IsTransientScopeInstance); internal record TransientScopeAsDisposableResolution( string Reference, diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index ce8c1156..f9c6a268 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -211,11 +211,13 @@ IScopeResolutionBuilder ScopeResolutionBuilderFactory( ILocalFunctionResolutionBuilder LocalFunctionResolutionBuilderFactory( IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, INamedTypeSymbol returnType, - ImmutableSortedDictionary parameters) => new LocalFunctionResolutionBuilder( + ImmutableSortedDictionary parameters, + string accessModifier) => new LocalFunctionResolutionBuilder( rangeResolutionBaseBuilder, returnType, parameters, FunctionResolutionSynchronicityDecisionMakerFactory(), + accessModifier, wellKnownTypes, referenceGeneratorFactory, @@ -253,12 +255,14 @@ IRangedFunctionGroupResolutionBuilder RangedFunctionGroupResolutionBuilderFactor string? reference, INamedTypeSymbol implementationType, string decorationSuffix, - IRangeResolutionBaseBuilder rangeResolutionBaseBuilder) => new RangedFunctionGroupResolutionBuilder( + IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, + bool isTransientScopeInstance) => new RangedFunctionGroupResolutionBuilder( label, reference, implementationType, decorationSuffix, rangeResolutionBaseBuilder, + isTransientScopeInstance, referenceGeneratorFactory, RangedFunctionResolutionBuilderFactory); From cf9270f8020be1da20499384f5ff7ef04eeaf2f9 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Mon, 1 Aug 2022 18:43:58 +0200 Subject: [PATCH 115/162] Consistency fix --- .../TransientScopeResolutionBuilder.cs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs b/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs index 3d6d5e8e..1b88ba6f 100644 --- a/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs @@ -1,5 +1,6 @@ using MrMeeseeks.DIE.Configuration; using MrMeeseeks.DIE.ResolutionBuilding.Function; +using MrMeeseeks.DIE.Utility; namespace MrMeeseeks.DIE.ResolutionBuilding; @@ -110,14 +111,11 @@ public TransientScopeRootResolution AddCreateResolveFunction( string containerInstanceScopeReference, ImmutableSortedDictionary currentParameters) { - var key = $"{rootType.FullName()}{(currentParameters.Any() ? $"_{string.Join(";", currentParameters)}" : "")}"; - if (!_transientScopeRootFunctionResolutions.TryGetValue( - key, - out var function)) - { - function = _scopeRootCreateFunctionResolutionBuilderFactory(this, parameter); - _transientScopeRootFunctionResolutions[key] = function; - } + var function = FunctionResolutionUtility.GetOrCreateFunction( + _transientScopeRootFunctionResolutions, + rootType, + currentParameters, + () => _scopeRootCreateFunctionResolutionBuilderFactory(this, parameter)); var transientScopeRootReference = RootReferenceGenerator.Generate("transientScopeRoot"); From 37047c04471be4f255b5bcac856a63fa877ce25c Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Mon, 1 Aug 2022 19:13:53 +0200 Subject: [PATCH 116/162] Merged scope root functions as far as possible to former "local"- now "create"-functions --- Main/CodeBuilding/RangeCodeBaseBuilder.cs | 24 +------- Main/CodeBuilding/ScopeCodeBuilder.cs | 3 - .../CodeBuilding/TransientScopeCodeBuilder.cs | 3 - .../ContainerResolutionBuilder.cs | 56 +++++++++---------- .../Function/FunctionResolutionBuilder.cs | 8 +-- .../LocalFunctionResolutionBuilder.cs | 6 +- .../RangeResolutionBaseBuilder.cs | 18 +++--- .../ScopeResolutionBuilder.cs | 33 +++-------- .../TransientScopeResolutionBuilder.cs | 33 +++-------- Main/ResolutionTreeItem.cs | 32 +++-------- Main/SourceGenerator.cs | 10 ++-- 11 files changed, 73 insertions(+), 153 deletions(-) diff --git a/Main/CodeBuilding/RangeCodeBaseBuilder.cs b/Main/CodeBuilding/RangeCodeBaseBuilder.cs index 70e12594..9504ec03 100644 --- a/Main/CodeBuilding/RangeCodeBaseBuilder.cs +++ b/Main/CodeBuilding/RangeCodeBaseBuilder.cs @@ -30,9 +30,7 @@ protected StringBuilder GenerateResolutionRange( { stringBuilder = rangeResolution.RangedInstanceFunctionGroups.Aggregate(stringBuilder, GenerateRangedInstanceFunction); - stringBuilder = rangeResolution.RootResolutions.Aggregate(stringBuilder, GenerateResolutionFunction); - - stringBuilder = rangeResolution.LocalFunctions.Aggregate(stringBuilder, GenerateResolutionFunction); + stringBuilder = rangeResolution.CreateFunctions.Aggregate(stringBuilder, GenerateResolutionFunction); if (_rangeResolution.AddForDisposal is { } addForDisposalMethod) { @@ -172,23 +170,7 @@ private StringBuilder GenerateResolutionFunction( StringBuilder stringBuilder, FunctionResolution resolution) { - if (resolution is RootResolutionFunction rootResolutionFunction) - { - var parameter = string.Join(",", resolution.Parameter.Select(r => $"{r.TypeFullName} {r.Reference}")); - stringBuilder = stringBuilder - .AppendLine($"{rootResolutionFunction.AccessModifier} {(rootResolutionFunction.SynchronicityDecision is SynchronicityDecision.AsyncTask or SynchronicityDecision.AsyncValueTask ? "async " : "")}{resolution.TypeFullName} {resolution.Reference}({parameter})") - .AppendLine($"{{"); - if (_containerResolution.DisposalType != DisposalType.None) - stringBuilder = stringBuilder - .AppendLine($"if (this.{_rangeResolution.DisposalHandling.DisposedPropertyReference}) throw new {WellKnownTypes.ObjectDisposedException}(\"\");"); - - stringBuilder = GenerateResolutionFunctionContent(stringBuilder, resolution.Resolvable) - .AppendLine($"return {resolution.Resolvable.Reference};") - .AppendLine($"}}"); - - return stringBuilder; - } - else if (resolution is LocalFunctionResolution localFunctionResolution) + if (resolution is CreateFunctionResolution localFunctionResolution) { var parameter = string.Join(",", resolution.Parameter.Select(r => $"{r.TypeFullName} {r.Reference}")); stringBuilder = stringBuilder @@ -205,7 +187,7 @@ private StringBuilder GenerateResolutionFunction( return stringBuilder; } - throw new Exception(); + throw new Exception(); // todo message } private StringBuilder GenerateResolutionFunctionContent( diff --git a/Main/CodeBuilding/ScopeCodeBuilder.cs b/Main/CodeBuilding/ScopeCodeBuilder.cs index 5370a52e..0f88e39a 100644 --- a/Main/CodeBuilding/ScopeCodeBuilder.cs +++ b/Main/CodeBuilding/ScopeCodeBuilder.cs @@ -22,9 +22,6 @@ internal class ScopeCodeBuilder : RangeCodeBaseBuilder, IScopeCodeBuilder public override StringBuilder Build(StringBuilder stringBuilder) { - if (!_scopeResolution.RootResolutions.Any() && !_scopeResolution.RangedInstanceFunctionGroups.Any()) - return stringBuilder; - var disposableImplementation = _containerResolution.DisposalType switch { DisposalType.Async => $" : {WellKnownTypes.AsyncDisposable.FullName()}", diff --git a/Main/CodeBuilding/TransientScopeCodeBuilder.cs b/Main/CodeBuilding/TransientScopeCodeBuilder.cs index cbe48720..2f484062 100644 --- a/Main/CodeBuilding/TransientScopeCodeBuilder.cs +++ b/Main/CodeBuilding/TransientScopeCodeBuilder.cs @@ -34,9 +34,6 @@ protected override StringBuilder GenerateDisposalFunction_TransientScopeDisposal public override StringBuilder Build(StringBuilder stringBuilder) { - if (!_transientScopeResolution.RootResolutions.Any() && !_transientScopeResolution.RangedInstanceFunctionGroups.Any()) - return stringBuilder; - var disposableImplementation = _containerResolution.DisposalType switch { DisposalType.Async => $", {WellKnownTypes.AsyncDisposable.FullName()}", diff --git a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs index 2cf5a810..2fc0150a 100644 --- a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs @@ -43,7 +43,7 @@ internal ContainerResolutionBuilder( INamedTypeSymbol, ImmutableSortedDictionary, string, - ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory, + ICreateFunctionResolutionBuilder> localFunctionResolutionBuilderFactory, IUserDefinedElements userDefinedElement, IFunctionCycleTracker functionCycleTracker) : base( @@ -73,7 +73,7 @@ internal ContainerResolutionBuilder( public void AddCreateResolveFunctions(IReadOnlyList<(INamedTypeSymbol, string)> createFunctionData) { foreach (var (typeSymbol, methodNamePrefix) in createFunctionData) - _rootResolutions.Add((CreateLocalFunctionResolution( + _rootResolutions.Add((CreateCreateFunctionResolution( typeSymbol, ImmutableSortedDictionary.Empty, Constants.PrivateKeyword), @@ -132,7 +132,7 @@ public override void RegisterDisposalType(DisposalType disposalType) public bool HasWorkToDo => _rootResolutions.Any(r => r.CreateFunction.HasWorkToDo) || RangedInstanceReferenceResolutions.Values.Any(r => r.HasWorkToDo) - || LocalFunctions.Values.Any(r => r.HasWorkToDo) + || CreateFunctions.Values.Any(r => r.HasWorkToDo) || _scopeManager.HasWorkToDo; public void DoWork() @@ -145,17 +145,17 @@ public void DoWork() } DoRangedInstancesWork(); - DoLocalFunctionsWork(); + DoCreateFunctionsWork(); _scopeManager.DoWork(); } } public ContainerResolution Build() { - var localFunctions = LocalFunctions + var localFunctions = CreateFunctions .Values .Select(lf => lf.Build()) - .Select(f => new LocalFunctionResolution( + .Select(f => new CreateFunctionResolution( f.Reference, f.TypeFullName, f.AccessModifier, @@ -164,7 +164,6 @@ public ContainerResolution Build() f.SynchronicityDecision)) .ToList(); - var rootFunctions = new List(); foreach (var (createFunction, methodNamePrefix) in _rootResolutions) { // Create function stays sync @@ -178,15 +177,15 @@ public ContainerResolution Build() call.Sync.Await = false; call.AsyncTask.Await = false; call.AsyncValueTask.Await = false; - var publicSyncResolutionFunction = new RootResolutionFunction( + var publicSyncResolutionFunction = new CreateFunctionResolution( $"{methodNamePrefix}{Constants.CreateFunctionSuffix}", createFunction.OriginalReturnType.FullName(), - "public", + Constants.PublicKeyword, call, createFunction.Parameters, SynchronicityDecision.Sync); - rootFunctions.Add(publicSyncResolutionFunction); + localFunctions.Add(publicSyncResolutionFunction); var boundTaskTypeFullName = _wellKnownTypes .Task1 @@ -199,10 +198,10 @@ public ContainerResolution Build() taskCall.Sync.Await = false; taskCall.AsyncTask.Await = false; taskCall.AsyncValueTask.Await = false; - var publicTaskResolutionFunction = new RootResolutionFunction( + var publicTaskResolutionFunction = new CreateFunctionResolution( $"{methodNamePrefix}{Constants.CreateFunctionSuffixAsync}", boundTaskTypeFullName, - "public", + Constants.PublicKeyword, new TaskFromSyncResolution( taskCall, wrappedTaskReference, @@ -210,7 +209,7 @@ public ContainerResolution Build() createFunction.Parameters, SynchronicityDecision.Sync); - rootFunctions.Add(publicTaskResolutionFunction); + localFunctions.Add(publicTaskResolutionFunction); var boundValueTaskTypeFullName = _wellKnownTypes .ValueTask1 @@ -223,10 +222,10 @@ public ContainerResolution Build() valueTaskCall.Sync.Await = false; valueTaskCall.AsyncTask.Await = false; valueTaskCall.AsyncValueTask.Await = false; - var publicValueTaskResolutionFunction = new RootResolutionFunction( + var publicValueTaskResolutionFunction = new CreateFunctionResolution( $"{methodNamePrefix}{Constants.CreateFunctionSuffixValueAsync}", boundValueTaskTypeFullName, - "public", + Constants.PublicKeyword, new ValueTaskFromSyncResolution( valueTaskCall, wrappedValueTaskReference, @@ -234,7 +233,7 @@ public ContainerResolution Build() createFunction.Parameters, SynchronicityDecision.Sync); - rootFunctions.Add(publicValueTaskResolutionFunction); + localFunctions.Add(publicValueTaskResolutionFunction); } else if (createFunction.ActualReturnType is { } actual && actual.Equals(_wellKnownTypes.Task1.Construct(createFunction.OriginalReturnType), @@ -246,15 +245,15 @@ public ContainerResolution Build() call.Sync.Await = false; call.AsyncTask.Await = false; call.AsyncValueTask.Await = false; - var publicTaskResolutionFunction = new RootResolutionFunction( + var publicTaskResolutionFunction = new CreateFunctionResolution( $"{methodNamePrefix}{Constants.CreateFunctionSuffixAsync}", actual.FullName(), - "public", + Constants.PublicKeyword, call, createFunction.Parameters, SynchronicityDecision.Sync); - rootFunctions.Add(publicTaskResolutionFunction); + localFunctions.Add(publicTaskResolutionFunction); var boundValueTaskTypeFullName = _wellKnownTypes .ValueTask1 @@ -267,10 +266,10 @@ public ContainerResolution Build() valueCall.Sync.Await = false; valueCall.AsyncTask.Await = false; valueCall.AsyncValueTask.Await = false; - var publicValueTaskResolutionFunction = new RootResolutionFunction( + var publicValueTaskResolutionFunction = new CreateFunctionResolution( $"{methodNamePrefix}{Constants.CreateFunctionSuffixValueAsync}", boundValueTaskTypeFullName, - "public", + Constants.PublicKeyword, new ValueTaskFromWrappedTaskResolution( valueCall, wrappedValueTaskReference, @@ -278,7 +277,7 @@ public ContainerResolution Build() createFunction.Parameters, SynchronicityDecision.Sync); - rootFunctions.Add(publicValueTaskResolutionFunction); + localFunctions.Add(publicValueTaskResolutionFunction); } else if (createFunction.ActualReturnType is { } actual1 && actual1.Equals(_wellKnownTypes.ValueTask1.Construct(createFunction.OriginalReturnType), @@ -295,10 +294,10 @@ public ContainerResolution Build() call.AsyncTask.Await = false; call.AsyncValueTask.Await = false; var wrappedTaskReference = RootReferenceGenerator.Generate(_wellKnownTypes.ValueTask); - var publicTaskResolutionFunction = new RootResolutionFunction( + var publicTaskResolutionFunction = new CreateFunctionResolution( $"{methodNamePrefix}{Constants.CreateFunctionSuffixAsync}", boundTaskTypeFullName, - "public", + Constants.PublicKeyword, new TaskFromWrappedValueTaskResolution( call, wrappedTaskReference, @@ -306,7 +305,7 @@ public ContainerResolution Build() createFunction.Parameters, SynchronicityDecision.Sync); - rootFunctions.Add(publicTaskResolutionFunction); + localFunctions.Add(publicTaskResolutionFunction); var valueCall = createFunction.BuildFunctionCall( ImmutableSortedDictionary.Empty, @@ -314,22 +313,21 @@ public ContainerResolution Build() valueCall.Sync.Await = false; valueCall.AsyncTask.Await = false; valueCall.AsyncValueTask.Await = false; - var publicValueTaskResolutionFunction = new RootResolutionFunction( + var publicValueTaskResolutionFunction = new CreateFunctionResolution( $"{methodNamePrefix}{Constants.CreateFunctionSuffixValueAsync}", actual1.FullName(), - "public", + Constants.PublicKeyword, valueCall, createFunction.Parameters, SynchronicityDecision.Sync); - rootFunctions.Add(publicValueTaskResolutionFunction); + localFunctions.Add(publicValueTaskResolutionFunction); } } var (transientScopeResolutions, scopeResolutions) = _scopeManager.Build(); return new( - rootFunctions, localFunctions, BuildDisposalHandling(), RangedInstanceReferenceResolutions.Values.Select(b => b.Build()).ToList(), diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs index d47cee4e..2ba2e14a 100644 --- a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs @@ -231,7 +231,7 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup cp.Value.Item1.FullName(), cp.Value))); - var newLocalFunction = _rangeResolutionBaseBuilder.CreateLocalFunctionResolution( + var newCreateFunction = _rangeResolutionBaseBuilder.CreateCreateFunctionResolution( genericType, currentParameters, Constants.PrivateKeyword); @@ -239,7 +239,7 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup var constructorInjection = new LazyResolution( RootReferenceGenerator.Generate(namedTypeSymbol), namedTypeSymbol.FullName(), - newLocalFunction.BuildFunctionCall( + newCreateFunction.BuildFunctionCall( currentParameters, Constants.ThisKeyword)); return (constructorInjection, null); @@ -280,7 +280,7 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup nextCurrentParameters = nextCurrentParameters.SetItem(lambdaParameter.Type.FullName(), lambdaParameter); } - var newLocalFunction = _rangeResolutionBaseBuilder.CreateLocalFunctionResolution( + var newCreateFunction = _rangeResolutionBaseBuilder.CreateCreateFunctionResolution( returnType, nextCurrentParameters, Constants.PrivateKeyword); @@ -290,7 +290,7 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup RootReferenceGenerator.Generate(type), type.FullName(), lambdaParameters.Select(t => t.Resolution).ToImmutableArray(), - newLocalFunction.BuildFunctionCall(nextCurrentParameters, Constants.ThisKeyword)), + newCreateFunction.BuildFunctionCall(nextCurrentParameters, Constants.ThisKeyword)), null); } diff --git a/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs index 59876b07..c0930438 100644 --- a/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs @@ -1,15 +1,15 @@ namespace MrMeeseeks.DIE.ResolutionBuilding.Function; -internal interface ILocalFunctionResolutionBuilder : IFunctionResolutionBuilder +internal interface ICreateFunctionResolutionBuilder : IFunctionResolutionBuilder { } -internal class LocalFunctionResolutionBuilder : FunctionResolutionBuilder, ILocalFunctionResolutionBuilder +internal class CreateFunctionResolutionBuilder : FunctionResolutionBuilder, ICreateFunctionResolutionBuilder { private readonly INamedTypeSymbol _returnType; private readonly string _accessModifier; - public LocalFunctionResolutionBuilder( + public CreateFunctionResolutionBuilder( // parameter IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, INamedTypeSymbol returnType, diff --git a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs index 635613d9..818bc057 100644 --- a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs +++ b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs @@ -32,7 +32,7 @@ ScopeRootResolution CreateScopeRootResolution( void RegisterDisposalType(DisposalType disposalType); - IFunctionResolutionBuilder CreateLocalFunctionResolution( + IFunctionResolutionBuilder CreateCreateFunctionResolution( INamedTypeSymbol type, ImmutableSortedDictionary currentParameters, string accessModifier); @@ -54,14 +54,14 @@ private readonly Func< INamedTypeSymbol, ImmutableSortedDictionary, string, - ILocalFunctionResolutionBuilder> _localFunctionResolutionBuilderFactory; + ICreateFunctionResolutionBuilder> _localFunctionResolutionBuilderFactory; private readonly Func _synchronicityDecisionMakerFactory; protected readonly IReferenceGenerator RootReferenceGenerator; protected readonly IDictionary RangedInstanceReferenceResolutions = new Dictionary(); - protected readonly IDictionary LocalFunctions = new Dictionary(); + protected readonly IDictionary CreateFunctions = new Dictionary(); protected readonly string Name; @@ -81,7 +81,7 @@ protected RangeResolutionBaseBuilder( INamedTypeSymbol, ImmutableSortedDictionary, string, - ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) + ICreateFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) { CheckTypeProperties = checkTypeProperties; UserDefinedElements = userDefinedElements; @@ -123,12 +123,12 @@ public abstract ScopeRootResolution CreateScopeRootResolution( ImmutableSortedDictionary currentParameters); public abstract void RegisterDisposalType(DisposalType disposalType); - public IFunctionResolutionBuilder CreateLocalFunctionResolution( + public IFunctionResolutionBuilder CreateCreateFunctionResolution( INamedTypeSymbol type, ImmutableSortedDictionary currentParameters, string accessModifier) => FunctionResolutionUtility.GetOrCreateFunction( - LocalFunctions, + CreateFunctions, type, currentParameters, () => _localFunctionResolutionBuilderFactory(this, type, currentParameters, accessModifier)); @@ -172,11 +172,11 @@ protected void DoRangedInstancesWork() } } - protected void DoLocalFunctionsWork() + protected void DoCreateFunctionsWork() { - while (LocalFunctions.Values.Any(lf => lf.HasWorkToDo)) + while (CreateFunctions.Values.Any(lf => lf.HasWorkToDo)) { - foreach (var localFunction in LocalFunctions.Values.Where(lf => lf.HasWorkToDo).ToList()) + foreach (var localFunction in CreateFunctions.Values.Where(lf => lf.HasWorkToDo).ToList()) { localFunction.DoWork(); } diff --git a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs index c9e990a6..58eaabea 100644 --- a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs @@ -25,8 +25,6 @@ internal class ScopeResolutionBuilder : RangeResolutionBaseBuilder, IScopeResolu private readonly string _transientScopeReference; private readonly string _transientScopeParameterReference; - private readonly Dictionary _scopeRootFunctionResolutions = new (); - internal ScopeResolutionBuilder( // parameter string name, @@ -48,7 +46,7 @@ internal ScopeResolutionBuilder( INamedTypeSymbol, ImmutableSortedDictionary, string, - ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) + ICreateFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) : base( name, checkTypeProperties, @@ -106,9 +104,8 @@ public override ScopeRootResolution CreateScopeRootResolution( public override void RegisterDisposalType(DisposalType disposalType) => _containerResolutionBuilder.RegisterDisposalType(disposalType); public bool HasWorkToDo => - _scopeRootFunctionResolutions.Values.Any(f => f.HasWorkToDo) - || RangedInstanceReferenceResolutions.Values.Any(r => r.HasWorkToDo) - || LocalFunctions.Values.Any(r => r.HasWorkToDo); + RangedInstanceReferenceResolutions.Values.Any(r => r.HasWorkToDo) + || CreateFunctions.Values.Any(r => r.HasWorkToDo); public ScopeRootResolution AddCreateResolveFunction( SwitchImplementationParameter parameter, @@ -118,7 +115,7 @@ public ScopeRootResolution AddCreateResolveFunction( ImmutableSortedDictionary currentParameters) { var function = FunctionResolutionUtility.GetOrCreateFunction( - _scopeRootFunctionResolutions, + CreateFunctions, rootType, currentParameters, () => _scopeRootCreateFunctionResolutionBuilderFactory(this, parameter)); @@ -137,32 +134,16 @@ public void DoWork() { while (HasWorkToDo) { - foreach (var functionResolutionBuilder in _scopeRootFunctionResolutions.Values.Where(f => f.HasWorkToDo).ToList()) - { - functionResolutionBuilder.DoWork(); - } - DoRangedInstancesWork(); - DoLocalFunctionsWork(); + DoCreateFunctionsWork(); } } public ScopeResolution Build() => - new(_scopeRootFunctionResolutions - .Values - .Select(fr => fr.Build()) - .Select(f => new RootResolutionFunction( - f.Reference, - f.TypeFullName, - "internal", - f.Resolvable, - f.Parameter, - f.SynchronicityDecision)) - .ToList(), - LocalFunctions + new(CreateFunctions .Values .Select(lf => lf.Build()) - .Select(f => new LocalFunctionResolution( + .Select(f => new CreateFunctionResolution( f.Reference, f.TypeFullName, f.AccessModifier, diff --git a/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs b/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs index 1b88ba6f..17e06535 100644 --- a/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs @@ -21,8 +21,6 @@ internal class TransientScopeResolutionBuilder : RangeResolutionBaseBuilder, ITr private readonly Func _scopeRootCreateFunctionResolutionBuilderFactory; private readonly string _containerReference; private readonly string _containerParameterReference; - - private readonly Dictionary _transientScopeRootFunctionResolutions = new (); internal TransientScopeResolutionBuilder( // parameter @@ -45,7 +43,7 @@ internal TransientScopeResolutionBuilder( INamedTypeSymbol, ImmutableSortedDictionary, string, - ILocalFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) + ICreateFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) : base( name, checkTypeProperties, @@ -101,9 +99,8 @@ public override ScopeRootResolution CreateScopeRootResolution( public override void RegisterDisposalType(DisposalType disposalType) => _containerResolutionBuilder.RegisterDisposalType(disposalType); public bool HasWorkToDo => - _transientScopeRootFunctionResolutions.Values.Any(f => f.HasWorkToDo) - || RangedInstanceReferenceResolutions.Values.Any(r => r.HasWorkToDo) - || LocalFunctions.Values.Any(r => r.HasWorkToDo); + RangedInstanceReferenceResolutions.Values.Any(r => r.HasWorkToDo) + || CreateFunctions.Values.Any(r => r.HasWorkToDo); public TransientScopeRootResolution AddCreateResolveFunction( SwitchImplementationParameter parameter, @@ -112,7 +109,7 @@ public TransientScopeRootResolution AddCreateResolveFunction( ImmutableSortedDictionary currentParameters) { var function = FunctionResolutionUtility.GetOrCreateFunction( - _transientScopeRootFunctionResolutions, + CreateFunctions, rootType, currentParameters, () => _scopeRootCreateFunctionResolutionBuilderFactory(this, parameter)); @@ -130,32 +127,16 @@ public void DoWork() { while (HasWorkToDo) { - foreach (var functionResolutionBuilder in _transientScopeRootFunctionResolutions.Values.Where(f => f.HasWorkToDo).ToList()) - { - functionResolutionBuilder.DoWork(); - } - DoRangedInstancesWork(); - DoLocalFunctionsWork(); + DoCreateFunctionsWork(); } } public TransientScopeResolution Build() => - new(_transientScopeRootFunctionResolutions - .Values - .Select(f => f.Build()) - .Select(f => new RootResolutionFunction( - f.Reference, - f.TypeFullName, - "internal", - f.Resolvable, - f.Parameter, - f.SynchronicityDecision)) - .ToList(), - LocalFunctions + new(CreateFunctions .Values .Select(lf => lf.Build()) - .Select(f => new LocalFunctionResolution( + .Select(f => new CreateFunctionResolution( f.Reference, f.TypeFullName, f.AccessModifier, diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index 928cd379..5a137ccc 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -29,16 +29,7 @@ internal record FunctionResolution( IReadOnlyList Parameter, SynchronicityDecision SynchronicityDecision) : Resolvable(Reference, TypeFullName); -internal record RootResolutionFunction( - string Reference, - string TypeFullName, - string AccessModifier, - Resolvable Resolvable, - IReadOnlyList Parameter, - SynchronicityDecision SynchronicityDecision) - : FunctionResolution(Reference, TypeFullName, AccessModifier, Resolvable, Parameter, SynchronicityDecision); - -internal record LocalFunctionResolution( +internal record CreateFunctionResolution( string Reference, string TypeFullName, string AccessModifier, @@ -212,8 +203,7 @@ internal record AsyncDisposableCollectionResolution( null); internal abstract record RangeResolution( - IReadOnlyList RootResolutions, - IReadOnlyList LocalFunctions, + IReadOnlyList CreateFunctions, DisposalHandling DisposalHandling, IReadOnlyList RangedInstanceFunctionGroups, string ContainerReference, @@ -226,8 +216,7 @@ internal record TransientScopeInterfaceResolution( string ContainerAdapterName); internal record ScopeResolution( - IReadOnlyList RootResolutions, - IReadOnlyList LocalFunctions, + IReadOnlyList CreateFunctions, DisposalHandling DisposalHandling, IReadOnlyList RangedInstanceFunctionGroups, string ContainerReference, @@ -238,8 +227,7 @@ internal record ScopeResolution( IMethodSymbol? AddForDisposal, IMethodSymbol? AddForDisposalAsync) : RangeResolution( - RootResolutions, - LocalFunctions, + CreateFunctions, DisposalHandling, RangedInstanceFunctionGroups, ContainerReference, @@ -247,8 +235,7 @@ internal record ScopeResolution( AddForDisposalAsync); internal record TransientScopeResolution( - IReadOnlyList RootResolutions, - IReadOnlyList LocalFunctions, + IReadOnlyList CreateFunctions, DisposalHandling DisposalHandling, IReadOnlyList RangedInstanceFunctionGroups, string ContainerReference, @@ -257,8 +244,7 @@ internal record TransientScopeResolution( IMethodSymbol? AddForDisposal, IMethodSymbol? AddForDisposalAsync) : RangeResolution( - RootResolutions, - LocalFunctions, + CreateFunctions, DisposalHandling, RangedInstanceFunctionGroups, ContainerReference, @@ -266,8 +252,7 @@ internal record TransientScopeResolution( AddForDisposalAsync); internal record ContainerResolution( - IReadOnlyList RootResolutions, - IReadOnlyList LocalFunctions, + IReadOnlyList CreateFunctions, DisposalHandling DisposalHandling, IReadOnlyList RangedInstanceFunctionGroups, TransientScopeInterfaceResolution TransientScopeInterface, @@ -283,8 +268,7 @@ internal record ContainerResolution( IMethodSymbol? AddForDisposal, IMethodSymbol? AddForDisposalAsync) : RangeResolution( - RootResolutions, - LocalFunctions, + CreateFunctions, DisposalHandling, RangedInstanceFunctionGroups, Constants.ThisKeyword, diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index f9c6a268..cd497e83 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -126,7 +126,7 @@ IContainerResolutionBuilder ResolutionTreeFactory(IContainerInfo ci) ScopeManagerFactory, RangedFunctionGroupResolutionBuilderFactory, FunctionResolutionSynchronicityDecisionMakerFactory, - LocalFunctionResolutionBuilderFactory, + CreateFunctionResolutionBuilderFactory, new UserDefinedElements(ci.ContainerType, ci.ContainerType, wellKnownTypes, wellKnownTypesMiscellaneous), functionCycleTracker); @@ -184,7 +184,7 @@ ITransientScopeResolutionBuilder TransientScopeResolutionBuilderFactory( ScopeRootCreateFunctionResolutionBuilderFactory, RangedFunctionGroupResolutionBuilderFactory, FunctionResolutionSynchronicityDecisionMakerFactory, - LocalFunctionResolutionBuilderFactory); + CreateFunctionResolutionBuilderFactory); IScopeResolutionBuilder ScopeResolutionBuilderFactory( string name, IContainerResolutionBuilder containerBuilder, @@ -206,13 +206,13 @@ IScopeResolutionBuilder ScopeResolutionBuilderFactory( ScopeRootCreateFunctionResolutionBuilderFactory, RangedFunctionGroupResolutionBuilderFactory, FunctionResolutionSynchronicityDecisionMakerFactory, - LocalFunctionResolutionBuilderFactory); + CreateFunctionResolutionBuilderFactory); - ILocalFunctionResolutionBuilder LocalFunctionResolutionBuilderFactory( + ICreateFunctionResolutionBuilder CreateFunctionResolutionBuilderFactory( IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, INamedTypeSymbol returnType, ImmutableSortedDictionary parameters, - string accessModifier) => new LocalFunctionResolutionBuilder( + string accessModifier) => new CreateFunctionResolutionBuilder( rangeResolutionBaseBuilder, returnType, parameters, From 3fa3e63040efcbb72422e0a087bd9c260cf6cda3 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Tue, 2 Aug 2022 18:04:44 +0200 Subject: [PATCH 117/162] Validation for Configuration Attributes --- Main/Configuration/TypesFromAttributes.cs | 497 +++++++++++++++++----- Main/SourceGenerator.cs | 9 +- 2 files changed, 385 insertions(+), 121 deletions(-) diff --git a/Main/Configuration/TypesFromAttributes.cs b/Main/Configuration/TypesFromAttributes.cs index 889c86e9..3feaee0d 100644 --- a/Main/Configuration/TypesFromAttributes.cs +++ b/Main/Configuration/TypesFromAttributes.cs @@ -77,8 +77,17 @@ internal TypesFromAttributes( IValidateAttributes validateAttributes, WellKnownTypesAggregation wellKnownTypesAggregation, WellKnownTypesChoice wellKnownTypesChoice, - WellKnownTypesMiscellaneous wellKnownTypesMiscellaneous) - : base(attributeData, rangeType, containerType, validateAttributes, wellKnownTypesAggregation, wellKnownTypesChoice, wellKnownTypesMiscellaneous) + WellKnownTypesMiscellaneous wellKnownTypesMiscellaneous, + WellKnownTypes wellKnownTypes) + : base( + attributeData, + rangeType, + containerType, + validateAttributes, + wellKnownTypesAggregation, + wellKnownTypesChoice, + wellKnownTypesMiscellaneous, + wellKnownTypes) { ContainerInstanceAbstraction = GetAbstractionTypesFromAttribute(wellKnownTypesAggregation.ContainerInstanceAbstractionAggregationAttribute); TransientScopeInstanceAbstraction = GetAbstractionTypesFromAttribute(wellKnownTypesAggregation.TransientScopeInstanceAbstractionAggregationAttribute); @@ -117,7 +126,8 @@ internal ScopeTypesFromAttributes( IValidateAttributes validateAttributes, WellKnownTypesAggregation wellKnownTypesAggregation, WellKnownTypesChoice wellKnownTypesChoice, - WellKnownTypesMiscellaneous wellKnownTypesMiscellaneous) + WellKnownTypesMiscellaneous wellKnownTypesMiscellaneous, + WellKnownTypes wellKnownTypes) { _rangeType = rangeType; _containerType = containerType; @@ -166,26 +176,74 @@ internal ScopeTypesFromAttributes( FilterTransientScopeRootImplementation = ImmutableHashSet.Empty; FilterScopeRootImplementation = ImmutableHashSet.Empty; + void NotParsableAttribute(AttributeData attributeData) => + _errors.Add(Diagnostics.ValidationConfigurationAttribute( + attributeData, + _rangeType, + _containerType, + "Not parsable attribute.")); + DecoratorSequenceChoices = ImmutableHashSet.CreateRange( (AttributeDictionary.TryGetValue(wellKnownTypesChoice.DecoratorSequenceChoiceAttribute, out var decoratorSequenceChoiceAttributes) ? decoratorSequenceChoiceAttributes : Enumerable.Empty()) .Select(ad => { - if (ad.ConstructorArguments.Length < 3) + if (ad.ConstructorArguments.Length != 3 + || ad.ConstructorArguments[0].Value is not INamedTypeSymbol interfaceType + || ad.ConstructorArguments[1].Value is not INamedTypeSymbol decoratedType) + { + NotParsableAttribute(ad); + return null; + } + + interfaceType = interfaceType.UnboundIfGeneric(); + + if (!decoratedType + .OriginalDefinition + .AllDerivedTypesAndSelf() + .Select(t => t.UnboundIfGeneric()) + .Contains(interfaceType, SymbolEqualityComparer.Default)) + { + _errors.Add(Diagnostics.ValidationConfigurationAttribute( + ad, + _rangeType, + _containerType, + $"Decorated type \"{decoratedType.FullName()}\" has to implement decorator interface \"{interfaceType.FullName()}\".")); return null; - var interfaceType = ad.ConstructorArguments[0].Value as INamedTypeSymbol; - var decoratedType = ad.ConstructorArguments[1].Value as INamedTypeSymbol; + } + var decorators = ad .ConstructorArguments[2] .Values - .Select(tc => tc.Value) + .Select(tc => + { + if (tc.Value is not INamedTypeSymbol decoratorType) + { + NotParsableAttribute(ad); + return null; + } + + if (!decoratorType + .OriginalDefinition + .AllDerivedTypesAndSelf() + .Select(t => t.UnboundIfGeneric()) + .Contains(interfaceType, SymbolEqualityComparer.Default)) + { + _errors.Add(Diagnostics.ValidationConfigurationAttribute( + ad, + _rangeType, + _containerType, + $"Decorator type \"{decoratorType.FullName()}\" has to implement decorator interface \"{interfaceType.FullName()}\".")); + return null; + } + + return decoratorType; + }) .OfType() .ToList(); - return decoratedType is null || interfaceType is null - ? null - : ((INamedTypeSymbol, INamedTypeSymbol, IReadOnlyList)?) (interfaceType, decoratedType, decorators); + return ((INamedTypeSymbol, INamedTypeSymbol, IReadOnlyList)?) (interfaceType, decoratedType, decorators); }) .OfType<(INamedTypeSymbol, INamedTypeSymbol, IReadOnlyList)>()); @@ -198,7 +256,26 @@ internal ScopeTypesFromAttributes( if (ad.ConstructorArguments.Length != 2 || ad.ConstructorArguments[0].Value is not INamedTypeSymbol interfaceType || ad.ConstructorArguments[1].Value is not INamedTypeSymbol decoratedType) + { + NotParsableAttribute(ad); return ((INamedTypeSymbol, INamedTypeSymbol)?) null; + } + + interfaceType = interfaceType.UnboundIfGeneric(); + + if (!decoratedType + .OriginalDefinition + .AllDerivedTypesAndSelf() + .Select(t => t.UnboundIfGeneric()) + .Contains(interfaceType, SymbolEqualityComparer.Default)) + { + _errors.Add(Diagnostics.ValidationConfigurationAttribute( + ad, + _rangeType, + _containerType, + $"Decorated type \"{decoratedType.FullName()}\" has to implement decorator interface \"{interfaceType.FullName()}\".")); + return null; + } return (interfaceType, decoratedType); }) @@ -211,7 +288,11 @@ internal ScopeTypesFromAttributes( .Select(ad => { if (ad.ConstructorArguments.Length < 2) - return ((INamedTypeSymbol, IList)?) null; + { + NotParsableAttribute(ad); + return ((INamedTypeSymbol, IMethodSymbol)?) null; + } + var implementationType = ad.ConstructorArguments[0].Value as INamedTypeSymbol; var parameterTypes = ad .ConstructorArguments[1] @@ -220,40 +301,53 @@ internal ScopeTypesFromAttributes( .OfType() .ToList(); - return implementationType is {} - ? (implementationType, parameterTypes) - : null; - }) - .Select(t => - { - if (t is null) return null; - - var implementationType = t.Value.Item1.OriginalDefinitionIfUnbound(); - var parameterTypes = t.Value.Item2; - - if (implementationType is null) return null; - - var constructorChoice = implementationType - .InstanceConstructors - .Where(c => c.Parameters.Length == parameterTypes.Count) - .SingleOrDefault(c => c.Parameters.Select(p => p.Type) - .Zip(parameterTypes, - (pLeft, pRight) => pLeft.Equals(pRight, SymbolEqualityComparer.Default)) - .All(b => b)); - return constructorChoice is { } - ? (implementationType, constructorChoice) - : ((INamedTypeSymbol, IMethodSymbol)?)null; + if (implementationType is { }) + { + implementationType = implementationType.OriginalDefinitionIfUnbound(); + + var constructorChoice = implementationType + .InstanceConstructors + .Where(c => c.Parameters.Length == parameterTypes.Count) + .SingleOrDefault(c => c.Parameters.Select(p => p.Type) + .Zip(parameterTypes, + (pLeft, pRight) => pLeft.Equals(pRight, SymbolEqualityComparer.Default)) + .All(b => b)); + + if (constructorChoice is { }) + { + return (implementationType, constructorChoice); + } + + _errors.Add(Diagnostics.ValidationConfigurationAttribute( + ad, + _rangeType, + _containerType, + $"Couldn't find constructor \"{implementationType.FullName()}({string.Join(", ", parameterTypes.Select(p => p.FullName()))})\".")); + + return null; + } + NotParsableAttribute(ad); + return null; }) .OfType<(INamedTypeSymbol, IMethodSymbol)>()); + INamedTypeSymbol? SingleTypeArgument(AttributeData attributeData) + { + if (attributeData.ConstructorArguments.Length != 1 + || attributeData.ConstructorArguments[0].Value is not INamedTypeSymbol type) + { + NotParsableAttribute(attributeData); + return null; + } + return type; + } + FilterConstructorChoices = ImmutableHashSet.CreateRange( (AttributeDictionary.TryGetValue(wellKnownTypesChoice.FilterConstructorChoiceAttribute, out var filterConstructorChoiceAttributes) ? filterConstructorChoiceAttributes : Enumerable.Empty()) - .Select(ad => ad.ConstructorArguments.Length < 1 - ? null - : ad.ConstructorArguments[0].Value as INamedTypeSymbol) + .Select(SingleTypeArgument) .OfType()); PropertyChoices = ImmutableHashSet.CreateRange( @@ -263,21 +357,44 @@ internal ScopeTypesFromAttributes( .Select(ad => { if (ad.ConstructorArguments.Length < 1) + { + NotParsableAttribute(ad); return ((INamedTypeSymbol, IReadOnlyList)?) null; - if (ad.ConstructorArguments[0].Value is not INamedTypeSymbol implementationType) + } + + if (ad.ConstructorArguments[0].Value is not INamedTypeSymbol implementationType) + { + NotParsableAttribute(ad); return null; + } var parameterTypes = ad .ConstructorArguments[1] .Values .Select(tc => tc.Value) .OfType() - .ToList(); + .ToImmutableHashSet(); + var propertyNames = implementationType + .OriginalDefinitionIfUnbound() + .GetMembers() + .OfType() + .Select(ps => ps.Name) + .ToImmutableHashSet(); + + foreach (var nonExistent in parameterTypes.Except(propertyNames)) + _errors.Add(Diagnostics.ValidationConfigurationAttribute( + ad, + _rangeType, + _containerType, + $"Couldn't find property \"{nonExistent}\" on \"{implementationType.FullName()}\".")); + + var pickedProperties = propertyNames.Intersect(parameterTypes); + var properties = implementationType .OriginalDefinitionIfUnbound() .GetMembers() .OfType() - .Where(ps => parameterTypes.Contains(ps.Name)) + .Where(ps => pickedProperties.Contains(ps.Name)) .ToList(); return (implementationType, properties); @@ -288,12 +405,7 @@ internal ScopeTypesFromAttributes( (AttributeDictionary.TryGetValue(wellKnownTypesChoice.FilterPropertyChoiceAttribute, out var filterPropertyChoicesGroup) ? filterPropertyChoicesGroup : Enumerable.Empty()) - .Select(ad => - { - if (ad.ConstructorArguments.Length < 1) - return null; - return ad.ConstructorArguments[0].Value as INamedTypeSymbol; - }) + .Select(SingleTypeArgument) .OfType()); TypeInitializers = ImmutableHashSet.CreateRange( @@ -302,22 +414,50 @@ internal ScopeTypesFromAttributes( : Enumerable.Empty()) .Select(ad => { - if (ad.ConstructorArguments.Length != 2 + if (ad.ConstructorArguments.Length != 2 || ad.ConstructorArguments[0].Value is not INamedTypeSymbol type || ad.ConstructorArguments[1].Value is not string methodName) + { + NotParsableAttribute(ad); return ((INamedTypeSymbol, IMethodSymbol)?) null; + } var initializationMethod = type .OriginalDefinitionIfUnbound() .GetMembers(methodName) .OfType() - .FirstOrDefault(m => m.Parameters.Length == 0); + .FirstOrDefault(); if (initializationMethod is { }) { + if (initializationMethod.Parameters.Any()) + { + _errors.Add(Diagnostics.ValidationConfigurationAttribute( + ad, + _rangeType, + _containerType, + $"If method \"{methodName}\" on \"{type.FullName()}\" is to be used as initialize method, then it isn't allowed to have parameters.")); + } + if (!initializationMethod.ReturnsVoid + && !SymbolEqualityComparer.Default.Equals(initializationMethod.ReturnType, wellKnownTypes.ValueTask) + && !SymbolEqualityComparer.Default.Equals(initializationMethod.ReturnType, wellKnownTypes.Task)) + { + _errors.Add(Diagnostics.ValidationConfigurationAttribute( + ad, + _rangeType, + _containerType, + $"If method \"{methodName}\" on \"{type.FullName()}\" is to be used as initialize method, then it should return either nothing (void), \"{wellKnownTypes.ValueTask.FullName()}\", or \"{wellKnownTypes.Task.FullName()}\".")); + return null; + } + return (type, initializationMethod); } - + + _errors.Add(Diagnostics.ValidationConfigurationAttribute( + ad, + _rangeType, + _containerType, + $"Couldn't find a method with the name \"{methodName}\" on \"{type.FullName()}\".")); return null; }) .OfType<(INamedTypeSymbol, IMethodSymbol)>()); @@ -326,12 +466,7 @@ internal ScopeTypesFromAttributes( (AttributeDictionary.TryGetValue(wellKnownTypesMiscellaneous.FilterTypeInitializerAttribute, out var filterTypeInitializerAttributes) ? filterTypeInitializerAttributes : Enumerable.Empty()) - .Select(ad => - { - if (ad.ConstructorArguments.Length != 1) - return null; - return ad.ConstructorArguments[0].Value as INamedTypeSymbol; - }) + .Select(SingleTypeArgument) .OfType()); GenericParameterSubstitutesChoices = ImmutableHashSet.CreateRange( @@ -341,12 +476,18 @@ internal ScopeTypesFromAttributes( .Select(ad => { if (ad.ConstructorArguments.Length < 3) + { + NotParsableAttribute(ad); return null; + } var genericType = ad.ConstructorArguments[0].Value as INamedTypeSymbol; - if (genericType is not { IsGenericType: true, IsUnboundGenericType: true } - || ad.ConstructorArguments[1].Value is not string nameOfGenericParameter) + if (genericType is not { IsGenericType: true, IsUnboundGenericType: true } + || ad.ConstructorArguments[1].Value is not string nameOfGenericParameter) + { + NotParsableAttribute(ad); return null; + } var typeParameterSymbol = genericType .OriginalDefinition @@ -354,16 +495,30 @@ internal ScopeTypesFromAttributes( .OfType() .FirstOrDefault(tps => tps.Name == nameOfGenericParameter); + if (typeParameterSymbol is null) + { + _errors.Add(Diagnostics.ValidationConfigurationAttribute( + ad, + _rangeType, + _containerType, + $"Couldn't find the generic type parameter with the name \"{nameOfGenericParameter}\" on \"{genericType.FullName()}\".")); + return null; + } + var substitutes = ad .ConstructorArguments[2] .Values .Select(tc => tc.Value) .OfType() .ToList(); + + if (substitutes.Count != ad.ConstructorArguments[2].Values.Length) + { + NotParsableAttribute(ad); + return null; + } - return typeParameterSymbol is null - ? null - : ((INamedTypeSymbol, ITypeParameterSymbol, IReadOnlyList)?) (genericType, typeParameterSymbol, substitutes); + return ((INamedTypeSymbol, ITypeParameterSymbol, IReadOnlyList)?) (genericType, typeParameterSymbol, substitutes); }) .OfType<(INamedTypeSymbol, ITypeParameterSymbol, IReadOnlyList)>()); @@ -374,24 +529,38 @@ internal ScopeTypesFromAttributes( .Select(ad => { if (ad.ConstructorArguments.Length < 3) + { + NotParsableAttribute(ad); return null; + } var genericType = ad.ConstructorArguments[0].Value as INamedTypeSymbol; var typeChoice = ad.ConstructorArguments[2].Value as INamedTypeSymbol; - if (genericType is not { IsGenericType: true, IsUnboundGenericType: true } + if (genericType is not { IsGenericType: true, IsUnboundGenericType: true } || ad.ConstructorArguments[1].Value is not string nameOfGenericParameter - || typeChoice is null) + || typeChoice is null) + { + NotParsableAttribute(ad); return null; + } var typeParameterSymbol = genericType .OriginalDefinition .TypeArguments .OfType() .FirstOrDefault(tps => tps.Name == nameOfGenericParameter); + + if (typeParameterSymbol is null) + { + _errors.Add(Diagnostics.ValidationConfigurationAttribute( + ad, + _rangeType, + _containerType, + $"Couldn't find the generic type parameter with the name \"{nameOfGenericParameter}\" on \"{genericType.FullName()}\".")); + return null; + } - return typeParameterSymbol is null - ? null - : ((INamedTypeSymbol, ITypeParameterSymbol, INamedTypeSymbol)?) (genericType, typeParameterSymbol, typeChoice); + return ((INamedTypeSymbol, ITypeParameterSymbol, INamedTypeSymbol)?) (genericType, typeParameterSymbol, typeChoice); }) .OfType<(INamedTypeSymbol, ITypeParameterSymbol, INamedTypeSymbol)>()); @@ -402,22 +571,36 @@ internal ScopeTypesFromAttributes( .Select(ad => { if (ad.ConstructorArguments.Length < 2) + { + NotParsableAttribute(ad); return null; + } var genericType = ad.ConstructorArguments[0].Value as INamedTypeSymbol; - if (genericType is not { IsGenericType: true, IsUnboundGenericType: true } - || ad.ConstructorArguments[1].Value is not string nameOfGenericParameter) + if (genericType is not { IsGenericType: true, IsUnboundGenericType: true } + || ad.ConstructorArguments[1].Value is not string nameOfGenericParameter) + { + NotParsableAttribute(ad); return null; + } var typeParameterSymbol = genericType .OriginalDefinition .TypeArguments .OfType() .FirstOrDefault(tps => tps.Name == nameOfGenericParameter); + + if (typeParameterSymbol is null) + { + _errors.Add(Diagnostics.ValidationConfigurationAttribute( + ad, + _rangeType, + _containerType, + $"Couldn't find the generic type parameter with the name \"{nameOfGenericParameter}\" on \"{genericType.FullName()}\".")); + return null; + } - return typeParameterSymbol is null - ? null - : ((INamedTypeSymbol, ITypeParameterSymbol)?) (genericType, typeParameterSymbol); + return ((INamedTypeSymbol, ITypeParameterSymbol)?) (genericType, typeParameterSymbol); }) .OfType<(INamedTypeSymbol, ITypeParameterSymbol)>()); @@ -428,22 +611,36 @@ internal ScopeTypesFromAttributes( .Select(ad => { if (ad.ConstructorArguments.Length < 2) + { + NotParsableAttribute(ad); return null; + } var genericType = ad.ConstructorArguments[0].Value as INamedTypeSymbol; - if (genericType is not { IsGenericType: true, IsUnboundGenericType: true } - || ad.ConstructorArguments[1].Value is not string nameOfGenericParameter) + if (genericType is not { IsGenericType: true, IsUnboundGenericType: true } + || ad.ConstructorArguments[1].Value is not string nameOfGenericParameter) + { + NotParsableAttribute(ad); return null; + } var typeParameterSymbol = genericType .OriginalDefinition .TypeArguments .OfType() .FirstOrDefault(tps => tps.Name == nameOfGenericParameter); + + if (typeParameterSymbol is null) + { + _errors.Add(Diagnostics.ValidationConfigurationAttribute( + ad, + _rangeType, + _containerType, + $"Couldn't find the generic type parameter with the name \"{nameOfGenericParameter}\" on \"{genericType.FullName()}\".")); + return null; + } - return typeParameterSymbol is null - ? null - : ((INamedTypeSymbol, ITypeParameterSymbol)?) (genericType, typeParameterSymbol); + return ((INamedTypeSymbol, ITypeParameterSymbol)?) (genericType, typeParameterSymbol); }) .OfType<(INamedTypeSymbol, ITypeParameterSymbol)>()); @@ -457,46 +654,86 @@ internal ScopeTypesFromAttributes( : Enumerable.Empty()) .Any(); - AssemblyImplementations = ImmutableHashSet.CreateRange( - (AttributeDictionary.TryGetValue(wellKnownTypesAggregation.AssemblyImplementationsAggregationAttribute, out var assemblyImplementationsAttributes) - ? assemblyImplementationsAttributes - : Enumerable.Empty()) - .SelectMany(ad => ad.ConstructorArguments.Length < 1 - ? Array.Empty() - : ad.ConstructorArguments[0] - .Values - .Select(tc => tc.Value) - .OfType() - .Select(t => t.ContainingAssembly) - .OfType()) - .Distinct(SymbolEqualityComparer.Default) - .OfType()); - - FilterAssemblyImplementations = ImmutableHashSet.CreateRange( - (AttributeDictionary.TryGetValue(wellKnownTypesAggregation.FilterAssemblyImplementationsAggregationAttribute, out var filterAssemblyImplementationsAttributes) - ? filterAssemblyImplementationsAttributes - : Enumerable.Empty()) - .SelectMany(ad => ad.ConstructorArguments.Length < 1 - ? Array.Empty() - : ad.ConstructorArguments[0] - .Values - .Select(tc => tc.Value) - .OfType() - .Select(t => t.ContainingAssembly) - .OfType()) - .Distinct(SymbolEqualityComparer.Default) - .OfType()); + IImmutableSet GetAssemblies(INamedTypeSymbol attributeType) => + ImmutableHashSet.CreateRange( + (AttributeDictionary.TryGetValue(attributeType, out var assemblyImplementationsAttributes) + ? assemblyImplementationsAttributes + : Enumerable.Empty()) + .SelectMany(ad => ad.ConstructorArguments.Length < 1 + ? Array.Empty() + : ad.ConstructorArguments[0] + .Values + .Select(tc => + { + if (tc.Value is not INamedTypeSymbol) + { + NotParsableAttribute(ad); + return null; + } + return tc.Value; + }) + .OfType() + .Select(t => + { + if (t.ContainingAssembly is null) + { + _errors.Add(Diagnostics.ValidationConfigurationAttribute( + ad, + _rangeType, + _containerType, + $"Type \"{t.FullName()}\" doesn't lead to a single known assembly.")); + } + return t.ContainingAssembly; + }) + .OfType()) + .Distinct(SymbolEqualityComparer.Default) + .OfType()); + + AssemblyImplementations = GetAssemblies(wellKnownTypesAggregation.AssemblyImplementationsAggregationAttribute); + + FilterAssemblyImplementations = GetAssemblies(wellKnownTypesAggregation.FilterAssemblyImplementationsAggregationAttribute); ImplementationChoices = ImmutableHashSet.CreateRange( (AttributeDictionary.TryGetValue(wellKnownTypesChoice.ImplementationChoiceAttribute, out var implementationChoiceAttributes) ? implementationChoiceAttributes : Enumerable.Empty()) - .Select(ad => - ad.ConstructorArguments.Length < 2 - || ad.ConstructorArguments[0].Value is not INamedTypeSymbol type - || ad.ConstructorArguments[1].Value is not INamedTypeSymbol implementation - ? null - : ((INamedTypeSymbol, INamedTypeSymbol)?) (type, implementation)) + .Select(ad => + { + if (ad.ConstructorArguments.Length < 2 + || ad.ConstructorArguments[0].Value is not INamedTypeSymbol type + || ad.ConstructorArguments[1].Value is not INamedTypeSymbol implementation) + { + NotParsableAttribute(ad); + return null; + } + + if (!validateAttributes.ValidateImplementation(implementation)) + { + _errors.Add(Diagnostics.ValidationConfigurationAttribute( + ad, + _rangeType, + _containerType, + $"Type \"{implementation.FullName()}\" has to be an implementation.")); + return null; + } + + var unboundType = type.UnboundIfGeneric(); + if (!implementation + .OriginalDefinitionIfUnbound() + .AllDerivedTypesAndSelf() + .Select(t => t.UnboundIfGeneric()) + .Contains(unboundType, SymbolEqualityComparer.Default)) + { + _errors.Add(Diagnostics.ValidationConfigurationAttribute( + ad, + _rangeType, + _containerType, + $"Type \"{implementation.FullName()}\" has to implement \"{type.FullName()}\".")); + return null; + } + + return ((INamedTypeSymbol, INamedTypeSymbol)?)(type, implementation); + }) .OfType<(INamedTypeSymbol, INamedTypeSymbol)>()); ImplementationCollectionChoices = ImmutableHashSet.CreateRange( @@ -505,21 +742,45 @@ internal ScopeTypesFromAttributes( : Enumerable.Empty()) .Select(ad => { - if (ad.ConstructorArguments.Length < 2) + if (ad.ConstructorArguments.Length < 2 + || ad.ConstructorArguments[0].Value is not INamedTypeSymbol type) + { + NotParsableAttribute(ad); return null; - - var type = ad.ConstructorArguments[0].Value as INamedTypeSymbol; - + } + + var unboundType = type.UnboundIfGeneric(); var implementations = ad .ConstructorArguments[1] .Values - .Select(tc => tc.Value) + .Select(tc => + { + if (tc.Value is not INamedTypeSymbol implementation) + { + NotParsableAttribute(ad); + return null; + } + + if (!implementation + .OriginalDefinitionIfUnbound() + .AllDerivedTypesAndSelf() + .Select(t => t.UnboundIfGeneric()) + .Contains(unboundType, SymbolEqualityComparer.Default)) + { + _errors.Add(Diagnostics.ValidationConfigurationAttribute( + ad, + _rangeType, + _containerType, + $"Type \"{implementation.FullName()}\" has to implement \"{type.FullName()}\".")); + return null; + } + + return tc.Value; + }) .OfType() .ToList(); - return type is null - ? null - : ((INamedTypeSymbol, IReadOnlyList)?) (type, implementations); + return ((INamedTypeSymbol, IReadOnlyList)?) (type, implementations); }) .OfType<(INamedTypeSymbol, IReadOnlyList)>()); diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index cd497e83..f5d0aeb7 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -68,7 +68,8 @@ public void Execute(GeneratorExecutionContext context) validateAttributes, wellKnownTypesAggregation, wellKnownTypesChoice, - wellKnownTypesMiscellaneous); + wellKnownTypesMiscellaneous, + wellKnownTypes); foreach (var diagnostic in assemblyTypesFromAttributes .Warnings @@ -102,7 +103,8 @@ IContainerResolutionBuilder ResolutionTreeFactory(IContainerInfo ci) validateAttributes, wellKnownTypesAggregation, wellKnownTypesChoice, - wellKnownTypesMiscellaneous); + wellKnownTypesMiscellaneous, + wellKnownTypes); foreach (var diagnostic in containerTypesFromAttributes.Warnings) diagLogger.Log(diagnostic); @@ -148,7 +150,8 @@ IScopeManager ScopeManagerFactory( validateAttributes, wellKnownTypesAggregation, wellKnownTypesChoice, - wellKnownTypesMiscellaneous); + wellKnownTypesMiscellaneous, + wellKnownTypes); foreach (var diagnostic in scopeTypesFromAttributes.Warnings) diagLogger.Log(diagnostic); From 98f43a9da44e91529aeaec6c3f35d9e8aa5107af Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Tue, 2 Aug 2022 18:18:21 +0200 Subject: [PATCH 118/162] Small fix --- Main/Configuration/TypesFromAttributes.cs | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/Main/Configuration/TypesFromAttributes.cs b/Main/Configuration/TypesFromAttributes.cs index 3feaee0d..db94d033 100644 --- a/Main/Configuration/TypesFromAttributes.cs +++ b/Main/Configuration/TypesFromAttributes.cs @@ -800,11 +800,12 @@ protected IImmutableSet GetAbstractionTypesFromAttribute( { var ret = _validateAttributes.ValidateAbstraction(t.Item2); - _warnings.Add(Diagnostics.ValidationConfigurationAttribute( - t.Item1, - _rangeType, - _containerType, - $"Given type \"{t.Item2.FullName()}\" isn't a valid abstraction type. It'll be ignored.")); + if (!ret) + _warnings.Add(Diagnostics.ValidationConfigurationAttribute( + t.Item1, + _rangeType, + _containerType, + $"Given type \"{t.Item2.FullName()}\" isn't a valid abstraction type. It'll be ignored.")); return ret; }) @@ -820,11 +821,12 @@ protected IImmutableSet GetImplementationTypesFromAttribute( { var ret = _validateAttributes.ValidateImplementation(t.Item2); - _warnings.Add(Diagnostics.ValidationConfigurationAttribute( - t.Item1, - _rangeType, - _containerType, - $"Given type \"{t.Item2.FullName()}\" isn't a valid implementation type. It'll be ignored.")); + if (!ret) + _warnings.Add(Diagnostics.ValidationConfigurationAttribute( + t.Item1, + _rangeType, + _containerType, + $"Given type \"{t.Item2.FullName()}\" isn't a valid implementation type. It'll be ignored.")); return ret; }) From 72047f263b83708e62d1349110701fd315639d9a Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Wed, 3 Aug 2022 17:30:39 +0200 Subject: [PATCH 119/162] Fixed bug --- .../Function/FunctionResolutionBuilder.cs | 8 +--- Sample/Context.cs | 37 +++++++++---------- Test/Decorator/ContainerInstance.cs | 26 ++++++++----- 3 files changed, 35 insertions(+), 36 deletions(-) diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs index 2ba2e14a..b65c82a1 100644 --- a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs @@ -639,11 +639,7 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup var (implementationType, currentParameters, implementationStack) = parameter; var scopeLevel = parameter switch { - SwitchImplementationParameterWithComposition withComposition => - withComposition.Composition.ImplementationTypes.Select(i => _checkTypeProperties.GetScopeLevelFor(i)) - .Min(), - SwitchImplementationParameterWithDecoration withDecoration => _checkTypeProperties.GetScopeLevelFor( - withDecoration.Decoration.ImplementationType), + SwitchImplementationParameterWithDecoration or SwitchImplementationParameterWithComposition => ScopeLevel.None, _ => _checkTypeProperties.GetScopeLevelFor(parameter.ImplementationType) }; var nextParameter = parameter switch @@ -667,8 +663,6 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup var ret = scopeLevel switch { - >= ScopeLevel.Scope when parameter is SwitchImplementationParameterWithDecoration or SwitchImplementationParameterWithDecoration => - (_rangeResolutionBaseBuilder.CreateScopeInstanceReferenceResolution(nextParameter), null), ScopeLevel.Container => (_rangeResolutionBaseBuilder.CreateContainerInstanceReferenceResolution(nextParameter), null), ScopeLevel.TransientScope => diff --git a/Sample/Context.cs b/Sample/Context.cs index d1fc66b6..52f83b14 100644 --- a/Sample/Context.cs +++ b/Sample/Context.cs @@ -1,37 +1,34 @@ -using System; +using System.Collections.Generic; using MrMeeseeks.DIE.Configuration.Attributes; using MrMeeseeks.DIE.Sample; -namespace MrMeeseeks.DIE.Test.Func.OverrideScoped; +namespace MrMeeseeks.DIE.Test.Decorator.ContainerInstanceMultipeImplementations; -internal class DependencyInner +internal interface IInterface { - internal DependencyInner( - Lazy lazyParent, - string asdf) - { - - } + IInterface Decorated { get; } } -internal class Dependency +internal class DependencyA : IInterface, IContainerInstance { - public int Value { get; } + public IInterface Decorated => this; +} - internal Dependency(int value, Func fac) => Value = value; +internal class DependencyB : IInterface, IContainerInstance +{ + public IInterface Decorated => this; } -internal class Parent : IScopeRoot +internal class Decorator : IInterface, IDecorator { - public Dependency Dependency { get; } - - internal Parent( - Func fac) => - Dependency = fac(1); + public Decorator(IInterface decoratedContainerInstance) => + Decorated = decoratedContainerInstance; + + public IInterface Decorated { get; } } -[CreateFunction(typeof(Parent), "Create")] +[CreateFunction(typeof(IReadOnlyList), "Create")] internal sealed partial class Container { - private int DIE_Factory_int => 0; + } \ No newline at end of file diff --git a/Test/Decorator/ContainerInstance.cs b/Test/Decorator/ContainerInstance.cs index d07b3f7f..5f0578b3 100644 --- a/Test/Decorator/ContainerInstance.cs +++ b/Test/Decorator/ContainerInstance.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -9,7 +10,12 @@ internal interface IInterface IInterface Decorated { get; } } -internal class Dependency : IInterface, IContainerInstance +internal class DependencyA : IInterface, IContainerInstance +{ + public IInterface Decorated => this; +} + +internal class DependencyB : IInterface, IContainerInstance { public IInterface Decorated => this; } @@ -22,7 +28,7 @@ public Decorator(IInterface decoratedContainerInstance) => public IInterface Decorated { get; } } -[CreateFunction(typeof(IInterface), "Create")] +[CreateFunction(typeof(IReadOnlyList), "Create")] internal sealed partial class Container { @@ -34,13 +40,15 @@ public class Tests public async ValueTask Test() { await using var container = new Container(); - var decorated = container.Create(); - Assert.NotEqual(decorated, decorated.Decorated); - Assert.IsType(decorated); - Assert.IsType(decorated.Decorated); + var collection = container.Create(); - var decoratedNextReference = container.Create(); - Assert.Equal(decorated, decoratedNextReference); - Assert.Equal(decorated.Decorated, decoratedNextReference.Decorated); + Assert.NotEqual(collection[0], collection[1]); + Assert.NotEqual(collection[0].Decorated, collection[1].Decorated); + Assert.NotEqual(collection[0], collection[0].Decorated); + Assert.NotEqual(collection[1], collection[1].Decorated); + Assert.IsType(collection[0]); + Assert.IsType(collection[1]); + Assert.True(typeof(DependencyA) == collection[0].Decorated.GetType() && typeof(DependencyB) == collection[1].Decorated.GetType() + || typeof(DependencyB) == collection[0].Decorated.GetType() && typeof(DependencyA) == collection[1].Decorated.GetType()); } } \ No newline at end of file From 74507e1b2f31f1c3e27798c929631ed9eeac3dd4 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sat, 6 Aug 2022 17:28:14 +0200 Subject: [PATCH 120/162] Async support for factories --- Main/CodeBuilding/RangeCodeBaseBuilder.cs | 8 +- .../Function/FunctionResolutionBuilder.cs | 110 +++++++++++++++--- Main/ResolutionTreeItem.cs | 6 +- .../FactoryInContainercsTask.cs | 30 +++++ .../FactoryInContainercsValueTask.cs | 30 +++++ .../CustomEmbedding/FieldInContainercsTask.cs | 30 +++++ .../FieldInContainercsValueTask.cs | 30 +++++ ...nContainercs.cs => PropertyInContainer.cs} | 0 .../PropertyInContainerTask.cs | 30 +++++ .../PropertyInContainerValueTask.cs | 30 +++++ 10 files changed, 285 insertions(+), 19 deletions(-) create mode 100644 Test/CustomEmbedding/FactoryInContainercsTask.cs create mode 100644 Test/CustomEmbedding/FactoryInContainercsValueTask.cs create mode 100644 Test/CustomEmbedding/FieldInContainercsTask.cs create mode 100644 Test/CustomEmbedding/FieldInContainercsValueTask.cs rename Test/CustomEmbedding/{PropertyInContainercs.cs => PropertyInContainer.cs} (100%) create mode 100644 Test/CustomEmbedding/PropertyInContainerTask.cs create mode 100644 Test/CustomEmbedding/PropertyInContainerValueTask.cs diff --git a/Main/CodeBuilding/RangeCodeBaseBuilder.cs b/Main/CodeBuilding/RangeCodeBaseBuilder.cs index 9504ec03..2904548b 100644 --- a/Main/CodeBuilding/RangeCodeBaseBuilder.cs +++ b/Main/CodeBuilding/RangeCodeBaseBuilder.cs @@ -419,13 +419,13 @@ private StringBuilder GenerateResolutions( case NullResolution(var reference, var typeFullName): stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference} = ({typeFullName}) null;"); break; - case FieldResolution(var reference, var typeFullName, var fieldName): - stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference} = this.{fieldName};"); + case FieldResolution(var reference, var typeFullName, var fieldName, var isAwait): + stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference} = {(isAwait ? "await " : "")}this.{fieldName};"); break; - case FactoryResolution(var reference, var typeFullName, var functionName, var parameters): + case FactoryResolution(var reference, var typeFullName, var functionName, var parameters, bool isAwait): stringBuilder = parameters.Aggregate(stringBuilder, (builder, tuple) => GenerateResolutions(builder, tuple.Dependency ?? throw new Exception())); - stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference} = this.{functionName}({string.Join(", ", parameters.Select(t => $"{t.Name}: {t.Dependency.Reference}"))});"); + stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference} = {(isAwait ? "await " : "")}this.{functionName}({string.Join(", ", parameters.Select(t => $"{t.Name}: {t.Dependency.Reference}"))});"); break; case CollectionResolution(var reference, var typeFullName, var itemFullName, var items): stringBuilder = items.OfType().Aggregate(stringBuilder, GenerateResolutions); diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs index b65c82a1..110bbf5e 100644 --- a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs @@ -15,16 +15,18 @@ internal interface IFunctionResolutionSynchronicityDecisionMaker Lazy Decision { get; } void Register(IAwaitableResolution awaitableResolution); + void ForceAwait(); } internal class FunctionResolutionSynchronicityDecisionMaker : IFunctionResolutionSynchronicityDecisionMaker { private readonly ISet _potentialAwaits = new HashSet(); + private bool _forceAwait; public Lazy Decision { get; } public FunctionResolutionSynchronicityDecisionMaker() => - Decision = new(() => _potentialAwaits.Any(pa => pa.Await) + Decision = new(() => _forceAwait || _potentialAwaits.Any(pa => pa.Await) ? SynchronicityDecision.AsyncValueTask : SynchronicityDecision.Sync); @@ -37,6 +39,8 @@ public void Register(IAwaitableResolution awaitableResolution) _potentialAwaits.Add(awaitableResolution); } + + public void ForceAwait() => _forceAwait = true; } internal interface IFunctionResolutionBuilder : IResolutionBuilder @@ -125,33 +129,113 @@ private string ErrorMessage(IImmutableStack stack, ITypeSymbol t.Value.Item1.OriginalDefinition, type.OriginalDefinition)) is { Value.Item1: not null, Value.Item2: not null } funcParameter) return (funcParameter.Value.Item2, null); + var valueTaskedType = _wellKnownTypes.ValueTask1.Construct(type); + var taskedType = _wellKnownTypes.Task1.Construct(type); + if (_userDefinedElements.GetFactoryFieldFor(type) is { } instance) return ( new FieldResolution( - RootReferenceGenerator.Generate(instance.Type), - instance.Type.FullName(), - instance.Name), + RootReferenceGenerator.Generate(type), + type.FullName(), + instance.Name, + false), + null); + if (_userDefinedElements.GetFactoryFieldFor(valueTaskedType) is { } valueTaskedInstance) + { + _synchronicityDecisionMaker.ForceAwait(); + return ( + new FieldResolution( + RootReferenceGenerator.Generate(type), + type.FullName(), + valueTaskedInstance.Name, + true), null); + } + if (_userDefinedElements.GetFactoryFieldFor(taskedType) is { } taskedInstance) + { + _synchronicityDecisionMaker.ForceAwait(); + return ( + new FieldResolution( + RootReferenceGenerator.Generate(type), + type.FullName(), + taskedInstance.Name, + true), + null); + } if (_userDefinedElements.GetFactoryPropertyFor(type) is { } property) return ( new FieldResolution( - RootReferenceGenerator.Generate(property.Type), - property.Type.FullName(), - property.Name), + RootReferenceGenerator.Generate(type), + type.FullName(), + property.Name, + false), + null); + if (_userDefinedElements.GetFactoryPropertyFor(valueTaskedType) is { } valueTaskedProperty) + { + _synchronicityDecisionMaker.ForceAwait(); + return ( + new FieldResolution( + RootReferenceGenerator.Generate(type), + type.FullName(), + valueTaskedProperty.Name, + true), + null); + } + if (_userDefinedElements.GetFactoryPropertyFor(taskedType) is { } taskedProperty) + { + _synchronicityDecisionMaker.ForceAwait(); + return ( + new FieldResolution( + RootReferenceGenerator.Generate(type), + type.FullName(), + taskedProperty.Name, + true), null); + } - if (_userDefinedElements.GetFactoryMethodFor(type) is { } factory) + if (_userDefinedElements.GetFactoryMethodFor(type) is { } method) return ( new FactoryResolution( - RootReferenceGenerator.Generate(factory.ReturnType), - factory.ReturnType.FullName(), - factory.Name, - factory + RootReferenceGenerator.Generate(type), + type.FullName(), + method.Name, + method .Parameters .Select(p => (p.Name, SwitchType(new SwitchTypeParameter(p.Type, currentFuncParameters, implementationStack)).Item1)) - .ToList()), + .ToList(), + false), null); + if (_userDefinedElements.GetFactoryMethodFor(valueTaskedType) is { } valueTaskedMethod) + { + _synchronicityDecisionMaker.ForceAwait(); + return ( + new FactoryResolution( + RootReferenceGenerator.Generate(type), + type.FullName(), + valueTaskedMethod.Name, + valueTaskedMethod + .Parameters + .Select(p => (p.Name, SwitchType(new SwitchTypeParameter(p.Type, currentFuncParameters, implementationStack)).Item1)) + .ToList(), + true), + null); + } + if (_userDefinedElements.GetFactoryMethodFor(taskedType) is { } taskedMethod) + { + _synchronicityDecisionMaker.ForceAwait(); + return ( + new FactoryResolution( + RootReferenceGenerator.Generate(type), + type.FullName(), + taskedMethod.Name, + taskedMethod + .Parameters + .Select(p => (p.Name, SwitchType(new SwitchTypeParameter(p.Type, currentFuncParameters, implementationStack)).Item1)) + .ToList(), + true), + null); + } if (type.OriginalDefinition.Equals(_wellKnownTypes.Task1, SymbolEqualityComparer.Default) && type is INamedTypeSymbol task) diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index 5a137ccc..3fff2a58 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -162,7 +162,8 @@ internal record FactoryResolution( string Reference, string TypeFullName, string FunctionName, - IReadOnlyList<(string Name, Resolvable Dependency)> Parameter) : Resolvable(Reference, TypeFullName); + IReadOnlyList<(string Name, Resolvable Dependency)> Parameter, + bool Await) : Resolvable(Reference, TypeFullName); internal record OutParameterResolution( string Reference, @@ -304,7 +305,8 @@ internal record NullResolution( internal record FieldResolution( string Reference, string TypeFullName, - string FieldName) : Resolvable(Reference, TypeFullName); + string FieldName, + bool Await) : Resolvable(Reference, TypeFullName); internal abstract record TaskBaseResolution( Resolvable WrappedResolvable, diff --git a/Test/CustomEmbedding/FactoryInContainercsTask.cs b/Test/CustomEmbedding/FactoryInContainercsTask.cs new file mode 100644 index 00000000..a2a6ee03 --- /dev/null +++ b/Test/CustomEmbedding/FactoryInContainercsTask.cs @@ -0,0 +1,30 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CustomEmbedding.FactoryInContainerTask; + +internal class Wrapper +{ + public Task Property { get; } + + internal Wrapper(Task property) => Property = property; +} + +[CreateFunction(typeof(Wrapper), "Create")] +internal sealed partial class Container +{ + private Task DIE_Factory_Yeah() => Task.FromResult("Yeah"); +} + +public class Tests +{ + + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var wrapper = container.Create(); + Assert.Equal("Yeah", await wrapper.Property.ConfigureAwait(false)); + } +} \ No newline at end of file diff --git a/Test/CustomEmbedding/FactoryInContainercsValueTask.cs b/Test/CustomEmbedding/FactoryInContainercsValueTask.cs new file mode 100644 index 00000000..8a67fcef --- /dev/null +++ b/Test/CustomEmbedding/FactoryInContainercsValueTask.cs @@ -0,0 +1,30 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CustomEmbedding.FactoryInContainerValueTask; + +internal class Wrapper +{ + public string Property { get; } + + internal Wrapper(string property) => Property = property; +} + +[CreateFunction(typeof(Wrapper), "Create")] +internal sealed partial class Container +{ + private ValueTask DIE_Factory_Yeah() => ValueTask.FromResult("Yeah"); +} + +public class Tests +{ + + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var wrapper = await container.CreateValueAsync().ConfigureAwait(false); + Assert.Equal("Yeah", wrapper.Property); + } +} \ No newline at end of file diff --git a/Test/CustomEmbedding/FieldInContainercsTask.cs b/Test/CustomEmbedding/FieldInContainercsTask.cs new file mode 100644 index 00000000..c3536d83 --- /dev/null +++ b/Test/CustomEmbedding/FieldInContainercsTask.cs @@ -0,0 +1,30 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CustomEmbedding.FieldInContainerTask; + +internal class Wrapper +{ + public Task Property { get; } + + internal Wrapper(Task property) => Property = property; +} + +[CreateFunction(typeof(Wrapper), "Create")] +internal sealed partial class Container +{ + private readonly Task DIE_Factory_Yeah = Task.FromResult("Yeah"); +} + +public class Tests +{ + + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var wrapper = container.Create(); + Assert.Equal("Yeah", await wrapper.Property.ConfigureAwait(false)); + } +} \ No newline at end of file diff --git a/Test/CustomEmbedding/FieldInContainercsValueTask.cs b/Test/CustomEmbedding/FieldInContainercsValueTask.cs new file mode 100644 index 00000000..675419d2 --- /dev/null +++ b/Test/CustomEmbedding/FieldInContainercsValueTask.cs @@ -0,0 +1,30 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CustomEmbedding.FieldInContainerValueTask; + +internal class Wrapper +{ + public string Property { get; } + + internal Wrapper(string property) => Property = property; +} + +[CreateFunction(typeof(Wrapper), "Create")] +internal sealed partial class Container +{ + private readonly ValueTask DIE_Factory_Yeah = ValueTask.FromResult("Yeah"); +} + +public class Tests +{ + + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var wrapper = await container.CreateValueAsync().ConfigureAwait(false); + Assert.Equal("Yeah", wrapper.Property); + } +} \ No newline at end of file diff --git a/Test/CustomEmbedding/PropertyInContainercs.cs b/Test/CustomEmbedding/PropertyInContainer.cs similarity index 100% rename from Test/CustomEmbedding/PropertyInContainercs.cs rename to Test/CustomEmbedding/PropertyInContainer.cs diff --git a/Test/CustomEmbedding/PropertyInContainerTask.cs b/Test/CustomEmbedding/PropertyInContainerTask.cs new file mode 100644 index 00000000..3aa6e98e --- /dev/null +++ b/Test/CustomEmbedding/PropertyInContainerTask.cs @@ -0,0 +1,30 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CustomEmbedding.PropertyInContainerTask; + +internal class Wrapper +{ + public Task Property { get; } + + internal Wrapper(Task property) => Property = property; +} + +[CreateFunction(typeof(Wrapper), "Create")] +internal sealed partial class Container +{ + private Task DIE_Factory_Yeah => Task.FromResult("Yeah"); +} + +public class Tests +{ + + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var wrapper = container.Create(); + Assert.Equal("Yeah", await wrapper.Property.ConfigureAwait(false)); + } +} \ No newline at end of file diff --git a/Test/CustomEmbedding/PropertyInContainerValueTask.cs b/Test/CustomEmbedding/PropertyInContainerValueTask.cs new file mode 100644 index 00000000..2aeb2cf6 --- /dev/null +++ b/Test/CustomEmbedding/PropertyInContainerValueTask.cs @@ -0,0 +1,30 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CustomEmbedding.PropertyInContainerValueTask; + +internal class Wrapper +{ + public string Property { get; } + + internal Wrapper(string property) => Property = property; +} + +[CreateFunction(typeof(Wrapper), "Create")] +internal sealed partial class Container +{ + private ValueTask DIE_Factory_Yeah => ValueTask.FromResult("Yeah"); +} + +public class Tests +{ + + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var wrapper = await container.CreateValueAsync().ConfigureAwait(false); + Assert.Equal("Yeah", wrapper.Property); + } +} \ No newline at end of file From d721bbd399c11e2d4ab928f8d4eeb11fa827743b Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Thu, 11 Aug 2022 21:06:15 +0200 Subject: [PATCH 121/162] Dispose-lock with no-managed-disposables and updated nuget packages --- Main/CodeBuilding/RangeCodeBaseBuilder.cs | 37 +++++++++++------- Main/Main.csproj | 10 ++--- Sample/Container.cs | 46 +++++++++++++++-------- Sample/Context.cs | 34 ----------------- Sample/MarkerInterfaces.cs | 20 ++++++++++ Sample/Sample.csproj | 2 +- Test/Test.csproj | 10 ++--- 7 files changed, 85 insertions(+), 74 deletions(-) delete mode 100644 Sample/Context.cs diff --git a/Main/CodeBuilding/RangeCodeBaseBuilder.cs b/Main/CodeBuilding/RangeCodeBaseBuilder.cs index 2904548b..36fec608 100644 --- a/Main/CodeBuilding/RangeCodeBaseBuilder.cs +++ b/Main/CodeBuilding/RangeCodeBaseBuilder.cs @@ -59,11 +59,21 @@ private StringBuilder GenerateDisposalFunction( StringBuilder stringBuilder, RangeResolution rangeResolution) { + var disposalHandling = rangeResolution.DisposalHandling; if (_containerResolution.DisposalType == DisposalType.None) { return stringBuilder - .AppendLine("public void Dispose() {}") - .AppendLine($"public {WellKnownTypes.ValueTask.FullName()} DisposeAsync() => new {WellKnownTypes.ValueTask.FullName()}({WellKnownTypes.Task.FullName()}.CompletedTask);"); + .AppendLine($"private int {disposalHandling.DisposedFieldReference} = 0;") + .AppendLine($"private bool {disposalHandling.DisposedPropertyReference} => {disposalHandling.DisposedFieldReference} != 0;") + .AppendLine("public void Dispose()") + .AppendLine("{") + .AppendLine($"var {disposalHandling.DisposedLocalReference} = global::System.Threading.Interlocked.Exchange(ref this.{disposalHandling.DisposedFieldReference}, 1);") + .AppendLine("}") + .AppendLine($"public {WellKnownTypes.ValueTask.FullName()} DisposeAsync()") + .AppendLine("{") + .AppendLine($"Dispose();") + .AppendLine($"return new {WellKnownTypes.ValueTask.FullName()}({WellKnownTypes.Task.FullName()}.CompletedTask);") + .AppendLine("}"); } var returnType = _containerResolution.DisposalType switch @@ -86,7 +96,6 @@ private StringBuilder GenerateDisposalFunction( stringBuilder = GenerateDisposalFunction_TransientScopeDictionary(stringBuilder); - var disposalHandling = rangeResolution.DisposalHandling; if (_containerResolution.DisposalType == DisposalType.Async) { stringBuilder = stringBuilder.AppendLine( @@ -176,11 +185,10 @@ private StringBuilder GenerateResolutionFunction( stringBuilder = stringBuilder .AppendLine($"{resolution.AccessModifier} {(localFunctionResolution.SynchronicityDecision is SynchronicityDecision.AsyncTask or SynchronicityDecision.AsyncValueTask ? "async " : "")}{resolution.TypeFullName} {resolution.Reference}({parameter})") .AppendLine($"{{"); - if (_containerResolution.DisposalType != DisposalType.None) - stringBuilder = stringBuilder - .AppendLine($"if (this.{_rangeResolution.DisposalHandling.DisposedPropertyReference}) throw new {WellKnownTypes.ObjectDisposedException}(\"\");"); - - stringBuilder = GenerateResolutionFunctionContent(stringBuilder, resolution.Resolvable) + stringBuilder = ObjectDisposedCheck(stringBuilder, resolution.TypeFullName); + stringBuilder = GenerateResolutionFunctionContent(stringBuilder, resolution.Resolvable); + stringBuilder = ObjectDisposedCheck(stringBuilder, resolution.TypeFullName); + stringBuilder = stringBuilder .AppendLine($"return {resolution.Resolvable.Reference};") .AppendLine($"}}"); @@ -443,6 +451,9 @@ private StringBuilder GenerateResolutions( protected abstract bool ExplicitTransientScopeInstanceImplementation { get; } + private StringBuilder ObjectDisposedCheck(StringBuilder stringBuilder, string returnTypeFullName) => stringBuilder + .AppendLine($"if (this.{_rangeResolution.DisposalHandling.DisposedPropertyReference}) throw new {WellKnownTypes.ObjectDisposedException}(\"{_rangeResolution.DisposalHandling.RangeName}\", $\"[DIE] This scope \\\"{_rangeResolution.DisposalHandling.RangeName}\\\" is already disposed, so it can't create a \\\"{returnTypeFullName}\\\" instance anymore.\");"); + private StringBuilder GenerateRangedInstanceFunction(StringBuilder stringBuilder, RangedInstanceFunctionGroupResolution rangedInstanceFunctionGroupResolution) { var isRefType = rangedInstanceFunctionGroupResolution.IsCreatedForStructs is null; @@ -480,10 +491,7 @@ private StringBuilder GenerateRangedInstanceFunction(StringBuilder stringBuilder .AppendLine($"{(isAsync ? "await " : "")}this.{rangedInstanceFunctionGroupResolution.LockReference}.Wait{(isAsync ? "Async" : "")}();") .AppendLine($"try") .AppendLine($"{{"); - if (_containerResolution.DisposalType != DisposalType.None) - stringBuilder = stringBuilder - .AppendLine( - $"if (this.{_rangeResolution.DisposalHandling.DisposedPropertyReference}) throw new {WellKnownTypes.ObjectDisposedException}(nameof({_rangeResolution.DisposalHandling.RangeName}));"); + stringBuilder = ObjectDisposedCheck(stringBuilder, rangedInstanceFunctionGroupResolution.TypeFullName); stringBuilder = stringBuilder .AppendLine(isRefType ? $"if (!object.ReferenceEquals({rangedInstanceFunctionGroupResolution.FieldReference}, null)) return {rangedInstanceFunctionGroupResolution.FieldReference};" @@ -502,7 +510,10 @@ private StringBuilder GenerateRangedInstanceFunction(StringBuilder stringBuilder .AppendLine($"finally") .AppendLine($"{{") .AppendLine($"this.{rangedInstanceFunctionGroupResolution.LockReference}.Release();") - .AppendLine($"}}") + .AppendLine($"}}"); + + stringBuilder = ObjectDisposedCheck(stringBuilder, rangedInstanceFunctionGroupResolution.TypeFullName); + stringBuilder = stringBuilder .AppendLine($"return this.{rangedInstanceFunctionGroupResolution.FieldReference};") .AppendLine($"}}"); } diff --git a/Main/Main.csproj b/Main/Main.csproj index bbfcc2cf..bf78190d 100644 --- a/Main/Main.csproj +++ b/Main/Main.csproj @@ -27,11 +27,11 @@ - - - - - + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Sample/Container.cs b/Sample/Container.cs index e5b0f411..52f83b14 100644 --- a/Sample/Container.cs +++ b/Sample/Container.cs @@ -1,20 +1,34 @@ -using MrMeeseeks.DIE.Configuration.Attributes; +using System.Collections.Generic; +using MrMeeseeks.DIE.Configuration.Attributes; using MrMeeseeks.DIE.Sample; -[assembly:ContainerInstanceAbstractionAggregation(typeof(IContainerInstance))] -[assembly:TransientScopeInstanceAbstractionAggregation(typeof(ITransientScopeInstance))] -[assembly:ScopeInstanceAbstractionAggregation(typeof(IScopeInstance))] -[assembly:TransientScopeRootAbstractionAggregation(typeof(ITransientScopeRoot))] -[assembly:ScopeRootAbstractionAggregation(typeof(IScopeRoot))] -[assembly:TransientAbstractionAggregation(typeof(ITransient))] -[assembly:SyncTransientAbstractionAggregation(typeof(ISyncTransient))] -[assembly:AsyncTransientAbstractionAggregation(typeof(IAsyncTransient))] -[assembly:DecoratorAbstractionAggregation(typeof(IDecorator<>))] -[assembly:CompositeAbstractionAggregation(typeof(IComposite<>))] -[assembly:TypeInitializer(typeof(ITypeInitializer), nameof(ITypeInitializer.Initialize))] -[assembly:TypeInitializer(typeof(ITaskTypeInitializer), nameof(ITaskTypeInitializer.InitializeAsync))] -[assembly:TypeInitializer(typeof(IValueTaskTypeInitializer), nameof(IValueTaskTypeInitializer.InitializeAsync))] +namespace MrMeeseeks.DIE.Test.Decorator.ContainerInstanceMultipeImplementations; -[assembly:AllImplementationsAggregation] +internal interface IInterface +{ + IInterface Decorated { get; } +} -[assembly:ErrorDescriptionInsteadOfBuildFailure] \ No newline at end of file +internal class DependencyA : IInterface, IContainerInstance +{ + public IInterface Decorated => this; +} + +internal class DependencyB : IInterface, IContainerInstance +{ + public IInterface Decorated => this; +} + +internal class Decorator : IInterface, IDecorator +{ + public Decorator(IInterface decoratedContainerInstance) => + Decorated = decoratedContainerInstance; + + public IInterface Decorated { get; } +} + +[CreateFunction(typeof(IReadOnlyList), "Create")] +internal sealed partial class Container +{ + +} \ No newline at end of file diff --git a/Sample/Context.cs b/Sample/Context.cs deleted file mode 100644 index 52f83b14..00000000 --- a/Sample/Context.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System.Collections.Generic; -using MrMeeseeks.DIE.Configuration.Attributes; -using MrMeeseeks.DIE.Sample; - -namespace MrMeeseeks.DIE.Test.Decorator.ContainerInstanceMultipeImplementations; - -internal interface IInterface -{ - IInterface Decorated { get; } -} - -internal class DependencyA : IInterface, IContainerInstance -{ - public IInterface Decorated => this; -} - -internal class DependencyB : IInterface, IContainerInstance -{ - public IInterface Decorated => this; -} - -internal class Decorator : IInterface, IDecorator -{ - public Decorator(IInterface decoratedContainerInstance) => - Decorated = decoratedContainerInstance; - - public IInterface Decorated { get; } -} - -[CreateFunction(typeof(IReadOnlyList), "Create")] -internal sealed partial class Container -{ - -} \ No newline at end of file diff --git a/Sample/MarkerInterfaces.cs b/Sample/MarkerInterfaces.cs index 121a865e..ad965cfd 100644 --- a/Sample/MarkerInterfaces.cs +++ b/Sample/MarkerInterfaces.cs @@ -1,4 +1,24 @@ using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using MrMeeseeks.DIE.Sample; + +[assembly:ErrorDescriptionInsteadOfBuildFailure] + +[assembly:ContainerInstanceAbstractionAggregation(typeof(IContainerInstance))] +[assembly:TransientScopeInstanceAbstractionAggregation(typeof(ITransientScopeInstance))] +[assembly:ScopeInstanceAbstractionAggregation(typeof(IScopeInstance))] +[assembly:TransientScopeRootAbstractionAggregation(typeof(ITransientScopeRoot))] +[assembly:ScopeRootAbstractionAggregation(typeof(IScopeRoot))] +[assembly:TransientAbstractionAggregation(typeof(ITransient))] +[assembly:SyncTransientAbstractionAggregation(typeof(ISyncTransient))] +[assembly:AsyncTransientAbstractionAggregation(typeof(IAsyncTransient))] +[assembly:DecoratorAbstractionAggregation(typeof(IDecorator<>))] +[assembly:CompositeAbstractionAggregation(typeof(IComposite<>))] +[assembly:TypeInitializer(typeof(ITypeInitializer), nameof(ITypeInitializer.Initialize))] +[assembly:TypeInitializer(typeof(ITaskTypeInitializer), nameof(ITaskTypeInitializer.InitializeAsync))] +[assembly:TypeInitializer(typeof(IValueTaskTypeInitializer), nameof(IValueTaskTypeInitializer.InitializeAsync))] + +[assembly:AllImplementationsAggregation] namespace MrMeeseeks.DIE.Sample; diff --git a/Sample/Sample.csproj b/Sample/Sample.csproj index 3f68edf4..2bba2ab3 100644 --- a/Sample/Sample.csproj +++ b/Sample/Sample.csproj @@ -11,7 +11,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Test/Test.csproj b/Test/Test.csproj index 06a3b29b..e2dbd1d2 100644 --- a/Test/Test.csproj +++ b/Test/Test.csproj @@ -11,17 +11,17 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all From e53a62870753c6c5ee25e2e9b974f027af8adbb8 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Thu, 18 Aug 2022 21:59:51 +0200 Subject: [PATCH 122/162] Validating CustomScopeForRootTypesAttributes --- Main/Validation/Range/ValidateContainer.cs | 37 ++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/Main/Validation/Range/ValidateContainer.cs b/Main/Validation/Range/ValidateContainer.cs index 1591dd83..37cb5eaa 100644 --- a/Main/Validation/Range/ValidateContainer.cs +++ b/Main/Validation/Range/ValidateContainer.cs @@ -47,22 +47,34 @@ public override IEnumerable Validate(INamedTypeSymbol rangeType, INa foreach (var diagnostic in _validateTransientScopeFactory.Validate(defaultTransientScope, rangeType)) yield return diagnostic; + var customTransientScopeTypes = new HashSet(SymbolEqualityComparer.Default); foreach (var customTransientScope in rangeType .GetTypeMembers() .Where(nts => nts.Name.StartsWith(Constants.CustomTransientScopeName))) + { + foreach (var diagnostic in ValidateCustomScope(customTransientScope, customTransientScopeTypes)) + yield return diagnostic; + foreach (var diagnostic in _validateTransientScopeFactory.Validate(customTransientScope, rangeType)) yield return diagnostic; + } if (rangeType.GetTypeMembers(Constants.DefaultScopeName, 0).FirstOrDefault() is { } defaultScope) foreach (var diagnostic in _validateScopeFactory.Validate(defaultScope, rangeType)) yield return diagnostic; + var customScopeTypes = new HashSet(SymbolEqualityComparer.Default); foreach (var customScope in rangeType .GetTypeMembers() .Where(nts => nts.Name.StartsWith(Constants.CustomScopeName))) + { + foreach (var diagnostic in ValidateCustomScope(customScope, customScopeTypes)) + yield return diagnostic; + foreach (var diagnostic in _validateScopeFactory.Validate(customScope, rangeType)) yield return diagnostic; + } var createFunctionAttributes = rangeType .GetAttributes() @@ -99,6 +111,31 @@ public override IEnumerable Validate(INamedTypeSymbol rangeType, INa else yield return ValidationErrorDiagnostic(rangeType, "Attribute doesn't have expected constructor arguments.", location); } + + IEnumerable ValidateCustomScope(INamedTypeSymbol customScope, ISet customScopeTypes) + { + var customScopeAttributes = customScope + .GetAttributes() + .Where(ad => SymbolEqualityComparer.Default.Equals(ad.AttributeClass, + _wellKnownTypesMiscellaneous.CustomScopeForRootTypesAttribute)) + .ToArray(); + + if (customScopeAttributes.Length == 0) + { + yield return ValidationErrorDiagnostic(rangeType, containerType, $"Custom scope \"{customScope.Name}\" has to have at least one \"{_wellKnownTypesMiscellaneous.CustomScopeForRootTypesAttribute.FullName()}\"-attribute."); + } + + var scopeRootTypes = customScopeAttributes + .SelectMany(ad => ad.ConstructorArguments[0].Values) + .OfType() + .ToList(); + foreach (var scopeRootType in scopeRootTypes + .Where(scopeRootType => customScopeTypes.Contains(scopeRootType, SymbolEqualityComparer.Default))) + { + yield return ValidationErrorDiagnostic(rangeType, containerType, $"Custom scope \"{customScope.Name}\" gets the type \"{scopeRootType.FullName()}\" passed into one of its \"{_wellKnownTypesMiscellaneous.CustomScopeForRootTypesAttribute.FullName()}\"-attributes, but it is already in use in another custom scope."); + } + customScopeTypes.UnionWith(scopeRootTypes); + } } protected override Diagnostic ValidationErrorDiagnostic(INamedTypeSymbol rangeType, INamedTypeSymbol _, string specification) => From a873778a7aab2a740658c04294d7738aa1bcc5cc Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Mon, 22 Aug 2022 23:02:28 +0200 Subject: [PATCH 123/162] Tuple support --- .../Function/FunctionResolutionBuilder.cs | 18 +++++++- Test/Tuple/NonSyntaxVariant.cs | 42 +++++++++++++++++++ Test/Tuple/NonSyntaxVariantSingleItem.cs | 36 ++++++++++++++++ Test/Tuple/TupleTests.cs | 36 ++++++++++++++++ 4 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 Test/Tuple/NonSyntaxVariant.cs create mode 100644 Test/Tuple/NonSyntaxVariantSingleItem.cs create mode 100644 Test/Tuple/TupleTests.cs diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs index 110bbf5e..722b2a41 100644 --- a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs @@ -255,7 +255,7 @@ private string ErrorMessage(IImmutableStack stack, ITypeSymbol DisposalType.None, valueTupleType .TypeArguments - .Select((t, i) => ($"item{(i + 1)}", SwitchType(new SwitchTypeParameter(t, currentFuncParameters, implementationStack)).Item1)) + .Select((t, i) => (valueTupleType.InstanceConstructors[0].Parameters[i].Name, SwitchType(new SwitchTypeParameter(t, currentFuncParameters, implementationStack)).Item1)) .ToList(), Array.Empty<(string Name, Resolvable Dependency)>(), null, @@ -295,6 +295,22 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup } } + if (type.FullName().StartsWith("global::System.Tuple<") && type is INamedTypeSymbol tupleType) + { + var constructorResolution = new ConstructorResolution( + RootReferenceGenerator.Generate(tupleType), + tupleType.FullName(), + DisposalType.None, + tupleType + .TypeArguments + .Select((t, i) => (tupleType.InstanceConstructors[0].Parameters[i].Name, SwitchType(new SwitchTypeParameter(t, currentFuncParameters, implementationStack)).Item1)) + .ToList(), + Array.Empty<(string Name, Resolvable Dependency)>(), + null, + null); + return (constructorResolution, constructorResolution); + } + if (type.OriginalDefinition.Equals(_wellKnownTypes.Lazy1, SymbolEqualityComparer.Default) && type is INamedTypeSymbol namedTypeSymbol) { diff --git a/Test/Tuple/NonSyntaxVariant.cs b/Test/Tuple/NonSyntaxVariant.cs new file mode 100644 index 00000000..60e35873 --- /dev/null +++ b/Test/Tuple/NonSyntaxVariant.cs @@ -0,0 +1,42 @@ +using System; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Tuple.NonSyntaxVariant; + +internal class Wrapper +{ + public Wrapper( + Tuple>>> + dependency) => + Dependency = dependency; + + public Tuple>>> + Dependency { get; } +} + +[CreateFunction(typeof(Wrapper), "Create")] +internal sealed partial class Container +{ + private int _i; + + private int DIE_Counter() => _i++; +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var nonSyntaxValueTupleBase = container.Create(); + Assert.Equal(25, nonSyntaxValueTupleBase.Dependency.Rest.Rest.Rest.Item5); + } +} \ No newline at end of file diff --git a/Test/Tuple/NonSyntaxVariantSingleItem.cs b/Test/Tuple/NonSyntaxVariantSingleItem.cs new file mode 100644 index 00000000..db531904 --- /dev/null +++ b/Test/Tuple/NonSyntaxVariantSingleItem.cs @@ -0,0 +1,36 @@ +using System; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Tuple.NonSyntaxVariantSingleItem; + +internal class Wrapper +{ + public Wrapper( + Tuple + dependency) => + Dependency = dependency; + + public Tuple + Dependency { get; } +} + +[CreateFunction(typeof(Wrapper), "Create")] +internal sealed partial class Container +{ + private int _i; + + private int DIE_Counter() => _i++; +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var wrapper = container.Create(); + Assert.Equal(0, wrapper.Dependency.Item1); + } +} \ No newline at end of file diff --git a/Test/Tuple/TupleTests.cs b/Test/Tuple/TupleTests.cs new file mode 100644 index 00000000..eb9e4167 --- /dev/null +++ b/Test/Tuple/TupleTests.cs @@ -0,0 +1,36 @@ +using System; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Tuple.NonSyntaxVariantDoubleItem; + +internal class Wrapper +{ + public Wrapper( + Tuple + dependency) => + Dependency = dependency; + + public Tuple + Dependency { get; } +} + +[CreateFunction(typeof(Wrapper), "Create")] +internal sealed partial class Container +{ + private int _i; + + private int DIE_Counter() => _i++; +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var wrapper = container.Create(); + Assert.Equal(1, wrapper.Dependency.Item2); + } +} \ No newline at end of file From 2520325f9350de2415c16acf52147b02cd59562d Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Wed, 24 Aug 2022 13:18:10 +0200 Subject: [PATCH 124/162] Fixing single item ValueTuple bug --- .github/workflows/main.yml | 2 +- .../Function/FunctionResolutionBuilder.cs | 5 ++- Sample/Container.cs | 37 +++++++------------ 3 files changed, 18 insertions(+), 26 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7d032782..ea938ed8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -20,7 +20,7 @@ jobs: - name: Setup .NET Core uses: actions/setup-dotnet@v2.1.0 with: - dotnet-version: 6.0.300 + dotnet-version: 6.0.400 - run: set DOTNET_CLI_TELEMETRY_OPTOUT=1 - name: Install dependencies run: dotnet restore .\MrMeeseeks.DIE.sln diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs index 722b2a41..4c0ad53f 100644 --- a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs @@ -249,13 +249,16 @@ private string ErrorMessage(IImmutableStack stack, ITypeSymbol if (type.FullName().StartsWith("global::System.ValueTuple<") && type is INamedTypeSymbol valueTupleType) { + var constructor = valueTupleType + .InstanceConstructors + .First(c => c.Parameters.Length > 0); var constructorResolution = new ConstructorResolution( RootReferenceGenerator.Generate(valueTupleType), valueTupleType.FullName(), DisposalType.None, valueTupleType .TypeArguments - .Select((t, i) => (valueTupleType.InstanceConstructors[0].Parameters[i].Name, SwitchType(new SwitchTypeParameter(t, currentFuncParameters, implementationStack)).Item1)) + .Select((t, i) => (constructor.Parameters[i].Name, SwitchType(new SwitchTypeParameter(t, currentFuncParameters, implementationStack)).Item1)) .ToList(), Array.Empty<(string Name, Resolvable Dependency)>(), null, diff --git a/Sample/Container.cs b/Sample/Container.cs index 52f83b14..a686f565 100644 --- a/Sample/Container.cs +++ b/Sample/Container.cs @@ -1,34 +1,23 @@ -using System.Collections.Generic; +using System; using MrMeeseeks.DIE.Configuration.Attributes; -using MrMeeseeks.DIE.Sample; -namespace MrMeeseeks.DIE.Test.Decorator.ContainerInstanceMultipeImplementations; +namespace MrMeeseeks.DIE.Test.ValueTuple.NonSyntaxVariantSingleItem; -internal interface IInterface +internal class Wrapper { - IInterface Decorated { get; } -} - -internal class DependencyA : IInterface, IContainerInstance -{ - public IInterface Decorated => this; -} - -internal class DependencyB : IInterface, IContainerInstance -{ - public IInterface Decorated => this; -} + public Wrapper( + ValueTuple + dependency) => + Dependency = dependency; -internal class Decorator : IInterface, IDecorator -{ - public Decorator(IInterface decoratedContainerInstance) => - Decorated = decoratedContainerInstance; - - public IInterface Decorated { get; } + public ValueTuple + Dependency { get; } } -[CreateFunction(typeof(IReadOnlyList), "Create")] +[CreateFunction(typeof(Wrapper), "Create")] internal sealed partial class Container { - + private int _i; + + private int DIE_Counter() => _i++; } \ No newline at end of file From 8949208dca89508d1b036835fe64acbeed8f8325 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Wed, 24 Aug 2022 22:32:57 +0200 Subject: [PATCH 125/162] Support user-defined properties injection --- Main/CodeBuilding/RangeCodeBaseBuilder.cs | 18 ++- .../Configuration/Attributes/Miscellaneous.cs | 12 +- Main/Configuration/CheckTypeProperties.cs | 21 +++- .../Configuration/CurrentlyConsideredTypes.cs | 25 +++- Main/Configuration/TypesFromAttributes.cs | 20 +-- Main/Constants.cs | 3 +- Main/Main.csproj | 4 +- .../Function/FunctionResolutionBuilder.cs | 114 ++++++++++++------ Main/ResolutionBuilding/ScopeManager.cs | 10 +- Main/ResolutionTreeItem.cs | 15 ++- Main/SourceGenerator.cs | 12 +- Main/UserDefinedElements.cs | 82 +++++++------ ...eUserDefinedConstrParamsInjectionMethod.cs | 14 +++ ... => ValidateUserDefinedInjectionMethod.cs} | 13 +- ...ateUserDefinedPropertiesInjectionMethod.cs | 14 +++ Main/Validation/Range/ValidateContainer.cs | 13 +- Main/Validation/Range/ValidateRange.cs | 48 +++++--- Main/Validation/Range/ValidateScope.cs | 6 +- Main/Validation/Range/ValidateScopeBase.cs | 9 +- .../Range/ValidateTransientScope.cs | 6 +- Main/WellKnownTypesMiscellaneous.cs | 16 ++- Sample/Sample.csproj | 2 +- .../Vanilla.cs} | 4 +- .../VanillaInScope.cs} | 4 +- .../VanillaInTransientScope.cs} | 4 +- .../WithAsyncDependency.cs} | 4 +- .../WithAsyncDependencyInScope.cs} | 4 +- .../WithAsyncDependencyInTransientScope.cs} | 4 +- .../WithDependency.cs} | 4 +- .../WithDependencyInScope.cs} | 4 +- .../WithDependencyInTransientScope.cs} | 4 +- Test/CustomEmbedding/Properties/Vanilla.cs | 28 +++++ .../Properties/VanillaInScope.cs | 39 ++++++ .../Properties/VanillaInTransientScope.cs | 39 ++++++ .../Properties/WithAsyncDependency.cs | 34 ++++++ .../Properties/WithAsyncDependencyInScope.cs | 45 +++++++ .../WithAsyncDependencyInTransientScope.cs | 45 +++++++ .../Properties/WithDependency.cs | 33 +++++ .../Properties/WithDependencyInScope.cs | 44 +++++++ .../WithDependencyInTransientScope.cs | 44 +++++++ 40 files changed, 692 insertions(+), 172 deletions(-) create mode 100644 Main/Validation/Range/UserDefined/ValidateUserDefinedConstrParamsInjectionMethod.cs rename Main/Validation/Range/UserDefined/{ValidateUserDefinedConstrParamMethod.cs => ValidateUserDefinedInjectionMethod.cs} (84%) create mode 100644 Main/Validation/Range/UserDefined/ValidateUserDefinedPropertiesInjectionMethod.cs rename Test/CustomEmbedding/{ConstructorParameter.cs => ConstrParam/Vanilla.cs} (82%) rename Test/CustomEmbedding/{ConstructorParameterInScope.cs => ConstrParam/VanillaInScope.cs} (86%) rename Test/CustomEmbedding/{ConstructorParameterInTransientScope.cs => ConstrParam/VanillaInTransientScope.cs} (85%) rename Test/CustomEmbedding/{ConstructorParameterWithAsyncDependency.cs => ConstrParam/WithAsyncDependency.cs} (85%) rename Test/CustomEmbedding/{ConstructorParameterWithAsyncDependencyInScope.cs => ConstrParam/WithAsyncDependencyInScope.cs} (87%) rename Test/CustomEmbedding/{ConstructorParameterWithAsyncDependencyInTransientScope.cs => ConstrParam/WithAsyncDependencyInTransientScope.cs} (87%) rename Test/CustomEmbedding/{ConstructorParameterWithDependency.cs => ConstrParam/WithDependency.cs} (84%) rename Test/CustomEmbedding/{ConstructorParameterWithDependencyInScope.cs => ConstrParam/WithDependencyInScope.cs} (86%) rename Test/CustomEmbedding/{ConstructorParameterWithDependencyInTransientScope.cs => ConstrParam/WithDependencyInTransientScope.cs} (86%) create mode 100644 Test/CustomEmbedding/Properties/Vanilla.cs create mode 100644 Test/CustomEmbedding/Properties/VanillaInScope.cs create mode 100644 Test/CustomEmbedding/Properties/VanillaInTransientScope.cs create mode 100644 Test/CustomEmbedding/Properties/WithAsyncDependency.cs create mode 100644 Test/CustomEmbedding/Properties/WithAsyncDependencyInScope.cs create mode 100644 Test/CustomEmbedding/Properties/WithAsyncDependencyInTransientScope.cs create mode 100644 Test/CustomEmbedding/Properties/WithDependency.cs create mode 100644 Test/CustomEmbedding/Properties/WithDependencyInScope.cs create mode 100644 Test/CustomEmbedding/Properties/WithDependencyInTransientScope.cs diff --git a/Main/CodeBuilding/RangeCodeBaseBuilder.cs b/Main/CodeBuilding/RangeCodeBaseBuilder.cs index 36fec608..904481ea 100644 --- a/Main/CodeBuilding/RangeCodeBaseBuilder.cs +++ b/Main/CodeBuilding/RangeCodeBaseBuilder.cs @@ -374,14 +374,24 @@ private StringBuilder GenerateResolutions( case OutParameterResolution(var reference, var typeFullName): stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); break; - case ConstructorParameterChoiceResolution(var functionName, var parameters): + case UserDefinedInjectionResolution(var functionName, var parameters): stringBuilder = parameters.Aggregate(stringBuilder, (builder, tuple) => GenerateResolutions(builder, tuple.Dependency)); stringBuilder = stringBuilder.AppendLine($"{functionName}({string.Join(", ", parameters.Select(p => $"{p.Name}: {(p.isOut ? "out " : "")}{p.Dependency.Reference}"))});"); break; - case ConstructorResolution(var reference, var typeFullName, var disposalType, var parameters, var initializedProperties, var initialization, var parameterChoiceResolution): - if (parameterChoiceResolution is { }) - GenerateResolutions(stringBuilder, parameterChoiceResolution); + case ConstructorResolution( + var reference, + var typeFullName, + var disposalType, + var parameters, + var initializedProperties, + var initialization, + var userDefinedConstrParamsInjection, + var userDefinedPropertiesInjection): + if (userDefinedConstrParamsInjection is { }) + GenerateResolutions(stringBuilder, userDefinedConstrParamsInjection); + if (userDefinedPropertiesInjection is { }) + GenerateResolutions(stringBuilder, userDefinedPropertiesInjection); stringBuilder = parameters.Aggregate(stringBuilder, (builder, tuple) => GenerateResolutions(builder, tuple.Dependency)); stringBuilder = initializedProperties.Aggregate(stringBuilder, diff --git a/Main/Configuration/Attributes/Miscellaneous.cs b/Main/Configuration/Attributes/Miscellaneous.cs index 64ddcd49..31d262c8 100644 --- a/Main/Configuration/Attributes/Miscellaneous.cs +++ b/Main/Configuration/Attributes/Miscellaneous.cs @@ -10,9 +10,17 @@ public CustomScopeForRootTypesAttribute(params Type[] types) } [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] -public class CustomConstructorParameterAttribute : Attribute +public class UserDefinedConstrParamsInjectionAttribute : Attribute { - public CustomConstructorParameterAttribute(Type type) + public UserDefinedConstrParamsInjectionAttribute(Type type) + { + } +} + +[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] +public class UserDefinedPropertiesInjectionAttribute : Attribute +{ + public UserDefinedPropertiesInjectionAttribute(Type type) { } } diff --git a/Main/Configuration/CheckTypeProperties.cs b/Main/Configuration/CheckTypeProperties.cs index e7465ebf..2d5b0a24 100644 --- a/Main/Configuration/CheckTypeProperties.cs +++ b/Main/Configuration/CheckTypeProperties.cs @@ -91,7 +91,7 @@ public ScopeLevel GetScopeLevelFor(INamedTypeSymbol implementationType) var compositeImplementation = _currentlyConsideredTypes.InterfaceToComposite[interfaceType.UnboundIfGeneric()]; var implementations = GetClosedImplementations( interfaceType, - ImmutableHashSet.Create(compositeImplementation), + ImmutableHashSet.Create(SymbolEqualityComparer.Default, compositeImplementation), true, true, false); @@ -162,7 +162,7 @@ public IReadOnlyList GetSequenceFor(INamedTypeSymbol interface { var implementations = GetClosedImplementations( interfaceType, - ImmutableHashSet.Create(imp), + ImmutableHashSet.Create(SymbolEqualityComparer.Default, imp), true, false, true); @@ -187,7 +187,12 @@ public IReadOnlyList GetSequenceFor(INamedTypeSymbol interface if (choice is not null) { - var possibleChoices = GetClosedImplementations(type, ImmutableHashSet.Create(choice), true, false, false); + var possibleChoices = GetClosedImplementations( + type, + ImmutableHashSet.Create(SymbolEqualityComparer.Default, choice), + true, + false, + false); return possibleChoices.Count == 1 ? possibleChoices.FirstOrDefault() : null; @@ -195,7 +200,12 @@ public IReadOnlyList GetSequenceFor(INamedTypeSymbol interface if (type is { TypeKind: not TypeKind.Interface, IsAbstract: false, IsStatic: false }) { - var possibleConcreteTypeImplementations = GetClosedImplementations(type, ImmutableHashSet.Create(type), true, false, false); + var possibleConcreteTypeImplementations = GetClosedImplementations( + type, + ImmutableHashSet.Create(SymbolEqualityComparer.Default, type), + true, + false, + false); return possibleConcreteTypeImplementations.Count == 1 ? possibleConcreteTypeImplementations.FirstOrDefault() : null; @@ -321,7 +331,8 @@ ITypeSymbol ForTypeParameterSymbol(ITypeParameterSymbol tps) var queue = ImmutableQueue.CreateRange(openTypeParameters .Select(tp => { - IImmutableSet substitutes = ImmutableHashSet.CreateRange( + IImmutableSet substitutes = ImmutableHashSet.CreateRange( + SymbolEqualityComparer.Default, _currentlyConsideredTypes.GenericParameterSubstitutesChoices.TryGetValue( (unboundImplementation, tp), out var subs) ? subs diff --git a/Main/Configuration/CurrentlyConsideredTypes.cs b/Main/Configuration/CurrentlyConsideredTypes.cs index 47d98b89..aae86a50 100644 --- a/Main/Configuration/CurrentlyConsideredTypes.cs +++ b/Main/Configuration/CurrentlyConsideredTypes.cs @@ -146,12 +146,20 @@ public CurrentlyConsideredTypes( } } - AllConsideredImplementations = ImmutableHashSet.CreateRange(allImplementations.Select(t => t.UnboundIfGeneric())); + AllConsideredImplementations = ImmutableHashSet.CreateRange( + SymbolEqualityComparer.Default, + allImplementations.Select(t => t.UnboundIfGeneric())); ImplementationMap = allImplementations .SelectMany(i => { return i.AllDerivedTypesAndSelf().Select(ii => (ii, i)); }) - .GroupBy(t => t.Item1.UnboundIfGeneric(), t => t.Item2) - .ToDictionary(g => g.Key, g => (IImmutableSet) ImmutableHashSet.CreateRange(g)); + .GroupBy<(INamedTypeSymbol, INamedTypeSymbol), INamedTypeSymbol, INamedTypeSymbol>( + t => t.Item1.UnboundIfGeneric(), + t => t.Item2, + SymbolEqualityComparer.Default) + .ToDictionary, INamedTypeSymbol, IImmutableSet>( + g => g.Key, + g => ImmutableHashSet.CreateRange(SymbolEqualityComparer.Default, g), + SymbolEqualityComparer.Default); var transientTypes = GetSetOfTypesWithProperties( t => t.TransientAbstraction, @@ -311,7 +319,10 @@ public CurrentlyConsideredTypes( DecoratorSequenceChoices = decoratorSequenceChoices .Where(kvp => kvp.Value.Any) - .ToDictionary(kvp => kvp.Key, kvp => kvp.Value.ToReadOnlyDictionary()); + .ToDictionary, INamedTypeSymbol, IReadOnlyDictionary>>( + kvp => kvp.Key, + kvp => kvp.Value.ToReadOnlyDictionary(), + SymbolEqualityComparer.Default); var initializers = new Dictionary(SymbolEqualityComparer.Default); @@ -428,7 +439,8 @@ IImmutableSet GetSetOfTypesWithProperties( foreach (var types in typesFromAttributes) { - var filteredTypes = ImmutableHashSet.CreateRange( + var filteredTypes = ImmutableHashSet.CreateRange( + SymbolEqualityComparer.Default, filteredPropertyGivingImplementationTypesGetter(types).Select(t => t.UnboundIfGeneric())); foreach (var type in filteredPropertyGivingAbstractTypesGetter(types)) if (implementationMap.TryGetValue(type.UnboundIfGeneric(), out var set)) @@ -436,7 +448,8 @@ IImmutableSet GetSetOfTypesWithProperties( ret = ret.Except(filteredTypes); - var addedTypes = ImmutableHashSet.CreateRange( + var addedTypes = ImmutableHashSet.CreateRange( + SymbolEqualityComparer.Default, propertyGivingImplementationTypesGetter(types).Select(t => t.UnboundIfGeneric())); foreach (var type in propertyGivingAbstractTypesGetter(types)) if (implementationMap.TryGetValue(type.UnboundIfGeneric(), out var set)) diff --git a/Main/Configuration/TypesFromAttributes.cs b/Main/Configuration/TypesFromAttributes.cs index db94d033..a11b3072 100644 --- a/Main/Configuration/TypesFromAttributes.cs +++ b/Main/Configuration/TypesFromAttributes.cs @@ -134,7 +134,7 @@ internal ScopeTypesFromAttributes( _validateAttributes = validateAttributes; AttributeDictionary = attributeData .GroupBy(ad => ad.AttributeClass, SymbolEqualityComparer.Default) - .ToDictionary(g => g.Key, g => g); + .ToDictionary(g => g.Key, g => g, SymbolEqualityComparer.Default); Implementation = GetImplementationTypesFromAttribute(wellKnownTypesAggregation.ImplementationAggregationAttribute); TransientAbstraction = GetAbstractionTypesFromAttribute(wellKnownTypesAggregation.TransientAbstractionAggregationAttribute); @@ -343,7 +343,8 @@ void NotParsableAttribute(AttributeData attributeData) => return type; } - FilterConstructorChoices = ImmutableHashSet.CreateRange( + FilterConstructorChoices = ImmutableHashSet.CreateRange( + SymbolEqualityComparer.Default, (AttributeDictionary.TryGetValue(wellKnownTypesChoice.FilterConstructorChoiceAttribute, out var filterConstructorChoiceAttributes) ? filterConstructorChoiceAttributes : Enumerable.Empty()) @@ -401,7 +402,8 @@ void NotParsableAttribute(AttributeData attributeData) => }) .OfType<(INamedTypeSymbol, IReadOnlyList)>()); - FilterPropertyChoices = ImmutableHashSet.CreateRange( + FilterPropertyChoices = ImmutableHashSet.CreateRange( + SymbolEqualityComparer.Default, (AttributeDictionary.TryGetValue(wellKnownTypesChoice.FilterPropertyChoiceAttribute, out var filterPropertyChoicesGroup) ? filterPropertyChoicesGroup : Enumerable.Empty()) @@ -462,7 +464,8 @@ void NotParsableAttribute(AttributeData attributeData) => }) .OfType<(INamedTypeSymbol, IMethodSymbol)>()); - FilterTypeInitializers = ImmutableHashSet.CreateRange( + FilterTypeInitializers = ImmutableHashSet.CreateRange( + SymbolEqualityComparer.Default, (AttributeDictionary.TryGetValue(wellKnownTypesMiscellaneous.FilterTypeInitializerAttribute, out var filterTypeInitializerAttributes) ? filterTypeInitializerAttributes : Enumerable.Empty()) @@ -655,7 +658,8 @@ void NotParsableAttribute(AttributeData attributeData) => .Any(); IImmutableSet GetAssemblies(INamedTypeSymbol attributeType) => - ImmutableHashSet.CreateRange( + ImmutableHashSet.CreateRange( + SymbolEqualityComparer.Default, (AttributeDictionary.TryGetValue(attributeType, out var assemblyImplementationsAttributes) ? assemblyImplementationsAttributes : Enumerable.Empty()) @@ -794,7 +798,8 @@ IImmutableSet GetAssemblies(INamedTypeSymbol attributeType) => protected IImmutableSet GetAbstractionTypesFromAttribute( INamedTypeSymbol attribute) { - return ImmutableHashSet.CreateRange( + return ImmutableHashSet.CreateRange( + SymbolEqualityComparer.Default, GetTypesFromAttribute(attribute) .Where(t => { @@ -815,7 +820,8 @@ protected IImmutableSet GetAbstractionTypesFromAttribute( protected IImmutableSet GetImplementationTypesFromAttribute( INamedTypeSymbol attribute) { - return ImmutableHashSet.CreateRange( + return ImmutableHashSet.CreateRange( + SymbolEqualityComparer.Default, GetTypesFromAttribute(attribute) .Where(t => { diff --git a/Main/Constants.cs b/Main/Constants.cs index 19587f96..78736605 100644 --- a/Main/Constants.cs +++ b/Main/Constants.cs @@ -19,7 +19,8 @@ internal static class Constants // User-defined scope elements internal const string UserDefinedFactory = $"{DieAbbreviation}_Factory"; - internal const string UserDefinedConstructorParameters = $"{DieAbbreviation}_ConstrParam"; + internal const string UserDefinedConstrParams = $"{DieAbbreviation}_ConstrParam"; + internal const string UserDefinedProperties = $"{DieAbbreviation}_Properties"; internal const string UserDefinedAddForDisposal = $"{DieAbbreviation}_AddForDisposal"; internal const string UserDefinedAddForDisposalAsync = $"{DieAbbreviation}_AddForDisposalAsync"; diff --git a/Main/Main.csproj b/Main/Main.csproj index bf78190d..2563c09d 100644 --- a/Main/Main.csproj +++ b/Main/Main.csproj @@ -31,11 +31,11 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs index 4c0ad53f..31cc025c 100644 --- a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs @@ -262,6 +262,7 @@ private string ErrorMessage(IImmutableStack stack, ITypeSymbol .ToList(), Array.Empty<(string Name, Resolvable Dependency)>(), null, + null, null); return (constructorResolution, constructorResolution); } @@ -310,6 +311,7 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup .ToList(), Array.Empty<(string Name, Resolvable Dependency)>(), null, + null, null); return (constructorResolution, constructorResolution); } @@ -849,39 +851,13 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup var isTransientScopeRoot = _checkTypeProperties.ShouldBeScopeRoot(implementationType) == ScopeLevel.TransientScope; - var outParameters = ImmutableDictionary.Empty; - ConstructorParameterChoiceResolution? constructorParameterChoiceResolution = null; - - if (_userDefinedElements.GetCustomConstructorParameterChoiceFor(implementationType) is - { } parameterChoiceMethod) - { - constructorParameterChoiceResolution = new ConstructorParameterChoiceResolution( - parameterChoiceMethod.Name, - parameterChoiceMethod - .Parameters - .Select(p => - { - var isOut = p.RefKind == RefKind.Out; - - if (isOut) - { - var outParameter = new OutParameterResolution( - RootReferenceGenerator.Generate(p.Type), - p.Type.FullName()); - outParameters = outParameters.Add(p.Name, outParameter); - return ( - p.Name, - outParameter, - isOut); - } + var (userDefinedConstrParamsInjection, outConstrParams) = GetUserDefinedInjectionResolution( + _userDefinedElements.GetConstrParamsInjectionFor(implementationType), + (name, parameters) => new UserDefinedConstrParamsInjectionResolution(name, parameters)); - return ( - p.Name, - SwitchType(new SwitchTypeParameter(p.Type, currentParameters, implementationStack)).Item1, - isOut); - }) - .ToList()); - } + var (userDefinedPropertiesInjection, outProperties) = GetUserDefinedInjectionResolution( + _userDefinedElements.GetPropertiesInjectionFor(implementationType), + (name, parameters) => new UserDefinedPropertiesInjectionResolution(name, parameters)); ITypeInitializationResolution? typeInitializationResolution = null; @@ -920,7 +896,7 @@ false when initializationMethod.ReturnType.Equals(_wellKnownTypes.ValueTask, Sym GetDisposalTypeFor(implementationType), new ReadOnlyCollection<(string Name, Resolvable Dependency)>(constructor .Parameters - .Select(p => ProcessChildType(p.Type, p.Name, implementationType, currentParameters)) + .Select(p => ProcessConstrParamChildType(p.Type, p.Name, currentParameters)) .ToList()), new ReadOnlyCollection<(string Name, Resolvable Dependency)>( (_checkTypeProperties.GetPropertyChoicesFor(implementationType) @@ -929,22 +905,41 @@ false when initializationMethod.ReturnType.Equals(_wellKnownTypes.ValueTask, Sym .OfType() .Where(_ => !implementationType.IsRecord) .Where(p => p.SetMethod?.IsInitOnly ?? false)) - .Select(p => ProcessChildType(p.Type, p.Name, implementationType, currentParameters)) + .Select(p => ProcessPropertyChildType(p.Type, p.Name, currentParameters)) .ToList()), typeInitializationResolution, - constructorParameterChoiceResolution); + userDefinedConstrParamsInjection, + userDefinedPropertiesInjection); return (resolution, resolution); + (string Name, Resolvable Dependency) ProcessConstrParamChildType( + ITypeSymbol typeSymbol, + string parameterName, + ImmutableSortedDictionary currParameter) + { + if (outConstrParams.TryGetValue(parameterName, out var outParameterResolution)) + return (parameterName, + new ParameterResolution(outParameterResolution.Reference, outParameterResolution.TypeFullName)); + return ProcessChildType(typeSymbol, parameterName, currParameter); + } + + (string Name, Resolvable Dependency) ProcessPropertyChildType( + ITypeSymbol typeSymbol, + string parameterName, + ImmutableSortedDictionary currParameter) + { + if (outProperties.TryGetValue(parameterName, out var outPropertyResolution)) + return (parameterName, + new ParameterResolution(outPropertyResolution.Reference, outPropertyResolution.TypeFullName)); + return ProcessChildType(typeSymbol, parameterName, currParameter); + } + (string Name, Resolvable Dependency) ProcessChildType( ITypeSymbol typeSymbol, string parameterName, - INamedTypeSymbol impType, ImmutableSortedDictionary currParameter) { - if (outParameters.TryGetValue(parameterName, out var outParameterResolution)) - return (parameterName, new ParameterResolution(outParameterResolution.Reference, outParameterResolution.TypeFullName)); - if (checkForDecoration && decoration is {}) { if (typeSymbol.Equals(decoration.InterfaceType, SymbolEqualityComparer.Default)) @@ -1029,6 +1024,47 @@ false when initializationMethod.ReturnType.Equals(_wellKnownTypes.ValueTask, Sym currParameter, implementationStack)).Item1); } + + (TInjection?, IImmutableDictionary) GetUserDefinedInjectionResolution( + IMethodSymbol? userDefinedInjectionMethod, + Func, TInjection> injectionResolutionFactory) + where TInjection : UserDefinedInjectionResolution + { + var outParameters = ImmutableDictionary.Empty; + TInjection? userDefinedInjectionResolution = null; + + if (userDefinedInjectionMethod is not null) + { + userDefinedInjectionResolution = injectionResolutionFactory( + userDefinedInjectionMethod.Name, + userDefinedInjectionMethod + .Parameters + .Select(p => + { + var isOut = p.RefKind == RefKind.Out; + + if (isOut) + { + var outParameter = new OutParameterResolution( + RootReferenceGenerator.Generate(p.Type), + p.Type.FullName()); + outParameters = outParameters.Add(p.Name, outParameter); + return ( + p.Name, + outParameter, + isOut); + } + + return ( + p.Name, + SwitchType(new SwitchTypeParameter(p.Type, currentParameters, implementationStack)).Item1, + isOut); + }) + .ToList()); + } + + return (userDefinedInjectionResolution, outParameters); + } } private DisposalType GetDisposalTypeFor(INamedTypeSymbol type) diff --git a/Main/ResolutionBuilding/ScopeManager.cs b/Main/ResolutionBuilding/ScopeManager.cs index ce853762..1775bd57 100644 --- a/Main/ResolutionBuilding/ScopeManager.cs +++ b/Main/ResolutionBuilding/ScopeManager.cs @@ -152,7 +152,10 @@ defaultTransientScopeType is {} })) .OfType() .Select(rootType => (rootType, nts))) - .ToDictionary(t => t.rootType, t => t.nts); + .ToDictionary<(INamedTypeSymbol rootType, INamedTypeSymbol nts), INamedTypeSymbol, INamedTypeSymbol>( + t => t.rootType, + t => t.nts, + SymbolEqualityComparer.Default); _scopeRootTypeToScopeType = containerInfo .ContainerType @@ -175,7 +178,10 @@ defaultTransientScopeType is {} })) .OfType() .Select(rootType => (rootType, nts))) - .ToDictionary(t => t.rootType, t => t.nts); + .ToDictionary<(INamedTypeSymbol rootType, INamedTypeSymbol nts), INamedTypeSymbol, INamedTypeSymbol>( + t => t.rootType, + t => t.nts, + SymbolEqualityComparer.Default); } public IScopeResolutionBuilder GetScopeBuilder(INamedTypeSymbol scopeRootType) diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index 3fff2a58..409a96f6 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -111,7 +111,8 @@ internal record ConstructorResolution( IReadOnlyList<(string Name, Resolvable Dependency)> Parameter, IReadOnlyList<(string Name, Resolvable Dependency)> InitializedProperties, ITypeInitializationResolution? Initialization, - ConstructorParameterChoiceResolution? ParameterChoices) : Resolvable(Reference, TypeFullName), ITaskConsumableResolution; + UserDefinedConstrParamsInjectionResolution? UserDefinedConstrParamsInjection, + UserDefinedPropertiesInjectionResolution? UserDefinedPropertiesInjection) : Resolvable(Reference, TypeFullName), ITaskConsumableResolution; internal record LazyResolution( string Reference, @@ -169,10 +170,18 @@ internal record OutParameterResolution( string Reference, string TypeFullName) : Resolvable(Reference, TypeFullName); -internal record ConstructorParameterChoiceResolution( +internal abstract record UserDefinedInjectionResolution( string FunctionName, IReadOnlyList<(string Name, Resolvable Dependency, bool isOut)> Parameter) : Resolvable("foo", "bar"); +internal record UserDefinedConstrParamsInjectionResolution( + string FunctionName, + IReadOnlyList<(string Name, Resolvable Dependency, bool isOut)> Parameter) : UserDefinedInjectionResolution(FunctionName, Parameter); + +internal record UserDefinedPropertiesInjectionResolution( + string FunctionName, + IReadOnlyList<(string Name, Resolvable Dependency, bool isOut)> Parameter) : UserDefinedInjectionResolution(FunctionName, Parameter); + internal record CollectionResolution( string Reference, string TypeFullName, @@ -189,6 +198,7 @@ internal record SyncDisposableCollectionResolution( Array.Empty<(string Name, Resolvable Dependency)>(), Array.Empty<(string Name, Resolvable Dependency)>(), null, + null, null); internal record AsyncDisposableCollectionResolution( @@ -201,6 +211,7 @@ internal record AsyncDisposableCollectionResolution( Array.Empty<(string Name, Resolvable Dependency)>(), Array.Empty<(string Name, Resolvable Dependency)>(), null, + null, null); internal abstract record RangeResolution( diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index f5d0aeb7..8edecc8a 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -29,14 +29,16 @@ public void Execute(GeneratorExecutionContext context) var diagLogger = new DiagLogger(errorDescriptionInsteadOfBuildFailure, context); var validateUserDefinedAddForDisposalSync = new ValidateUserDefinedAddForDisposalSync(wellKnownTypes); var validateUserDefinedAddForDisposalAsync = new ValidateUserDefinedAddForDisposalAsync(wellKnownTypes); - var validateUserDefinedConstrParam = new ValidateUserDefinedConstrParam(wellKnownTypesMiscellaneous); + var validateUserDefinedConstrParamsInjectionMethod = new ValidateUserDefinedConstrParamsInjectionMethod(wellKnownTypesMiscellaneous); + var validateUserDefinedPropertiesInjectionMethod = new ValidateUserDefinedPropertiesInjectionMethod(wellKnownTypesMiscellaneous); var validateUserDefinedFactoryField = new ValidateUserDefinedFactoryField(); var validateUserDefinedFactoryMethod = new ValidateUserDefinedFactoryMethod(); var validateAttributes = new ValidateAttributes(); var validateTransientScope = new ValidateTransientScope( validateUserDefinedAddForDisposalSync, validateUserDefinedAddForDisposalAsync, - validateUserDefinedConstrParam, + validateUserDefinedConstrParamsInjectionMethod, + validateUserDefinedPropertiesInjectionMethod, validateUserDefinedFactoryMethod, validateUserDefinedFactoryField, wellKnownTypes, @@ -45,7 +47,8 @@ public void Execute(GeneratorExecutionContext context) var validateScope = new ValidateScope( validateUserDefinedAddForDisposalSync, validateUserDefinedAddForDisposalAsync, - validateUserDefinedConstrParam, + validateUserDefinedConstrParamsInjectionMethod, + validateUserDefinedPropertiesInjectionMethod, validateUserDefinedFactoryMethod, validateUserDefinedFactoryField, wellKnownTypes, @@ -56,7 +59,8 @@ public void Execute(GeneratorExecutionContext context) validateScope, validateUserDefinedAddForDisposalSync, validateUserDefinedAddForDisposalAsync, - validateUserDefinedConstrParam, + validateUserDefinedConstrParamsInjectionMethod, + validateUserDefinedPropertiesInjectionMethod, validateUserDefinedFactoryMethod, validateUserDefinedFactoryField, wellKnownTypes, diff --git a/Main/UserDefinedElements.cs b/Main/UserDefinedElements.cs index 93fb58b1..8cd3079a 100644 --- a/Main/UserDefinedElements.cs +++ b/Main/UserDefinedElements.cs @@ -7,7 +7,8 @@ internal interface IUserDefinedElements IMethodSymbol? GetFactoryMethodFor(ITypeSymbol type); IMethodSymbol? AddForDisposal { get; } IMethodSymbol? AddForDisposalAsync { get; } - IMethodSymbol? GetCustomConstructorParameterChoiceFor(INamedTypeSymbol type); + IMethodSymbol? GetConstrParamsInjectionFor(INamedTypeSymbol type); + IMethodSymbol? GetPropertiesInjectionFor(INamedTypeSymbol type); } internal class EmptyUserDefinedElements : IUserDefinedElements @@ -17,7 +18,8 @@ internal class EmptyUserDefinedElements : IUserDefinedElements public IMethodSymbol? GetFactoryMethodFor(ITypeSymbol type) => null; public IMethodSymbol? AddForDisposal => null; public IMethodSymbol? AddForDisposalAsync => null; - public IMethodSymbol? GetCustomConstructorParameterChoiceFor(INamedTypeSymbol type) => null; + public IMethodSymbol? GetConstrParamsInjectionFor(INamedTypeSymbol type) => null; + public IMethodSymbol? GetPropertiesInjectionFor(INamedTypeSymbol type) => null; } internal class UserDefinedElements : IUserDefinedElements @@ -25,7 +27,8 @@ internal class UserDefinedElements : IUserDefinedElements private readonly IReadOnlyDictionary _typeToField; private readonly IReadOnlyDictionary _typeToProperty; private readonly IReadOnlyDictionary _typeToMethod; - private readonly IReadOnlyDictionary _customConstructorParameterChoiceMethods; + private readonly IReadOnlyDictionary _constrParamsInjectionMethods; + private readonly IReadOnlyDictionary _propertiesInjectionMethods; public UserDefinedElements( // parameter @@ -65,11 +68,11 @@ public UserDefinedElements( containerType, "Multiple user-defined factories aren't allowed to have the same type.")); - _typeToField = new Dictionary(); + _typeToField = new Dictionary(SymbolEqualityComparer.Default); - _typeToProperty = new Dictionary(); + _typeToProperty = new Dictionary(SymbolEqualityComparer.Default); - _typeToMethod = new Dictionary(); + _typeToMethod = new Dictionary(SymbolEqualityComparer.Default); } else { @@ -117,16 +120,24 @@ public UserDefinedElements( .OfType() .FirstOrDefault(); - var constrParamCandidates = dieMembers - .Where(s => s.Name.StartsWith(Constants.UserDefinedConstructorParameters)) + _constrParamsInjectionMethods = GetInjectionMethods(Constants.UserDefinedConstrParams, wellKnownTypesMiscellaneous.UserDefinedConstrParamsInjectionAttribute); + + _propertiesInjectionMethods = GetInjectionMethods(Constants.UserDefinedProperties, wellKnownTypesMiscellaneous.UserDefinedPropertiesInjectionAttribute); + + if (validationErrors.Any()) + throw new ValidationDieException(validationErrors.ToImmutableArray()); + + IReadOnlyDictionary GetInjectionMethods(string prefix, INamedTypeSymbol attributeType) + { + var injectionMethodCandidates = dieMembers + .Where(s => s.Name.StartsWith(prefix)) .Where(s => s is IMethodSymbol { ReturnsVoid: true, Arity: 0, IsConditional: false, MethodKind: MethodKind.Ordinary } method && method.Parameters.Any(p => p.RefKind == RefKind.Out)) .OfType() .Select(m => { var type = m.GetAttributes() - .Where(ad => SymbolEqualityComparer.Default.Equals(ad.AttributeClass, - wellKnownTypesMiscellaneous.CustomConstructorParameterAttribute)) + .Where(ad => SymbolEqualityComparer.Default.Equals(ad.AttributeClass, attributeType)) .Select(ad => { if (ad.ConstructorArguments.Length != 1) @@ -141,31 +152,29 @@ public UserDefinedElements( .OfType<(INamedTypeSymbol, IMethodSymbol)>() .ToImmutableArray(); - var constrParamGroupings = constrParamCandidates - .GroupBy(t => t.Item1, SymbolEqualityComparer.Default) - .Where(g => g.Count() > 1) - .ToImmutableArray(); - - if (constrParamGroupings.Any()) - { - foreach (var nonValidConstrParamGroup in constrParamGroupings) - foreach (var t in nonValidConstrParamGroup) - validationErrors.Add( - Diagnostics.ValidationUserDefinedElement( - t.Item2, - scopeType, - containerType, - "Multiple user-defined custom constructor parameter methods aren't allowed to have the same type that they are based on.")); - - _customConstructorParameterChoiceMethods = new Dictionary(); - } - else - _customConstructorParameterChoiceMethods = constrParamCandidates + var injectionMethodGroupings = injectionMethodCandidates + .GroupBy(t => t.Item1, SymbolEqualityComparer.Default) + .Where(g => g.Count() > 1) + .ToImmutableArray(); + + if (injectionMethodGroupings.Any()) + { + foreach (var nonValidInjectionMethodGroup in injectionMethodGroupings) + foreach (var t in nonValidInjectionMethodGroup) + validationErrors.Add( + Diagnostics.ValidationUserDefinedElement( + t.Item2, + scopeType, + containerType, + "Multiple user-defined custom constructor parameter methods aren't allowed to have the same type that they are based on.")); + + return new Dictionary(SymbolEqualityComparer.Default); + } + + return injectionMethodCandidates .OfType<(INamedTypeSymbol, IMethodSymbol)>() .ToDictionary(t => t.Item1, t => t.Item2, SymbolEqualityComparer.Default); - - if (validationErrors.Any()) - throw new ValidationDieException(validationErrors.ToImmutableArray()); + } } public IFieldSymbol? GetFactoryFieldFor(ITypeSymbol typeSymbol) => @@ -179,6 +188,9 @@ public UserDefinedElements( public IMethodSymbol? AddForDisposal { get; } public IMethodSymbol? AddForDisposalAsync { get; } - public IMethodSymbol? GetCustomConstructorParameterChoiceFor(INamedTypeSymbol type) => - _customConstructorParameterChoiceMethods.TryGetValue(type, out var ret) ? ret : null; + public IMethodSymbol? GetConstrParamsInjectionFor(INamedTypeSymbol type) => + _constrParamsInjectionMethods.TryGetValue(type, out var ret) ? ret : null; + + public IMethodSymbol? GetPropertiesInjectionFor(INamedTypeSymbol type) => + _propertiesInjectionMethods.TryGetValue(type, out var ret) ? ret : null; } \ No newline at end of file diff --git a/Main/Validation/Range/UserDefined/ValidateUserDefinedConstrParamsInjectionMethod.cs b/Main/Validation/Range/UserDefined/ValidateUserDefinedConstrParamsInjectionMethod.cs new file mode 100644 index 00000000..22b44abe --- /dev/null +++ b/Main/Validation/Range/UserDefined/ValidateUserDefinedConstrParamsInjectionMethod.cs @@ -0,0 +1,14 @@ +namespace MrMeeseeks.DIE.Validation.Range.UserDefined; + +internal interface IValidateUserDefinedConstrParamsInjectionMethod : IValidateUserDefinedInjectionMethod +{ + +} + +internal class ValidateUserDefinedConstrParamsInjectionMethod : ValidateUserDefinedInjectionMethod, IValidateUserDefinedConstrParamsInjectionMethod +{ + internal ValidateUserDefinedConstrParamsInjectionMethod(WellKnownTypesMiscellaneous wellKnownTypesMiscellaneous) => + InjectionAttribute = wellKnownTypesMiscellaneous.UserDefinedConstrParamsInjectionAttribute; + + protected override INamedTypeSymbol InjectionAttribute { get; } +} \ No newline at end of file diff --git a/Main/Validation/Range/UserDefined/ValidateUserDefinedConstrParamMethod.cs b/Main/Validation/Range/UserDefined/ValidateUserDefinedInjectionMethod.cs similarity index 84% rename from Main/Validation/Range/UserDefined/ValidateUserDefinedConstrParamMethod.cs rename to Main/Validation/Range/UserDefined/ValidateUserDefinedInjectionMethod.cs index f0fb9eff..21bd95fa 100644 --- a/Main/Validation/Range/UserDefined/ValidateUserDefinedConstrParamMethod.cs +++ b/Main/Validation/Range/UserDefined/ValidateUserDefinedInjectionMethod.cs @@ -1,16 +1,13 @@ namespace MrMeeseeks.DIE.Validation.Range.UserDefined; -internal interface IValidateUserDefinedConstrParam : IValidateUserDefinedMethod +internal interface IValidateUserDefinedInjectionMethod : IValidateUserDefinedMethod { } -internal class ValidateUserDefinedConstrParam : ValidateUserDefinedMethod, IValidateUserDefinedConstrParam +internal abstract class ValidateUserDefinedInjectionMethod : ValidateUserDefinedMethod, IValidateUserDefinedInjectionMethod { - private readonly WellKnownTypesMiscellaneous _wellKnownTypesMiscellaneous; - - internal ValidateUserDefinedConstrParam(WellKnownTypesMiscellaneous wellKnownTypesMiscellaneous) => - _wellKnownTypesMiscellaneous = wellKnownTypesMiscellaneous; + protected abstract INamedTypeSymbol InjectionAttribute { get; } public override IEnumerable Validate(IMethodSymbol method, INamedTypeSymbol rangeType, INamedTypeSymbol containerType) { @@ -73,8 +70,8 @@ public override IEnumerable Validate(IMethodSymbol method, INamedTyp if (method .GetAttributes() - .Count(ad => SymbolEqualityComparer.Default.Equals(ad.AttributeClass, _wellKnownTypesMiscellaneous.CustomConstructorParameterAttribute)) + .Count(ad => SymbolEqualityComparer.Default.Equals(ad.AttributeClass, InjectionAttribute)) != 1) - yield return ValidationErrorDiagnostic(method, rangeType, containerType, $"Has to have exactly one attribute of type \"{_wellKnownTypesMiscellaneous.CustomConstructorParameterAttribute.FullName()}\"."); + yield return ValidationErrorDiagnostic(method, rangeType, containerType, $"Has to have exactly one attribute of type \"{InjectionAttribute.FullName()}\"."); } } \ No newline at end of file diff --git a/Main/Validation/Range/UserDefined/ValidateUserDefinedPropertiesInjectionMethod.cs b/Main/Validation/Range/UserDefined/ValidateUserDefinedPropertiesInjectionMethod.cs new file mode 100644 index 00000000..ba338fe3 --- /dev/null +++ b/Main/Validation/Range/UserDefined/ValidateUserDefinedPropertiesInjectionMethod.cs @@ -0,0 +1,14 @@ +namespace MrMeeseeks.DIE.Validation.Range.UserDefined; + +internal interface IValidateUserDefinedPropertiesMethod: IValidateUserDefinedInjectionMethod +{ + +} + +internal class ValidateUserDefinedPropertiesInjectionMethod : ValidateUserDefinedInjectionMethod, IValidateUserDefinedPropertiesMethod +{ + internal ValidateUserDefinedPropertiesInjectionMethod(WellKnownTypesMiscellaneous wellKnownTypesMiscellaneous) => + InjectionAttribute = wellKnownTypesMiscellaneous.UserDefinedPropertiesInjectionAttribute; + + protected override INamedTypeSymbol InjectionAttribute { get; } +} \ No newline at end of file diff --git a/Main/Validation/Range/ValidateContainer.cs b/Main/Validation/Range/ValidateContainer.cs index 37cb5eaa..7c83a72b 100644 --- a/Main/Validation/Range/ValidateContainer.cs +++ b/Main/Validation/Range/ValidateContainer.cs @@ -19,7 +19,8 @@ internal ValidateContainer( IValidateScope validateScopeFactory, IValidateUserDefinedAddForDisposalSync validateUserDefinedAddForDisposalSync, IValidateUserDefinedAddForDisposalAsync validateUserDefinedAddForDisposalAsync, - IValidateUserDefinedConstrParam validateUserDefinedConstrParam, + IValidateUserDefinedConstrParamsInjectionMethod validateUserDefinedConstrParamsInjectionMethod, + IValidateUserDefinedPropertiesMethod validateUserDefinedPropertiesMethod, IValidateUserDefinedFactoryMethod validateUserDefinedFactoryMethod, IValidateUserDefinedFactoryField validateUserDefinedFactoryField, WellKnownTypes wellKnownTypes, @@ -27,7 +28,8 @@ internal ValidateContainer( : base( validateUserDefinedAddForDisposalSync, validateUserDefinedAddForDisposalAsync, - validateUserDefinedConstrParam, + validateUserDefinedConstrParamsInjectionMethod, + validateUserDefinedPropertiesMethod, validateUserDefinedFactoryMethod, validateUserDefinedFactoryField, wellKnownTypes) @@ -112,7 +114,7 @@ public override IEnumerable Validate(INamedTypeSymbol rangeType, INa yield return ValidationErrorDiagnostic(rangeType, "Attribute doesn't have expected constructor arguments.", location); } - IEnumerable ValidateCustomScope(INamedTypeSymbol customScope, ISet customScopeTypes) + IEnumerable ValidateCustomScope(INamedTypeSymbol customScope, ISet customScopeTypesSet) { var customScopeAttributes = customScope .GetAttributes() @@ -127,14 +129,15 @@ IEnumerable ValidateCustomScope(INamedTypeSymbol customScope, ISet ad.ConstructorArguments[0].Values) + .Select(tc => tc.Value) .OfType() .ToList(); foreach (var scopeRootType in scopeRootTypes - .Where(scopeRootType => customScopeTypes.Contains(scopeRootType, SymbolEqualityComparer.Default))) + .Where(scopeRootType => customScopeTypesSet.Contains(scopeRootType, SymbolEqualityComparer.Default))) { yield return ValidationErrorDiagnostic(rangeType, containerType, $"Custom scope \"{customScope.Name}\" gets the type \"{scopeRootType.FullName()}\" passed into one of its \"{_wellKnownTypesMiscellaneous.CustomScopeForRootTypesAttribute.FullName()}\"-attributes, but it is already in use in another custom scope."); } - customScopeTypes.UnionWith(scopeRootTypes); + customScopeTypesSet.UnionWith(scopeRootTypes); } } diff --git a/Main/Validation/Range/ValidateRange.cs b/Main/Validation/Range/ValidateRange.cs index 0a0dc90f..365e2089 100644 --- a/Main/Validation/Range/ValidateRange.cs +++ b/Main/Validation/Range/ValidateRange.cs @@ -12,7 +12,8 @@ internal abstract class ValidateRange : IValidateRange { private readonly IValidateUserDefinedAddForDisposalSync _validateUserDefinedAddForDisposalSync; private readonly IValidateUserDefinedAddForDisposalAsync _validateUserDefinedAddForDisposalAsync; - private readonly IValidateUserDefinedConstrParam _validateUserDefinedConstrParam; + private readonly IValidateUserDefinedConstrParamsInjectionMethod _validateUserDefinedConstrParamsInjectionMethod; + private readonly IValidateUserDefinedPropertiesMethod _validateUserDefinedPropertiesMethod; private readonly IValidateUserDefinedFactoryMethod _validateUserDefinedFactoryMethod; private readonly IValidateUserDefinedFactoryField _validateUserDefinedFactoryField; private readonly WellKnownTypes _wellKnownTypes; @@ -21,14 +22,16 @@ internal abstract class ValidateRange : IValidateRange internal ValidateRange( IValidateUserDefinedAddForDisposalSync validateUserDefinedAddForDisposalSync, IValidateUserDefinedAddForDisposalAsync validateUserDefinedAddForDisposalAsync, - IValidateUserDefinedConstrParam validateUserDefinedConstrParam, + IValidateUserDefinedConstrParamsInjectionMethod validateUserDefinedConstrParamsInjectionMethod, + IValidateUserDefinedPropertiesMethod validateUserDefinedPropertiesMethod, IValidateUserDefinedFactoryMethod validateUserDefinedFactoryMethod, IValidateUserDefinedFactoryField validateUserDefinedFactoryField, WellKnownTypes wellKnownTypes) { _validateUserDefinedAddForDisposalSync = validateUserDefinedAddForDisposalSync; _validateUserDefinedAddForDisposalAsync = validateUserDefinedAddForDisposalAsync; - _validateUserDefinedConstrParam = validateUserDefinedConstrParam; + _validateUserDefinedConstrParamsInjectionMethod = validateUserDefinedConstrParamsInjectionMethod; + _validateUserDefinedPropertiesMethod = validateUserDefinedPropertiesMethod; _validateUserDefinedFactoryMethod = validateUserDefinedFactoryMethod; _validateUserDefinedFactoryField = validateUserDefinedFactoryField; _wellKnownTypes = wellKnownTypes; @@ -104,22 +107,10 @@ public virtual IEnumerable Validate(INamedTypeSymbol rangeType, INam foreach (var diagnostic in ValidateAddForDisposal(Constants.UserDefinedAddForDisposalAsync, false)) yield return diagnostic; - var userDefinedConstructorParameters = rangeType - .GetMembers() - .Where(s => s.Name.StartsWith(Constants.UserDefinedConstructorParameters)) - .ToImmutableArray(); - - if (userDefinedConstructorParameters.Any()) - { - foreach (var symbol in userDefinedConstructorParameters - .Where(s => s is not IMethodSymbol)) - yield return ValidationErrorDiagnostic(rangeType, containerType, $"Member \"{symbol.Name}\" should be a method but isn't."); - - foreach (var userDefinedConstructorParameterMethod in userDefinedConstructorParameters - .OfType()) - foreach (var diagnostic in _validateUserDefinedConstrParam.Validate(userDefinedConstructorParameterMethod, rangeType, containerType)) - yield return diagnostic; - } + foreach (var diagnostic in ValidateUserDefinedInjection(Constants.UserDefinedConstrParams, _validateUserDefinedConstrParamsInjectionMethod)) + yield return diagnostic; + foreach (var diagnostic in ValidateUserDefinedInjection(Constants.UserDefinedProperties, _validateUserDefinedPropertiesMethod)) + yield return diagnostic; var userDefinedFactories = rangeType .GetMembers() @@ -177,6 +168,25 @@ IEnumerable ValidateAddForDisposal(string addForDisposalName, bool i } } } + + IEnumerable ValidateUserDefinedInjection(string prefix, IValidateUserDefinedInjectionMethod validateUserDefinedInjectionMethod) + { + var userDefinedInjectionMethods = rangeType + .GetMembers() + .Where(s => s.Name.StartsWith(prefix)) + .ToImmutableArray(); + + if (userDefinedInjectionMethods.Any()) + { + foreach (var symbol in userDefinedInjectionMethods + .Where(s => s is not IMethodSymbol)) + yield return ValidationErrorDiagnostic(rangeType, containerType, $"Member \"{symbol.Name}\" should be a method but isn't."); + + foreach (var userDefinedPropertyMethod in userDefinedInjectionMethods.OfType()) + foreach (var diagnostic in validateUserDefinedInjectionMethod.Validate(userDefinedPropertyMethod, rangeType, containerType)) + yield return diagnostic; + } + } } if (rangeType.IsAbstract) diff --git a/Main/Validation/Range/ValidateScope.cs b/Main/Validation/Range/ValidateScope.cs index 845f5f1b..7f3f879f 100644 --- a/Main/Validation/Range/ValidateScope.cs +++ b/Main/Validation/Range/ValidateScope.cs @@ -11,7 +11,8 @@ internal class ValidateScope : ValidateScopeBase, IValidateScope internal ValidateScope( IValidateUserDefinedAddForDisposalSync validateUserDefinedAddForDisposalSync, IValidateUserDefinedAddForDisposalAsync validateUserDefinedAddForDisposalAsync, - IValidateUserDefinedConstrParam validateUserDefinedConstrParam, + IValidateUserDefinedConstrParamsInjectionMethod validateUserDefinedConstrParamsInjectionMethod, + IValidateUserDefinedPropertiesMethod validateUserDefinedPropertiesMethod, IValidateUserDefinedFactoryMethod validateUserDefinedFactoryMethod, IValidateUserDefinedFactoryField validateUserDefinedFactoryField, WellKnownTypes wellKnownTypes, @@ -20,7 +21,8 @@ internal ValidateScope( : base( validateUserDefinedAddForDisposalSync, validateUserDefinedAddForDisposalAsync, - validateUserDefinedConstrParam, + validateUserDefinedConstrParamsInjectionMethod, + validateUserDefinedPropertiesMethod, validateUserDefinedFactoryMethod, validateUserDefinedFactoryField, wellKnownTypes, diff --git a/Main/Validation/Range/ValidateScopeBase.cs b/Main/Validation/Range/ValidateScopeBase.cs index 236a13a0..6ac6ce75 100644 --- a/Main/Validation/Range/ValidateScopeBase.cs +++ b/Main/Validation/Range/ValidateScopeBase.cs @@ -14,7 +14,8 @@ internal abstract class ValidateScopeBase : ValidateRange, IValidateScopeBase internal ValidateScopeBase( IValidateUserDefinedAddForDisposalSync validateUserDefinedAddForDisposalSync, IValidateUserDefinedAddForDisposalAsync validateUserDefinedAddForDisposalAsync, - IValidateUserDefinedConstrParam validateUserDefinedConstrParam, + IValidateUserDefinedConstrParamsInjectionMethod validateUserDefinedConstrParamsInjectionMethod, + IValidateUserDefinedPropertiesMethod validateUserDefinedPropertiesMethod, IValidateUserDefinedFactoryMethod validateUserDefinedFactoryMethod, IValidateUserDefinedFactoryField validateUserDefinedFactoryField, WellKnownTypes wellKnownTypes, @@ -23,14 +24,16 @@ internal ValidateScopeBase( : base( validateUserDefinedAddForDisposalSync, validateUserDefinedAddForDisposalAsync, - validateUserDefinedConstrParam, + validateUserDefinedConstrParamsInjectionMethod, + validateUserDefinedPropertiesMethod, validateUserDefinedFactoryMethod, validateUserDefinedFactoryField, wellKnownTypes) { _wellKnownTypesMiscellaneous = wellKnownTypesMiscellaneous; - _notAllowedAttributeTypes = ImmutableHashSet.Create( + _notAllowedAttributeTypes = ImmutableHashSet.Create( + SymbolEqualityComparer.Default, wellKnownTypesAggregation.ContainerInstanceAbstractionAggregationAttribute, wellKnownTypesAggregation.ContainerInstanceImplementationAggregationAttribute, wellKnownTypesAggregation.FilterContainerInstanceAbstractionAggregationAttribute, diff --git a/Main/Validation/Range/ValidateTransientScope.cs b/Main/Validation/Range/ValidateTransientScope.cs index ea38cf47..74bc630b 100644 --- a/Main/Validation/Range/ValidateTransientScope.cs +++ b/Main/Validation/Range/ValidateTransientScope.cs @@ -11,7 +11,8 @@ internal class ValidateTransientScope : ValidateScopeBase, IValidateTransientSco internal ValidateTransientScope( IValidateUserDefinedAddForDisposalSync validateUserDefinedAddForDisposalSync, IValidateUserDefinedAddForDisposalAsync validateUserDefinedAddForDisposalAsync, - IValidateUserDefinedConstrParam validateUserDefinedConstrParam, + IValidateUserDefinedConstrParamsInjectionMethod validateUserDefinedConstrParamsInjectionMethod, + IValidateUserDefinedPropertiesMethod validateUserDefinedPropertiesMethod, IValidateUserDefinedFactoryMethod validateUserDefinedFactoryMethod, IValidateUserDefinedFactoryField validateUserDefinedFactoryField, WellKnownTypes wellKnownTypes, @@ -20,7 +21,8 @@ internal ValidateTransientScope( : base( validateUserDefinedAddForDisposalSync, validateUserDefinedAddForDisposalAsync, - validateUserDefinedConstrParam, + validateUserDefinedConstrParamsInjectionMethod, + validateUserDefinedPropertiesMethod, validateUserDefinedFactoryMethod, validateUserDefinedFactoryField, wellKnownTypes, diff --git a/Main/WellKnownTypesMiscellaneous.cs b/Main/WellKnownTypesMiscellaneous.cs index e3deb195..279e0183 100644 --- a/Main/WellKnownTypesMiscellaneous.cs +++ b/Main/WellKnownTypesMiscellaneous.cs @@ -6,7 +6,8 @@ internal record WellKnownTypesMiscellaneous( INamedTypeSymbol TypeInitializerAttribute, INamedTypeSymbol FilterTypeInitializerAttribute, INamedTypeSymbol CustomScopeForRootTypesAttribute, - INamedTypeSymbol CustomConstructorParameterAttribute, + INamedTypeSymbol UserDefinedConstrParamsInjectionAttribute, + INamedTypeSymbol UserDefinedPropertiesInjectionAttribute, INamedTypeSymbol CreateFunctionAttribute, INamedTypeSymbol ErrorDescriptionInsteadOfBuildFailureAttribute, INamedTypeSymbol DieExceptionKind) @@ -16,8 +17,11 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypesMiscel var customScopeForRootTypesAttribute = compilation .GetTypeByMetadataName(typeof(CustomScopeForRootTypesAttribute).FullName ?? ""); - var customConstructorParameterAttribute = compilation - .GetTypeByMetadataName(typeof(CustomConstructorParameterAttribute).FullName ?? ""); + var userDefinedConstrParamsInjectionAttribute = compilation + .GetTypeByMetadataName(typeof(UserDefinedConstrParamsInjectionAttribute).FullName ?? ""); + + var userDefinedPropertiesInjectionAttribute = compilation + .GetTypeByMetadataName(typeof(UserDefinedPropertiesInjectionAttribute).FullName ?? ""); var typeInitializerAttribute = compilation .GetTypeByMetadataName(typeof(TypeInitializerAttribute).FullName ?? ""); @@ -37,7 +41,8 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypesMiscel if (typeInitializerAttribute is not null && filterTypeInitializerAttribute is not null && customScopeForRootTypesAttribute is not null - && customConstructorParameterAttribute is not null + && userDefinedConstrParamsInjectionAttribute is not null + && userDefinedPropertiesInjectionAttribute is not null && createFunctionAttribute is not null && errorDescriptionInsteadOfBuildFailureAttribute is not null && dieExceptionKind is not null) @@ -47,7 +52,8 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypesMiscel TypeInitializerAttribute: typeInitializerAttribute, FilterTypeInitializerAttribute: filterTypeInitializerAttribute, CustomScopeForRootTypesAttribute: customScopeForRootTypesAttribute, - CustomConstructorParameterAttribute: customConstructorParameterAttribute, + UserDefinedConstrParamsInjectionAttribute: userDefinedConstrParamsInjectionAttribute, + UserDefinedPropertiesInjectionAttribute: userDefinedPropertiesInjectionAttribute, CreateFunctionAttribute: createFunctionAttribute, ErrorDescriptionInsteadOfBuildFailureAttribute: errorDescriptionInsteadOfBuildFailureAttribute, DieExceptionKind: dieExceptionKind); diff --git a/Sample/Sample.csproj b/Sample/Sample.csproj index 2bba2ab3..f21bc7a0 100644 --- a/Sample/Sample.csproj +++ b/Sample/Sample.csproj @@ -11,7 +11,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Test/CustomEmbedding/ConstructorParameter.cs b/Test/CustomEmbedding/ConstrParam/Vanilla.cs similarity index 82% rename from Test/CustomEmbedding/ConstructorParameter.cs rename to Test/CustomEmbedding/ConstrParam/Vanilla.cs index ad323ad4..c2a21610 100644 --- a/Test/CustomEmbedding/ConstructorParameter.cs +++ b/Test/CustomEmbedding/ConstrParam/Vanilla.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.CustomEmbedding.ConstructorParameter; +namespace MrMeeseeks.DIE.Test.CustomEmbedding.ConstrParam.Vanilla; internal class Dependency { @@ -14,7 +14,7 @@ internal class Dependency [CreateFunction(typeof(Dependency), "Create")] internal sealed partial class Container { - [CustomConstructorParameter(typeof(Dependency))] + [UserDefinedConstrParamsInjection(typeof(Dependency))] private void DIE_ConstrParam_Dependency(out int number) => number = 69; } diff --git a/Test/CustomEmbedding/ConstructorParameterInScope.cs b/Test/CustomEmbedding/ConstrParam/VanillaInScope.cs similarity index 86% rename from Test/CustomEmbedding/ConstructorParameterInScope.cs rename to Test/CustomEmbedding/ConstrParam/VanillaInScope.cs index c58899a8..04524412 100644 --- a/Test/CustomEmbedding/ConstructorParameterInScope.cs +++ b/Test/CustomEmbedding/ConstrParam/VanillaInScope.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.CustomEmbedding.ConstructorParameterInScope; +namespace MrMeeseeks.DIE.Test.CustomEmbedding.ConstrParam.VanillaInScope; internal class Dependency { @@ -24,7 +24,7 @@ internal sealed partial class Container { private sealed partial class DIE_DefaultScope { - [CustomConstructorParameter(typeof(Dependency))] + [UserDefinedConstrParamsInjection(typeof(Dependency))] private void DIE_ConstrParam_Dependency(out int number) => number = 69; } } diff --git a/Test/CustomEmbedding/ConstructorParameterInTransientScope.cs b/Test/CustomEmbedding/ConstrParam/VanillaInTransientScope.cs similarity index 85% rename from Test/CustomEmbedding/ConstructorParameterInTransientScope.cs rename to Test/CustomEmbedding/ConstrParam/VanillaInTransientScope.cs index d906e2ba..6aa3601e 100644 --- a/Test/CustomEmbedding/ConstructorParameterInTransientScope.cs +++ b/Test/CustomEmbedding/ConstrParam/VanillaInTransientScope.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.CustomEmbedding.ConstructorParameterInTransientScope; +namespace MrMeeseeks.DIE.Test.CustomEmbedding.ConstrParam.VanillaInTransientScope; internal class Dependency { @@ -24,7 +24,7 @@ internal sealed partial class Container { private sealed partial class DIE_DefaultTransientScope { - [CustomConstructorParameter(typeof(Dependency))] + [UserDefinedConstrParamsInjection(typeof(Dependency))] private void DIE_ConstrParam_Dependency(out int number) => number = 69; } } diff --git a/Test/CustomEmbedding/ConstructorParameterWithAsyncDependency.cs b/Test/CustomEmbedding/ConstrParam/WithAsyncDependency.cs similarity index 85% rename from Test/CustomEmbedding/ConstructorParameterWithAsyncDependency.cs rename to Test/CustomEmbedding/ConstrParam/WithAsyncDependency.cs index c63e767c..acb46869 100644 --- a/Test/CustomEmbedding/ConstructorParameterWithAsyncDependency.cs +++ b/Test/CustomEmbedding/ConstrParam/WithAsyncDependency.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.CustomEmbedding.ConstructorParameterWithAsyncDependency; +namespace MrMeeseeks.DIE.Test.CustomEmbedding.ConstrParam.WithAsyncDependency; internal class Dependency { @@ -20,7 +20,7 @@ internal class OtherDependency : IValueTaskTypeInitializer [CreateFunction(typeof(Dependency), "Create")] internal sealed partial class Container { - [CustomConstructorParameter(typeof(Dependency))] + [UserDefinedConstrParamsInjection(typeof(Dependency))] private void DIE_ConstrParam_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; } diff --git a/Test/CustomEmbedding/ConstructorParameterWithAsyncDependencyInScope.cs b/Test/CustomEmbedding/ConstrParam/WithAsyncDependencyInScope.cs similarity index 87% rename from Test/CustomEmbedding/ConstructorParameterWithAsyncDependencyInScope.cs rename to Test/CustomEmbedding/ConstrParam/WithAsyncDependencyInScope.cs index 924eb4b3..c211383f 100644 --- a/Test/CustomEmbedding/ConstructorParameterWithAsyncDependencyInScope.cs +++ b/Test/CustomEmbedding/ConstrParam/WithAsyncDependencyInScope.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.CustomEmbedding.ConstructorParameterWithAsyncDependencyInScope; +namespace MrMeeseeks.DIE.Test.CustomEmbedding.ConstrParam.WithAsyncDependencyInScope; internal class Dependency { @@ -30,7 +30,7 @@ internal sealed partial class Container { private sealed partial class DIE_DefaultScope { - [CustomConstructorParameter(typeof(Dependency))] + [UserDefinedConstrParamsInjection(typeof(Dependency))] private void DIE_ConstrParam_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; } } diff --git a/Test/CustomEmbedding/ConstructorParameterWithAsyncDependencyInTransientScope.cs b/Test/CustomEmbedding/ConstrParam/WithAsyncDependencyInTransientScope.cs similarity index 87% rename from Test/CustomEmbedding/ConstructorParameterWithAsyncDependencyInTransientScope.cs rename to Test/CustomEmbedding/ConstrParam/WithAsyncDependencyInTransientScope.cs index f1ecf414..d8c4fdfb 100644 --- a/Test/CustomEmbedding/ConstructorParameterWithAsyncDependencyInTransientScope.cs +++ b/Test/CustomEmbedding/ConstrParam/WithAsyncDependencyInTransientScope.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.CustomEmbedding.ConstructorParameterWithAsyncDependencyInTransientScope; +namespace MrMeeseeks.DIE.Test.CustomEmbedding.ConstrParam.WithAsyncDependencyInTransientScope; internal class Dependency { @@ -30,7 +30,7 @@ internal sealed partial class Container { private sealed partial class DIE_DefaultTransientScope { - [CustomConstructorParameter(typeof(Dependency))] + [UserDefinedConstrParamsInjection(typeof(Dependency))] private void DIE_ConstrParam_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; } } diff --git a/Test/CustomEmbedding/ConstructorParameterWithDependency.cs b/Test/CustomEmbedding/ConstrParam/WithDependency.cs similarity index 84% rename from Test/CustomEmbedding/ConstructorParameterWithDependency.cs rename to Test/CustomEmbedding/ConstrParam/WithDependency.cs index f4edb130..345711e8 100644 --- a/Test/CustomEmbedding/ConstructorParameterWithDependency.cs +++ b/Test/CustomEmbedding/ConstrParam/WithDependency.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.CustomEmbedding.ConstructorParameterWithDependency; +namespace MrMeeseeks.DIE.Test.CustomEmbedding.ConstrParam.WithDependency; internal class Dependency { @@ -19,7 +19,7 @@ internal class OtherDependency [CreateFunction(typeof(Dependency), "Create")] internal sealed partial class Container { - [CustomConstructorParameter(typeof(Dependency))] + [UserDefinedConstrParamsInjection(typeof(Dependency))] private void DIE_ConstrParam_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; } diff --git a/Test/CustomEmbedding/ConstructorParameterWithDependencyInScope.cs b/Test/CustomEmbedding/ConstrParam/WithDependencyInScope.cs similarity index 86% rename from Test/CustomEmbedding/ConstructorParameterWithDependencyInScope.cs rename to Test/CustomEmbedding/ConstrParam/WithDependencyInScope.cs index e29057ed..37b07526 100644 --- a/Test/CustomEmbedding/ConstructorParameterWithDependencyInScope.cs +++ b/Test/CustomEmbedding/ConstrParam/WithDependencyInScope.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.CustomEmbedding.ConstructorParameterWithDependencyInScope; +namespace MrMeeseeks.DIE.Test.CustomEmbedding.ConstrParam.WithDependencyInScope; internal class Dependency { @@ -29,7 +29,7 @@ internal sealed partial class Container { private sealed partial class DIE_DefaultScope { - [CustomConstructorParameter(typeof(Dependency))] + [UserDefinedConstrParamsInjection(typeof(Dependency))] private void DIE_ConstrParam_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; } } diff --git a/Test/CustomEmbedding/ConstructorParameterWithDependencyInTransientScope.cs b/Test/CustomEmbedding/ConstrParam/WithDependencyInTransientScope.cs similarity index 86% rename from Test/CustomEmbedding/ConstructorParameterWithDependencyInTransientScope.cs rename to Test/CustomEmbedding/ConstrParam/WithDependencyInTransientScope.cs index aa668aa7..93c7484d 100644 --- a/Test/CustomEmbedding/ConstructorParameterWithDependencyInTransientScope.cs +++ b/Test/CustomEmbedding/ConstrParam/WithDependencyInTransientScope.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.CustomEmbedding.ConstructorParameterWithDependencyInTransientScope; +namespace MrMeeseeks.DIE.Test.CustomEmbedding.ConstrParam.WithDependencyInTransientScope; internal class Dependency { @@ -29,7 +29,7 @@ internal sealed partial class Container { private sealed partial class DIE_DefaultTransientScope { - [CustomConstructorParameter(typeof(Dependency))] + [UserDefinedConstrParamsInjection(typeof(Dependency))] private void DIE_ConstrParam_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; } } diff --git a/Test/CustomEmbedding/Properties/Vanilla.cs b/Test/CustomEmbedding/Properties/Vanilla.cs new file mode 100644 index 00000000..0b81f365 --- /dev/null +++ b/Test/CustomEmbedding/Properties/Vanilla.cs @@ -0,0 +1,28 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CustomEmbedding.Properties.Vanilla; + +internal class Dependency +{ + public int Number { get; init; } +} + +[CreateFunction(typeof(Dependency), "Create")] +internal sealed partial class Container +{ + [UserDefinedPropertiesInjection(typeof(Dependency))] + private void DIE_Properties_Dependency(out int Number) => Number = 69; +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var instance = container.Create(); + Assert.Equal(69, instance.Number); + } +} \ No newline at end of file diff --git a/Test/CustomEmbedding/Properties/VanillaInScope.cs b/Test/CustomEmbedding/Properties/VanillaInScope.cs new file mode 100644 index 00000000..eae4a45c --- /dev/null +++ b/Test/CustomEmbedding/Properties/VanillaInScope.cs @@ -0,0 +1,39 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CustomEmbedding.Properties.VanillaInScope; + +internal class Dependency +{ + public int Number { get; init; } +} + +internal class ScopeRoot : IScopeRoot +{ + public Dependency Dependency { get; } + + internal ScopeRoot( + Dependency dependency) => Dependency = dependency; +} + +[CreateFunction(typeof(ScopeRoot), "Create")] +internal sealed partial class Container +{ + private sealed partial class DIE_DefaultScope + { + [UserDefinedPropertiesInjection(typeof(Dependency))] + private void DIE_Properties_Dependency(out int Number) => Number = 69; + } +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var instance = container.Create().Dependency; + Assert.Equal(69, instance.Number); + } +} \ No newline at end of file diff --git a/Test/CustomEmbedding/Properties/VanillaInTransientScope.cs b/Test/CustomEmbedding/Properties/VanillaInTransientScope.cs new file mode 100644 index 00000000..0abc51e8 --- /dev/null +++ b/Test/CustomEmbedding/Properties/VanillaInTransientScope.cs @@ -0,0 +1,39 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CustomEmbedding.Properties.VanillaInTransientScope; + +internal class Dependency +{ + public int Number { get; init; } +} + +internal class TransientScopeRoot : ITransientScopeRoot +{ + public Dependency Dependency { get; } + + internal TransientScopeRoot( + Dependency dependency) => Dependency = dependency; +} + +[CreateFunction(typeof(TransientScopeRoot), "Create")] +internal sealed partial class Container +{ + private sealed partial class DIE_DefaultTransientScope + { + [UserDefinedPropertiesInjection(typeof(Dependency))] + private void DIE_Properties_Dependency(out int Number) => Number = 69; + } +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var instance = container.Create().Dependency; + Assert.Equal(69, instance.Number); + } +} \ No newline at end of file diff --git a/Test/CustomEmbedding/Properties/WithAsyncDependency.cs b/Test/CustomEmbedding/Properties/WithAsyncDependency.cs new file mode 100644 index 00000000..4a1f543b --- /dev/null +++ b/Test/CustomEmbedding/Properties/WithAsyncDependency.cs @@ -0,0 +1,34 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CustomEmbedding.Properties.WithAsyncDependency; + +internal class Dependency +{ + public int Number { get; init; } +} + +internal class OtherDependency : IValueTaskTypeInitializer +{ + public int Number => 69; + public ValueTask InitializeAsync() => new (Task.CompletedTask); +} + +[CreateFunction(typeof(Dependency), "Create")] +internal sealed partial class Container +{ + [UserDefinedPropertiesInjection(typeof(Dependency))] + private void DIE_Properties_Dependency(OtherDependency otherDependency, out int Number) => Number = otherDependency.Number; +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var instance = await container.CreateAsync().ConfigureAwait(false); + Assert.Equal(69, instance.Number); + } +} \ No newline at end of file diff --git a/Test/CustomEmbedding/Properties/WithAsyncDependencyInScope.cs b/Test/CustomEmbedding/Properties/WithAsyncDependencyInScope.cs new file mode 100644 index 00000000..83ceec39 --- /dev/null +++ b/Test/CustomEmbedding/Properties/WithAsyncDependencyInScope.cs @@ -0,0 +1,45 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CustomEmbedding.Properties.WithAsyncDependencyInScope; + +internal class Dependency +{ + public int Number { get; init; } +} + +internal class OtherDependency : IValueTaskTypeInitializer +{ + public int Number => 69; + public ValueTask InitializeAsync() => new (Task.CompletedTask); +} + +internal class ScopeRoot : IScopeRoot +{ + public Dependency Dependency { get; } + + internal ScopeRoot( + Dependency dependency) => Dependency = dependency; +} + +[CreateFunction(typeof(ScopeRoot), "Create")] +internal sealed partial class Container +{ + private sealed partial class DIE_DefaultScope + { + [UserDefinedPropertiesInjection(typeof(Dependency))] + private void DIE_Properties_Dependency(OtherDependency otherDependency, out int Number) => Number = otherDependency.Number; + } +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var instance = await container.CreateAsync().ConfigureAwait(false); + Assert.Equal(69, instance.Dependency.Number); + } +} \ No newline at end of file diff --git a/Test/CustomEmbedding/Properties/WithAsyncDependencyInTransientScope.cs b/Test/CustomEmbedding/Properties/WithAsyncDependencyInTransientScope.cs new file mode 100644 index 00000000..52637f99 --- /dev/null +++ b/Test/CustomEmbedding/Properties/WithAsyncDependencyInTransientScope.cs @@ -0,0 +1,45 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CustomEmbedding.Properties.WithAsyncDependencyInTransientScope; + +internal class Dependency +{ + public int Number { get; init; } +} + +internal class OtherDependency : IValueTaskTypeInitializer +{ + public int Number => 69; + public ValueTask InitializeAsync() => new (Task.CompletedTask); +} + +internal class TransientScopeRoot : ITransientScopeRoot +{ + public Dependency Dependency { get; } + + internal TransientScopeRoot( + Dependency dependency) => Dependency = dependency; +} + +[CreateFunction(typeof(TransientScopeRoot), "Create")] +internal sealed partial class Container +{ + private sealed partial class DIE_DefaultTransientScope + { + [UserDefinedPropertiesInjection(typeof(Dependency))] + private void DIE_Properties_Dependency(OtherDependency otherDependency, out int Number) => Number = otherDependency.Number; + } +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var instance = await container.CreateAsync().ConfigureAwait(false); + Assert.Equal(69, instance.Dependency.Number); + } +} \ No newline at end of file diff --git a/Test/CustomEmbedding/Properties/WithDependency.cs b/Test/CustomEmbedding/Properties/WithDependency.cs new file mode 100644 index 00000000..cb492c35 --- /dev/null +++ b/Test/CustomEmbedding/Properties/WithDependency.cs @@ -0,0 +1,33 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CustomEmbedding.Properties.WithDependency; + +internal class Dependency +{ + public int Number { get; init; } +} + +internal class OtherDependency +{ + public int Number => 69; +} + +[CreateFunction(typeof(Dependency), "Create")] +internal sealed partial class Container +{ + [UserDefinedPropertiesInjection(typeof(Dependency))] + private void DIE_Properties_Dependency(OtherDependency otherDependency, out int Number) => Number = otherDependency.Number; +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var instance = container.Create(); + Assert.Equal(69, instance.Number); + } +} \ No newline at end of file diff --git a/Test/CustomEmbedding/Properties/WithDependencyInScope.cs b/Test/CustomEmbedding/Properties/WithDependencyInScope.cs new file mode 100644 index 00000000..935ca1f3 --- /dev/null +++ b/Test/CustomEmbedding/Properties/WithDependencyInScope.cs @@ -0,0 +1,44 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CustomEmbedding.Properties.WithDependencyInScope; + +internal class Dependency +{ + public int Number { get; init; } +} + +internal class OtherDependency +{ + public int Number => 69; +} + +internal class ScopeRoot : IScopeRoot +{ + public Dependency Dependency { get; } + + internal ScopeRoot( + Dependency dependency) => Dependency = dependency; +} + +[CreateFunction(typeof(ScopeRoot), "Create")] +internal sealed partial class Container +{ + private sealed partial class DIE_DefaultScope + { + [UserDefinedPropertiesInjection(typeof(Dependency))] + private void DIE_Properties_Dependency(OtherDependency otherDependency, out int Number) => Number = otherDependency.Number; + } +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var instance = container.Create(); + Assert.Equal(69, instance.Dependency.Number); + } +} \ No newline at end of file diff --git a/Test/CustomEmbedding/Properties/WithDependencyInTransientScope.cs b/Test/CustomEmbedding/Properties/WithDependencyInTransientScope.cs new file mode 100644 index 00000000..a52ab50d --- /dev/null +++ b/Test/CustomEmbedding/Properties/WithDependencyInTransientScope.cs @@ -0,0 +1,44 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CustomEmbedding.Properties.WithDependencyInTransientScope; + +internal class Dependency +{ + public int Number { get; init; } +} + +internal class OtherDependency +{ + public int Number => 69; +} + +internal class TransientScopeRoot : ITransientScopeRoot +{ + public Dependency Dependency { get; } + + internal TransientScopeRoot( + Dependency dependency) => Dependency = dependency; +} + +[CreateFunction(typeof(TransientScopeRoot), "Create")] +internal sealed partial class Container +{ + private sealed partial class DIE_DefaultTransientScope + { + [UserDefinedPropertiesInjection(typeof(Dependency))] + private void DIE_Properties_Dependency(OtherDependency otherDependency, out int Number) => Number = otherDependency.Number; + } +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var instance = container.Create(); + Assert.Equal(69, instance.Dependency.Number); + } +} \ No newline at end of file From 82606ed192336f75705567f2b5ee42166b32bd93 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Thu, 25 Aug 2022 19:48:36 +0200 Subject: [PATCH 126/162] Consistent naming for user-defined injections --- Main/CodeBuilding/RangeCodeBaseBuilder.cs | 6 +++--- Main/Configuration/Attributes/Miscellaneous.cs | 4 ++-- Main/Constants.cs | 2 +- .../Function/FunctionResolutionBuilder.cs | 14 +++++++------- Main/ResolutionTreeItem.cs | 4 ++-- Main/SourceGenerator.cs | 8 ++++---- Main/UserDefinedElements.cs | 14 +++++++------- ...lidateUserDefinedConstrParamsInjectionMethod.cs | 8 ++++---- Main/Validation/Range/ValidateContainer.cs | 4 ++-- Main/Validation/Range/ValidateRange.cs | 10 +++++----- Main/Validation/Range/ValidateScope.cs | 4 ++-- Main/Validation/Range/ValidateScopeBase.cs | 4 ++-- Main/Validation/Range/ValidateTransientScope.cs | 4 ++-- Main/WellKnownTypesMiscellaneous.cs | 10 +++++----- .../FactoryField/InContainercs.cs} | 2 +- .../FactoryField/InContainercsTask.cs} | 2 +- .../FactoryField/InContainercsValueTask.cs} | 2 +- .../FactoryField/InScope.cs} | 2 +- .../FactoryField/InTransientScope.cs} | 2 +- .../FactoryMethod/InContainercs.cs} | 2 +- .../FactoryMethod/InContainercsTask.cs} | 2 +- .../FactoryMethod/InContainercsValueTask.cs} | 2 +- .../FactoryMethod/InScope.cs} | 2 +- .../FactoryMethod/InTransientScope.cs} | 2 +- .../FactoryMethod/WithParameterInContainercs.cs} | 2 +- .../FactoryMethod/WithParameterInScope.cs} | 2 +- .../WithParameterInTransientScope.cs} | 2 +- .../FactoryProperty/InContainer.cs} | 2 +- .../FactoryProperty/InContainerTask.cs} | 2 +- .../FactoryProperty/InContainerValueTask.cs} | 2 +- .../FactoryProperty/InScope.cs} | 2 +- .../FactoryProperty/InTransientScope.cs} | 2 +- .../InjectionConstrParams}/Vanilla.cs | 4 ++-- .../InjectionConstrParams}/VanillaInScope.cs | 4 ++-- .../VanillaInTransientScope.cs | 4 ++-- .../InjectionConstrParams}/WithAsyncDependency.cs | 4 ++-- .../WithAsyncDependencyInScope.cs | 4 ++-- .../WithAsyncDependencyInTransientScope.cs | 4 ++-- .../InjectionConstrParams}/WithDependency.cs | 4 ++-- .../WithDependencyInScope.cs | 4 ++-- .../WithDependencyInTransientScope.cs | 4 ++-- .../InjectionProps}/Vanilla.cs | 4 ++-- .../InjectionProps}/VanillaInScope.cs | 4 ++-- .../InjectionProps}/VanillaInTransientScope.cs | 4 ++-- .../InjectionProps}/WithAsyncDependency.cs | 4 ++-- .../InjectionProps}/WithAsyncDependencyInScope.cs | 4 ++-- .../WithAsyncDependencyInTransientScope.cs | 4 ++-- .../InjectionProps}/WithDependency.cs | 4 ++-- .../InjectionProps}/WithDependencyInScope.cs | 4 ++-- .../WithDependencyInTransientScope.cs | 4 ++-- 50 files changed, 102 insertions(+), 102 deletions(-) rename Test/{CustomEmbedding/FieldInContainercs.cs => UserDefinedElements/FactoryField/InContainercs.cs} (88%) rename Test/{CustomEmbedding/FieldInContainercsTask.cs => UserDefinedElements/FactoryField/InContainercsTask.cs} (89%) rename Test/{CustomEmbedding/FieldInContainercsValueTask.cs => UserDefinedElements/FactoryField/InContainercsValueTask.cs} (88%) rename Test/{CustomEmbedding/FieldInScope.cs => UserDefinedElements/FactoryField/InScope.cs} (90%) rename Test/{CustomEmbedding/FieldInTransientScope.cs => UserDefinedElements/FactoryField/InTransientScope.cs} (90%) rename Test/{CustomEmbedding/FactoryInContainercs.cs => UserDefinedElements/FactoryMethod/InContainercs.cs} (88%) rename Test/{CustomEmbedding/FactoryInContainercsTask.cs => UserDefinedElements/FactoryMethod/InContainercsTask.cs} (88%) rename Test/{CustomEmbedding/FactoryInContainercsValueTask.cs => UserDefinedElements/FactoryMethod/InContainercsValueTask.cs} (88%) rename Test/{CustomEmbedding/FactoryInScope.cs => UserDefinedElements/FactoryMethod/InScope.cs} (90%) rename Test/{CustomEmbedding/FactoryInTransientScope.cs => UserDefinedElements/FactoryMethod/InTransientScope.cs} (89%) rename Test/{CustomEmbedding/FactoryWithParameterInContainercs.cs => UserDefinedElements/FactoryMethod/WithParameterInContainercs.cs} (86%) rename Test/{CustomEmbedding/FactoryWithParameterInScope.cs => UserDefinedElements/FactoryMethod/WithParameterInScope.cs} (90%) rename Test/{CustomEmbedding/FactoryWithParameterInTransientScope.cs => UserDefinedElements/FactoryMethod/WithParameterInTransientScope.cs} (89%) rename Test/{CustomEmbedding/PropertyInContainer.cs => UserDefinedElements/FactoryProperty/InContainer.cs} (88%) rename Test/{CustomEmbedding/PropertyInContainerTask.cs => UserDefinedElements/FactoryProperty/InContainerTask.cs} (88%) rename Test/{CustomEmbedding/PropertyInContainerValueTask.cs => UserDefinedElements/FactoryProperty/InContainerValueTask.cs} (88%) rename Test/{CustomEmbedding/PropertyInScope.cs => UserDefinedElements/FactoryProperty/InScope.cs} (89%) rename Test/{CustomEmbedding/PropertyInTransientScope.cs => UserDefinedElements/FactoryProperty/InTransientScope.cs} (89%) rename Test/{CustomEmbedding/ConstrParam => UserDefinedElements/InjectionConstrParams}/Vanilla.cs (80%) rename Test/{CustomEmbedding/ConstrParam => UserDefinedElements/InjectionConstrParams}/VanillaInScope.cs (84%) rename Test/{CustomEmbedding/ConstrParam => UserDefinedElements/InjectionConstrParams}/VanillaInTransientScope.cs (83%) rename Test/{CustomEmbedding/ConstrParam => UserDefinedElements/InjectionConstrParams}/WithAsyncDependency.cs (83%) rename Test/{CustomEmbedding/ConstrParam => UserDefinedElements/InjectionConstrParams}/WithAsyncDependencyInScope.cs (86%) rename Test/{CustomEmbedding/ConstrParam => UserDefinedElements/InjectionConstrParams}/WithAsyncDependencyInTransientScope.cs (86%) rename Test/{CustomEmbedding/ConstrParam => UserDefinedElements/InjectionConstrParams}/WithDependency.cs (82%) rename Test/{CustomEmbedding/ConstrParam => UserDefinedElements/InjectionConstrParams}/WithDependencyInScope.cs (85%) rename Test/{CustomEmbedding/ConstrParam => UserDefinedElements/InjectionConstrParams}/WithDependencyInTransientScope.cs (85%) rename Test/{CustomEmbedding/Properties => UserDefinedElements/InjectionProps}/Vanilla.cs (78%) rename Test/{CustomEmbedding/Properties => UserDefinedElements/InjectionProps}/VanillaInScope.cs (83%) rename Test/{CustomEmbedding/Properties => UserDefinedElements/InjectionProps}/VanillaInTransientScope.cs (83%) rename Test/{CustomEmbedding/Properties => UserDefinedElements/InjectionProps}/WithAsyncDependency.cs (77%) rename Test/{CustomEmbedding/Properties => UserDefinedElements/InjectionProps}/WithAsyncDependencyInScope.cs (81%) rename Test/{CustomEmbedding/Properties => UserDefinedElements/InjectionProps}/WithAsyncDependencyInTransientScope.cs (81%) rename Test/{CustomEmbedding/Properties => UserDefinedElements/InjectionProps}/WithDependency.cs (74%) rename Test/{CustomEmbedding/Properties => UserDefinedElements/InjectionProps}/WithDependencyInScope.cs (79%) rename Test/{CustomEmbedding/Properties => UserDefinedElements/InjectionProps}/WithDependencyInTransientScope.cs (79%) diff --git a/Main/CodeBuilding/RangeCodeBaseBuilder.cs b/Main/CodeBuilding/RangeCodeBaseBuilder.cs index 904481ea..312a752f 100644 --- a/Main/CodeBuilding/RangeCodeBaseBuilder.cs +++ b/Main/CodeBuilding/RangeCodeBaseBuilder.cs @@ -386,10 +386,10 @@ private StringBuilder GenerateResolutions( var parameters, var initializedProperties, var initialization, - var userDefinedConstrParamsInjection, + var userDefinedConstructorParametersInjection, var userDefinedPropertiesInjection): - if (userDefinedConstrParamsInjection is { }) - GenerateResolutions(stringBuilder, userDefinedConstrParamsInjection); + if (userDefinedConstructorParametersInjection is { }) + GenerateResolutions(stringBuilder, userDefinedConstructorParametersInjection); if (userDefinedPropertiesInjection is { }) GenerateResolutions(stringBuilder, userDefinedPropertiesInjection); stringBuilder = parameters.Aggregate(stringBuilder, diff --git a/Main/Configuration/Attributes/Miscellaneous.cs b/Main/Configuration/Attributes/Miscellaneous.cs index 31d262c8..e09fc4bc 100644 --- a/Main/Configuration/Attributes/Miscellaneous.cs +++ b/Main/Configuration/Attributes/Miscellaneous.cs @@ -10,9 +10,9 @@ public CustomScopeForRootTypesAttribute(params Type[] types) } [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] -public class UserDefinedConstrParamsInjectionAttribute : Attribute +public class UserDefinedConstructorParametersInjectionAttribute : Attribute { - public UserDefinedConstrParamsInjectionAttribute(Type type) + public UserDefinedConstructorParametersInjectionAttribute(Type type) { } } diff --git a/Main/Constants.cs b/Main/Constants.cs index 78736605..c3909a8b 100644 --- a/Main/Constants.cs +++ b/Main/Constants.cs @@ -20,7 +20,7 @@ internal static class Constants // User-defined scope elements internal const string UserDefinedFactory = $"{DieAbbreviation}_Factory"; internal const string UserDefinedConstrParams = $"{DieAbbreviation}_ConstrParam"; - internal const string UserDefinedProperties = $"{DieAbbreviation}_Properties"; + internal const string UserDefinedProps = $"{DieAbbreviation}_Props"; internal const string UserDefinedAddForDisposal = $"{DieAbbreviation}_AddForDisposal"; internal const string UserDefinedAddForDisposalAsync = $"{DieAbbreviation}_AddForDisposalAsync"; diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs index 31cc025c..c8ab776f 100644 --- a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs @@ -851,9 +851,9 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup var isTransientScopeRoot = _checkTypeProperties.ShouldBeScopeRoot(implementationType) == ScopeLevel.TransientScope; - var (userDefinedConstrParamsInjection, outConstrParams) = GetUserDefinedInjectionResolution( - _userDefinedElements.GetConstrParamsInjectionFor(implementationType), - (name, parameters) => new UserDefinedConstrParamsInjectionResolution(name, parameters)); + var (userDefinedConstructorParametersInjection, outConstructorsParameters) = GetUserDefinedInjectionResolution( + _userDefinedElements.GetConstructorParametersInjectionFor(implementationType), + (name, parameters) => new UserDefinedConstructorParametersInjectionResolution(name, parameters)); var (userDefinedPropertiesInjection, outProperties) = GetUserDefinedInjectionResolution( _userDefinedElements.GetPropertiesInjectionFor(implementationType), @@ -896,7 +896,7 @@ false when initializationMethod.ReturnType.Equals(_wellKnownTypes.ValueTask, Sym GetDisposalTypeFor(implementationType), new ReadOnlyCollection<(string Name, Resolvable Dependency)>(constructor .Parameters - .Select(p => ProcessConstrParamChildType(p.Type, p.Name, currentParameters)) + .Select(p => ProcessConstructorParametersChildType(p.Type, p.Name, currentParameters)) .ToList()), new ReadOnlyCollection<(string Name, Resolvable Dependency)>( (_checkTypeProperties.GetPropertyChoicesFor(implementationType) @@ -908,17 +908,17 @@ false when initializationMethod.ReturnType.Equals(_wellKnownTypes.ValueTask, Sym .Select(p => ProcessPropertyChildType(p.Type, p.Name, currentParameters)) .ToList()), typeInitializationResolution, - userDefinedConstrParamsInjection, + userDefinedConstructorParametersInjection, userDefinedPropertiesInjection); return (resolution, resolution); - (string Name, Resolvable Dependency) ProcessConstrParamChildType( + (string Name, Resolvable Dependency) ProcessConstructorParametersChildType( ITypeSymbol typeSymbol, string parameterName, ImmutableSortedDictionary currParameter) { - if (outConstrParams.TryGetValue(parameterName, out var outParameterResolution)) + if (outConstructorsParameters.TryGetValue(parameterName, out var outParameterResolution)) return (parameterName, new ParameterResolution(outParameterResolution.Reference, outParameterResolution.TypeFullName)); return ProcessChildType(typeSymbol, parameterName, currParameter); diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index 409a96f6..b9320631 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -111,7 +111,7 @@ internal record ConstructorResolution( IReadOnlyList<(string Name, Resolvable Dependency)> Parameter, IReadOnlyList<(string Name, Resolvable Dependency)> InitializedProperties, ITypeInitializationResolution? Initialization, - UserDefinedConstrParamsInjectionResolution? UserDefinedConstrParamsInjection, + UserDefinedConstructorParametersInjectionResolution? UserDefinedConstructorParametersInjection, UserDefinedPropertiesInjectionResolution? UserDefinedPropertiesInjection) : Resolvable(Reference, TypeFullName), ITaskConsumableResolution; internal record LazyResolution( @@ -174,7 +174,7 @@ internal abstract record UserDefinedInjectionResolution( string FunctionName, IReadOnlyList<(string Name, Resolvable Dependency, bool isOut)> Parameter) : Resolvable("foo", "bar"); -internal record UserDefinedConstrParamsInjectionResolution( +internal record UserDefinedConstructorParametersInjectionResolution( string FunctionName, IReadOnlyList<(string Name, Resolvable Dependency, bool isOut)> Parameter) : UserDefinedInjectionResolution(FunctionName, Parameter); diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index 8edecc8a..f54254ee 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -29,7 +29,7 @@ public void Execute(GeneratorExecutionContext context) var diagLogger = new DiagLogger(errorDescriptionInsteadOfBuildFailure, context); var validateUserDefinedAddForDisposalSync = new ValidateUserDefinedAddForDisposalSync(wellKnownTypes); var validateUserDefinedAddForDisposalAsync = new ValidateUserDefinedAddForDisposalAsync(wellKnownTypes); - var validateUserDefinedConstrParamsInjectionMethod = new ValidateUserDefinedConstrParamsInjectionMethod(wellKnownTypesMiscellaneous); + var validateUserDefinedConstructorParametersInjectionMethod = new ValidateUserDefinedConstructorParametersInjectionMethod(wellKnownTypesMiscellaneous); var validateUserDefinedPropertiesInjectionMethod = new ValidateUserDefinedPropertiesInjectionMethod(wellKnownTypesMiscellaneous); var validateUserDefinedFactoryField = new ValidateUserDefinedFactoryField(); var validateUserDefinedFactoryMethod = new ValidateUserDefinedFactoryMethod(); @@ -37,7 +37,7 @@ public void Execute(GeneratorExecutionContext context) var validateTransientScope = new ValidateTransientScope( validateUserDefinedAddForDisposalSync, validateUserDefinedAddForDisposalAsync, - validateUserDefinedConstrParamsInjectionMethod, + validateUserDefinedConstructorParametersInjectionMethod, validateUserDefinedPropertiesInjectionMethod, validateUserDefinedFactoryMethod, validateUserDefinedFactoryField, @@ -47,7 +47,7 @@ public void Execute(GeneratorExecutionContext context) var validateScope = new ValidateScope( validateUserDefinedAddForDisposalSync, validateUserDefinedAddForDisposalAsync, - validateUserDefinedConstrParamsInjectionMethod, + validateUserDefinedConstructorParametersInjectionMethod, validateUserDefinedPropertiesInjectionMethod, validateUserDefinedFactoryMethod, validateUserDefinedFactoryField, @@ -59,7 +59,7 @@ public void Execute(GeneratorExecutionContext context) validateScope, validateUserDefinedAddForDisposalSync, validateUserDefinedAddForDisposalAsync, - validateUserDefinedConstrParamsInjectionMethod, + validateUserDefinedConstructorParametersInjectionMethod, validateUserDefinedPropertiesInjectionMethod, validateUserDefinedFactoryMethod, validateUserDefinedFactoryField, diff --git a/Main/UserDefinedElements.cs b/Main/UserDefinedElements.cs index 8cd3079a..7f61b88e 100644 --- a/Main/UserDefinedElements.cs +++ b/Main/UserDefinedElements.cs @@ -7,7 +7,7 @@ internal interface IUserDefinedElements IMethodSymbol? GetFactoryMethodFor(ITypeSymbol type); IMethodSymbol? AddForDisposal { get; } IMethodSymbol? AddForDisposalAsync { get; } - IMethodSymbol? GetConstrParamsInjectionFor(INamedTypeSymbol type); + IMethodSymbol? GetConstructorParametersInjectionFor(INamedTypeSymbol type); IMethodSymbol? GetPropertiesInjectionFor(INamedTypeSymbol type); } @@ -18,7 +18,7 @@ internal class EmptyUserDefinedElements : IUserDefinedElements public IMethodSymbol? GetFactoryMethodFor(ITypeSymbol type) => null; public IMethodSymbol? AddForDisposal => null; public IMethodSymbol? AddForDisposalAsync => null; - public IMethodSymbol? GetConstrParamsInjectionFor(INamedTypeSymbol type) => null; + public IMethodSymbol? GetConstructorParametersInjectionFor(INamedTypeSymbol type) => null; public IMethodSymbol? GetPropertiesInjectionFor(INamedTypeSymbol type) => null; } @@ -27,7 +27,7 @@ internal class UserDefinedElements : IUserDefinedElements private readonly IReadOnlyDictionary _typeToField; private readonly IReadOnlyDictionary _typeToProperty; private readonly IReadOnlyDictionary _typeToMethod; - private readonly IReadOnlyDictionary _constrParamsInjectionMethods; + private readonly IReadOnlyDictionary _constructorParametersInjectionMethods; private readonly IReadOnlyDictionary _propertiesInjectionMethods; public UserDefinedElements( @@ -120,9 +120,9 @@ public UserDefinedElements( .OfType() .FirstOrDefault(); - _constrParamsInjectionMethods = GetInjectionMethods(Constants.UserDefinedConstrParams, wellKnownTypesMiscellaneous.UserDefinedConstrParamsInjectionAttribute); + _constructorParametersInjectionMethods = GetInjectionMethods(Constants.UserDefinedConstrParams, wellKnownTypesMiscellaneous.UserDefinedConstructorParametersInjectionAttribute); - _propertiesInjectionMethods = GetInjectionMethods(Constants.UserDefinedProperties, wellKnownTypesMiscellaneous.UserDefinedPropertiesInjectionAttribute); + _propertiesInjectionMethods = GetInjectionMethods(Constants.UserDefinedProps, wellKnownTypesMiscellaneous.UserDefinedPropertiesInjectionAttribute); if (validationErrors.Any()) throw new ValidationDieException(validationErrors.ToImmutableArray()); @@ -188,8 +188,8 @@ public UserDefinedElements( public IMethodSymbol? AddForDisposal { get; } public IMethodSymbol? AddForDisposalAsync { get; } - public IMethodSymbol? GetConstrParamsInjectionFor(INamedTypeSymbol type) => - _constrParamsInjectionMethods.TryGetValue(type, out var ret) ? ret : null; + public IMethodSymbol? GetConstructorParametersInjectionFor(INamedTypeSymbol type) => + _constructorParametersInjectionMethods.TryGetValue(type, out var ret) ? ret : null; public IMethodSymbol? GetPropertiesInjectionFor(INamedTypeSymbol type) => _propertiesInjectionMethods.TryGetValue(type, out var ret) ? ret : null; diff --git a/Main/Validation/Range/UserDefined/ValidateUserDefinedConstrParamsInjectionMethod.cs b/Main/Validation/Range/UserDefined/ValidateUserDefinedConstrParamsInjectionMethod.cs index 22b44abe..3eb26d8c 100644 --- a/Main/Validation/Range/UserDefined/ValidateUserDefinedConstrParamsInjectionMethod.cs +++ b/Main/Validation/Range/UserDefined/ValidateUserDefinedConstrParamsInjectionMethod.cs @@ -1,14 +1,14 @@ namespace MrMeeseeks.DIE.Validation.Range.UserDefined; -internal interface IValidateUserDefinedConstrParamsInjectionMethod : IValidateUserDefinedInjectionMethod +internal interface IValidateUserDefinedConstructorParametersInjectionMethod : IValidateUserDefinedInjectionMethod { } -internal class ValidateUserDefinedConstrParamsInjectionMethod : ValidateUserDefinedInjectionMethod, IValidateUserDefinedConstrParamsInjectionMethod +internal class ValidateUserDefinedConstructorParametersInjectionMethod : ValidateUserDefinedInjectionMethod, IValidateUserDefinedConstructorParametersInjectionMethod { - internal ValidateUserDefinedConstrParamsInjectionMethod(WellKnownTypesMiscellaneous wellKnownTypesMiscellaneous) => - InjectionAttribute = wellKnownTypesMiscellaneous.UserDefinedConstrParamsInjectionAttribute; + internal ValidateUserDefinedConstructorParametersInjectionMethod(WellKnownTypesMiscellaneous wellKnownTypesMiscellaneous) => + InjectionAttribute = wellKnownTypesMiscellaneous.UserDefinedConstructorParametersInjectionAttribute; protected override INamedTypeSymbol InjectionAttribute { get; } } \ No newline at end of file diff --git a/Main/Validation/Range/ValidateContainer.cs b/Main/Validation/Range/ValidateContainer.cs index 7c83a72b..21f54c29 100644 --- a/Main/Validation/Range/ValidateContainer.cs +++ b/Main/Validation/Range/ValidateContainer.cs @@ -19,7 +19,7 @@ internal ValidateContainer( IValidateScope validateScopeFactory, IValidateUserDefinedAddForDisposalSync validateUserDefinedAddForDisposalSync, IValidateUserDefinedAddForDisposalAsync validateUserDefinedAddForDisposalAsync, - IValidateUserDefinedConstrParamsInjectionMethod validateUserDefinedConstrParamsInjectionMethod, + IValidateUserDefinedConstructorParametersInjectionMethod validateUserDefinedConstructorParametersInjectionMethod, IValidateUserDefinedPropertiesMethod validateUserDefinedPropertiesMethod, IValidateUserDefinedFactoryMethod validateUserDefinedFactoryMethod, IValidateUserDefinedFactoryField validateUserDefinedFactoryField, @@ -28,7 +28,7 @@ internal ValidateContainer( : base( validateUserDefinedAddForDisposalSync, validateUserDefinedAddForDisposalAsync, - validateUserDefinedConstrParamsInjectionMethod, + validateUserDefinedConstructorParametersInjectionMethod, validateUserDefinedPropertiesMethod, validateUserDefinedFactoryMethod, validateUserDefinedFactoryField, diff --git a/Main/Validation/Range/ValidateRange.cs b/Main/Validation/Range/ValidateRange.cs index 365e2089..d66b230f 100644 --- a/Main/Validation/Range/ValidateRange.cs +++ b/Main/Validation/Range/ValidateRange.cs @@ -12,7 +12,7 @@ internal abstract class ValidateRange : IValidateRange { private readonly IValidateUserDefinedAddForDisposalSync _validateUserDefinedAddForDisposalSync; private readonly IValidateUserDefinedAddForDisposalAsync _validateUserDefinedAddForDisposalAsync; - private readonly IValidateUserDefinedConstrParamsInjectionMethod _validateUserDefinedConstrParamsInjectionMethod; + private readonly IValidateUserDefinedConstructorParametersInjectionMethod _validateUserDefinedConstructorParametersInjectionMethod; private readonly IValidateUserDefinedPropertiesMethod _validateUserDefinedPropertiesMethod; private readonly IValidateUserDefinedFactoryMethod _validateUserDefinedFactoryMethod; private readonly IValidateUserDefinedFactoryField _validateUserDefinedFactoryField; @@ -22,7 +22,7 @@ internal abstract class ValidateRange : IValidateRange internal ValidateRange( IValidateUserDefinedAddForDisposalSync validateUserDefinedAddForDisposalSync, IValidateUserDefinedAddForDisposalAsync validateUserDefinedAddForDisposalAsync, - IValidateUserDefinedConstrParamsInjectionMethod validateUserDefinedConstrParamsInjectionMethod, + IValidateUserDefinedConstructorParametersInjectionMethod validateUserDefinedConstructorParametersInjectionMethod, IValidateUserDefinedPropertiesMethod validateUserDefinedPropertiesMethod, IValidateUserDefinedFactoryMethod validateUserDefinedFactoryMethod, IValidateUserDefinedFactoryField validateUserDefinedFactoryField, @@ -30,7 +30,7 @@ internal ValidateRange( { _validateUserDefinedAddForDisposalSync = validateUserDefinedAddForDisposalSync; _validateUserDefinedAddForDisposalAsync = validateUserDefinedAddForDisposalAsync; - _validateUserDefinedConstrParamsInjectionMethod = validateUserDefinedConstrParamsInjectionMethod; + _validateUserDefinedConstructorParametersInjectionMethod = validateUserDefinedConstructorParametersInjectionMethod; _validateUserDefinedPropertiesMethod = validateUserDefinedPropertiesMethod; _validateUserDefinedFactoryMethod = validateUserDefinedFactoryMethod; _validateUserDefinedFactoryField = validateUserDefinedFactoryField; @@ -107,9 +107,9 @@ public virtual IEnumerable Validate(INamedTypeSymbol rangeType, INam foreach (var diagnostic in ValidateAddForDisposal(Constants.UserDefinedAddForDisposalAsync, false)) yield return diagnostic; - foreach (var diagnostic in ValidateUserDefinedInjection(Constants.UserDefinedConstrParams, _validateUserDefinedConstrParamsInjectionMethod)) + foreach (var diagnostic in ValidateUserDefinedInjection(Constants.UserDefinedConstrParams, _validateUserDefinedConstructorParametersInjectionMethod)) yield return diagnostic; - foreach (var diagnostic in ValidateUserDefinedInjection(Constants.UserDefinedProperties, _validateUserDefinedPropertiesMethod)) + foreach (var diagnostic in ValidateUserDefinedInjection(Constants.UserDefinedProps, _validateUserDefinedPropertiesMethod)) yield return diagnostic; var userDefinedFactories = rangeType diff --git a/Main/Validation/Range/ValidateScope.cs b/Main/Validation/Range/ValidateScope.cs index 7f3f879f..80197913 100644 --- a/Main/Validation/Range/ValidateScope.cs +++ b/Main/Validation/Range/ValidateScope.cs @@ -11,7 +11,7 @@ internal class ValidateScope : ValidateScopeBase, IValidateScope internal ValidateScope( IValidateUserDefinedAddForDisposalSync validateUserDefinedAddForDisposalSync, IValidateUserDefinedAddForDisposalAsync validateUserDefinedAddForDisposalAsync, - IValidateUserDefinedConstrParamsInjectionMethod validateUserDefinedConstrParamsInjectionMethod, + IValidateUserDefinedConstructorParametersInjectionMethod validateUserDefinedConstructorParametersInjectionMethod, IValidateUserDefinedPropertiesMethod validateUserDefinedPropertiesMethod, IValidateUserDefinedFactoryMethod validateUserDefinedFactoryMethod, IValidateUserDefinedFactoryField validateUserDefinedFactoryField, @@ -21,7 +21,7 @@ internal ValidateScope( : base( validateUserDefinedAddForDisposalSync, validateUserDefinedAddForDisposalAsync, - validateUserDefinedConstrParamsInjectionMethod, + validateUserDefinedConstructorParametersInjectionMethod, validateUserDefinedPropertiesMethod, validateUserDefinedFactoryMethod, validateUserDefinedFactoryField, diff --git a/Main/Validation/Range/ValidateScopeBase.cs b/Main/Validation/Range/ValidateScopeBase.cs index 6ac6ce75..e1d26186 100644 --- a/Main/Validation/Range/ValidateScopeBase.cs +++ b/Main/Validation/Range/ValidateScopeBase.cs @@ -14,7 +14,7 @@ internal abstract class ValidateScopeBase : ValidateRange, IValidateScopeBase internal ValidateScopeBase( IValidateUserDefinedAddForDisposalSync validateUserDefinedAddForDisposalSync, IValidateUserDefinedAddForDisposalAsync validateUserDefinedAddForDisposalAsync, - IValidateUserDefinedConstrParamsInjectionMethod validateUserDefinedConstrParamsInjectionMethod, + IValidateUserDefinedConstructorParametersInjectionMethod validateUserDefinedConstructorParametersInjectionMethod, IValidateUserDefinedPropertiesMethod validateUserDefinedPropertiesMethod, IValidateUserDefinedFactoryMethod validateUserDefinedFactoryMethod, IValidateUserDefinedFactoryField validateUserDefinedFactoryField, @@ -24,7 +24,7 @@ internal ValidateScopeBase( : base( validateUserDefinedAddForDisposalSync, validateUserDefinedAddForDisposalAsync, - validateUserDefinedConstrParamsInjectionMethod, + validateUserDefinedConstructorParametersInjectionMethod, validateUserDefinedPropertiesMethod, validateUserDefinedFactoryMethod, validateUserDefinedFactoryField, diff --git a/Main/Validation/Range/ValidateTransientScope.cs b/Main/Validation/Range/ValidateTransientScope.cs index 74bc630b..b9e21365 100644 --- a/Main/Validation/Range/ValidateTransientScope.cs +++ b/Main/Validation/Range/ValidateTransientScope.cs @@ -11,7 +11,7 @@ internal class ValidateTransientScope : ValidateScopeBase, IValidateTransientSco internal ValidateTransientScope( IValidateUserDefinedAddForDisposalSync validateUserDefinedAddForDisposalSync, IValidateUserDefinedAddForDisposalAsync validateUserDefinedAddForDisposalAsync, - IValidateUserDefinedConstrParamsInjectionMethod validateUserDefinedConstrParamsInjectionMethod, + IValidateUserDefinedConstructorParametersInjectionMethod validateUserDefinedConstructorParametersInjectionMethod, IValidateUserDefinedPropertiesMethod validateUserDefinedPropertiesMethod, IValidateUserDefinedFactoryMethod validateUserDefinedFactoryMethod, IValidateUserDefinedFactoryField validateUserDefinedFactoryField, @@ -21,7 +21,7 @@ internal ValidateTransientScope( : base( validateUserDefinedAddForDisposalSync, validateUserDefinedAddForDisposalAsync, - validateUserDefinedConstrParamsInjectionMethod, + validateUserDefinedConstructorParametersInjectionMethod, validateUserDefinedPropertiesMethod, validateUserDefinedFactoryMethod, validateUserDefinedFactoryField, diff --git a/Main/WellKnownTypesMiscellaneous.cs b/Main/WellKnownTypesMiscellaneous.cs index 279e0183..44814efe 100644 --- a/Main/WellKnownTypesMiscellaneous.cs +++ b/Main/WellKnownTypesMiscellaneous.cs @@ -6,7 +6,7 @@ internal record WellKnownTypesMiscellaneous( INamedTypeSymbol TypeInitializerAttribute, INamedTypeSymbol FilterTypeInitializerAttribute, INamedTypeSymbol CustomScopeForRootTypesAttribute, - INamedTypeSymbol UserDefinedConstrParamsInjectionAttribute, + INamedTypeSymbol UserDefinedConstructorParametersInjectionAttribute, INamedTypeSymbol UserDefinedPropertiesInjectionAttribute, INamedTypeSymbol CreateFunctionAttribute, INamedTypeSymbol ErrorDescriptionInsteadOfBuildFailureAttribute, @@ -17,8 +17,8 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypesMiscel var customScopeForRootTypesAttribute = compilation .GetTypeByMetadataName(typeof(CustomScopeForRootTypesAttribute).FullName ?? ""); - var userDefinedConstrParamsInjectionAttribute = compilation - .GetTypeByMetadataName(typeof(UserDefinedConstrParamsInjectionAttribute).FullName ?? ""); + var userDefinedConstructorParametersInjectionAttribute = compilation + .GetTypeByMetadataName(typeof(UserDefinedConstructorParametersInjectionAttribute).FullName ?? ""); var userDefinedPropertiesInjectionAttribute = compilation .GetTypeByMetadataName(typeof(UserDefinedPropertiesInjectionAttribute).FullName ?? ""); @@ -41,7 +41,7 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypesMiscel if (typeInitializerAttribute is not null && filterTypeInitializerAttribute is not null && customScopeForRootTypesAttribute is not null - && userDefinedConstrParamsInjectionAttribute is not null + && userDefinedConstructorParametersInjectionAttribute is not null && userDefinedPropertiesInjectionAttribute is not null && createFunctionAttribute is not null && errorDescriptionInsteadOfBuildFailureAttribute is not null @@ -52,7 +52,7 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypesMiscel TypeInitializerAttribute: typeInitializerAttribute, FilterTypeInitializerAttribute: filterTypeInitializerAttribute, CustomScopeForRootTypesAttribute: customScopeForRootTypesAttribute, - UserDefinedConstrParamsInjectionAttribute: userDefinedConstrParamsInjectionAttribute, + UserDefinedConstructorParametersInjectionAttribute: userDefinedConstructorParametersInjectionAttribute, UserDefinedPropertiesInjectionAttribute: userDefinedPropertiesInjectionAttribute, CreateFunctionAttribute: createFunctionAttribute, ErrorDescriptionInsteadOfBuildFailureAttribute: errorDescriptionInsteadOfBuildFailureAttribute, diff --git a/Test/CustomEmbedding/FieldInContainercs.cs b/Test/UserDefinedElements/FactoryField/InContainercs.cs similarity index 88% rename from Test/CustomEmbedding/FieldInContainercs.cs rename to Test/UserDefinedElements/FactoryField/InContainercs.cs index c3f8db4d..1078edb7 100644 --- a/Test/CustomEmbedding/FieldInContainercs.cs +++ b/Test/UserDefinedElements/FactoryField/InContainercs.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.CustomEmbedding.FieldInContainer; +namespace MrMeeseeks.DIE.Test.UserDefinedElements.FactoryField.InContainer; internal class Wrapper { diff --git a/Test/CustomEmbedding/FieldInContainercsTask.cs b/Test/UserDefinedElements/FactoryField/InContainercsTask.cs similarity index 89% rename from Test/CustomEmbedding/FieldInContainercsTask.cs rename to Test/UserDefinedElements/FactoryField/InContainercsTask.cs index c3536d83..50a3d607 100644 --- a/Test/CustomEmbedding/FieldInContainercsTask.cs +++ b/Test/UserDefinedElements/FactoryField/InContainercsTask.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.CustomEmbedding.FieldInContainerTask; +namespace MrMeeseeks.DIE.Test.UserDefinedElements.FactoryField.InContainerTask; internal class Wrapper { diff --git a/Test/CustomEmbedding/FieldInContainercsValueTask.cs b/Test/UserDefinedElements/FactoryField/InContainercsValueTask.cs similarity index 88% rename from Test/CustomEmbedding/FieldInContainercsValueTask.cs rename to Test/UserDefinedElements/FactoryField/InContainercsValueTask.cs index 675419d2..4172842c 100644 --- a/Test/CustomEmbedding/FieldInContainercsValueTask.cs +++ b/Test/UserDefinedElements/FactoryField/InContainercsValueTask.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.CustomEmbedding.FieldInContainerValueTask; +namespace MrMeeseeks.DIE.Test.UserDefinedElements.FactoryField.InContainerValueTask; internal class Wrapper { diff --git a/Test/CustomEmbedding/FieldInScope.cs b/Test/UserDefinedElements/FactoryField/InScope.cs similarity index 90% rename from Test/CustomEmbedding/FieldInScope.cs rename to Test/UserDefinedElements/FactoryField/InScope.cs index adef6687..f61e3b27 100644 --- a/Test/CustomEmbedding/FieldInScope.cs +++ b/Test/UserDefinedElements/FactoryField/InScope.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.CustomEmbedding.FieldInScope; +namespace MrMeeseeks.DIE.Test.UserDefinedElements.FactoryField.InScope; internal class ScopeRoot : IScopeRoot { diff --git a/Test/CustomEmbedding/FieldInTransientScope.cs b/Test/UserDefinedElements/FactoryField/InTransientScope.cs similarity index 90% rename from Test/CustomEmbedding/FieldInTransientScope.cs rename to Test/UserDefinedElements/FactoryField/InTransientScope.cs index 52f481c3..171012ea 100644 --- a/Test/CustomEmbedding/FieldInTransientScope.cs +++ b/Test/UserDefinedElements/FactoryField/InTransientScope.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.CustomEmbedding.FieldInTransientScope; +namespace MrMeeseeks.DIE.Test.UserDefinedElements.FactoryField.InTransientScope; internal class TransientScopeRoot : ITransientScopeRoot { diff --git a/Test/CustomEmbedding/FactoryInContainercs.cs b/Test/UserDefinedElements/FactoryMethod/InContainercs.cs similarity index 88% rename from Test/CustomEmbedding/FactoryInContainercs.cs rename to Test/UserDefinedElements/FactoryMethod/InContainercs.cs index 2ccf99cd..775ec8be 100644 --- a/Test/CustomEmbedding/FactoryInContainercs.cs +++ b/Test/UserDefinedElements/FactoryMethod/InContainercs.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.CustomEmbedding.FactoryInContainer; +namespace MrMeeseeks.DIE.Test.UserDefinedElements.FactoryMethod.InContainer; internal class Wrapper { diff --git a/Test/CustomEmbedding/FactoryInContainercsTask.cs b/Test/UserDefinedElements/FactoryMethod/InContainercsTask.cs similarity index 88% rename from Test/CustomEmbedding/FactoryInContainercsTask.cs rename to Test/UserDefinedElements/FactoryMethod/InContainercsTask.cs index a2a6ee03..e02b67a6 100644 --- a/Test/CustomEmbedding/FactoryInContainercsTask.cs +++ b/Test/UserDefinedElements/FactoryMethod/InContainercsTask.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.CustomEmbedding.FactoryInContainerTask; +namespace MrMeeseeks.DIE.Test.UserDefinedElements.FactoryMethod.InContainerTask; internal class Wrapper { diff --git a/Test/CustomEmbedding/FactoryInContainercsValueTask.cs b/Test/UserDefinedElements/FactoryMethod/InContainercsValueTask.cs similarity index 88% rename from Test/CustomEmbedding/FactoryInContainercsValueTask.cs rename to Test/UserDefinedElements/FactoryMethod/InContainercsValueTask.cs index 8a67fcef..16af4cec 100644 --- a/Test/CustomEmbedding/FactoryInContainercsValueTask.cs +++ b/Test/UserDefinedElements/FactoryMethod/InContainercsValueTask.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.CustomEmbedding.FactoryInContainerValueTask; +namespace MrMeeseeks.DIE.Test.UserDefinedElements.FactoryMethod.InContainerValueTask; internal class Wrapper { diff --git a/Test/CustomEmbedding/FactoryInScope.cs b/Test/UserDefinedElements/FactoryMethod/InScope.cs similarity index 90% rename from Test/CustomEmbedding/FactoryInScope.cs rename to Test/UserDefinedElements/FactoryMethod/InScope.cs index 0a46554a..726695be 100644 --- a/Test/CustomEmbedding/FactoryInScope.cs +++ b/Test/UserDefinedElements/FactoryMethod/InScope.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.CustomEmbedding.FactoryInScope; +namespace MrMeeseeks.DIE.Test.UserDefinedElements.FactoryMethod.InScope; internal class ScopeRoot : IScopeRoot { diff --git a/Test/CustomEmbedding/FactoryInTransientScope.cs b/Test/UserDefinedElements/FactoryMethod/InTransientScope.cs similarity index 89% rename from Test/CustomEmbedding/FactoryInTransientScope.cs rename to Test/UserDefinedElements/FactoryMethod/InTransientScope.cs index eaee5bab..0c26a143 100644 --- a/Test/CustomEmbedding/FactoryInTransientScope.cs +++ b/Test/UserDefinedElements/FactoryMethod/InTransientScope.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.CustomEmbedding.FactoryInTransientScope; +namespace MrMeeseeks.DIE.Test.UserDefinedElements.FactoryMethod.InTransientScope; internal class TransientScopeRoot : ITransientScopeRoot { diff --git a/Test/CustomEmbedding/FactoryWithParameterInContainercs.cs b/Test/UserDefinedElements/FactoryMethod/WithParameterInContainercs.cs similarity index 86% rename from Test/CustomEmbedding/FactoryWithParameterInContainercs.cs rename to Test/UserDefinedElements/FactoryMethod/WithParameterInContainercs.cs index bcf8bad0..9f5cb02d 100644 --- a/Test/CustomEmbedding/FactoryWithParameterInContainercs.cs +++ b/Test/UserDefinedElements/FactoryMethod/WithParameterInContainercs.cs @@ -3,7 +3,7 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.CustomEmbedding.FactoryWithParameterInContainer; +namespace MrMeeseeks.DIE.Test.UserDefinedElements.FactoryMethod.WithParameterInContainer; [ImplementationAggregation(typeof(FileInfo))] [CreateFunction(typeof(FileInfo), "Create")] diff --git a/Test/CustomEmbedding/FactoryWithParameterInScope.cs b/Test/UserDefinedElements/FactoryMethod/WithParameterInScope.cs similarity index 90% rename from Test/CustomEmbedding/FactoryWithParameterInScope.cs rename to Test/UserDefinedElements/FactoryMethod/WithParameterInScope.cs index b4e0188d..54b39551 100644 --- a/Test/CustomEmbedding/FactoryWithParameterInScope.cs +++ b/Test/UserDefinedElements/FactoryMethod/WithParameterInScope.cs @@ -3,7 +3,7 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.CustomEmbedding.FactoryWithParameterInScope; +namespace MrMeeseeks.DIE.Test.UserDefinedElements.FactoryMethod.WithParameterInScope; internal class ScopeRoot : IScopeRoot { diff --git a/Test/CustomEmbedding/FactoryWithParameterInTransientScope.cs b/Test/UserDefinedElements/FactoryMethod/WithParameterInTransientScope.cs similarity index 89% rename from Test/CustomEmbedding/FactoryWithParameterInTransientScope.cs rename to Test/UserDefinedElements/FactoryMethod/WithParameterInTransientScope.cs index 5810abf7..a6988e7f 100644 --- a/Test/CustomEmbedding/FactoryWithParameterInTransientScope.cs +++ b/Test/UserDefinedElements/FactoryMethod/WithParameterInTransientScope.cs @@ -3,7 +3,7 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.CustomEmbedding.FactoryWithParameterInTransientScope; +namespace MrMeeseeks.DIE.Test.UserDefinedElements.FactoryMethod.WithParameterInTransientScope; internal class TransientScopeRoot : ITransientScopeRoot { diff --git a/Test/CustomEmbedding/PropertyInContainer.cs b/Test/UserDefinedElements/FactoryProperty/InContainer.cs similarity index 88% rename from Test/CustomEmbedding/PropertyInContainer.cs rename to Test/UserDefinedElements/FactoryProperty/InContainer.cs index de4ece38..1c066a1e 100644 --- a/Test/CustomEmbedding/PropertyInContainer.cs +++ b/Test/UserDefinedElements/FactoryProperty/InContainer.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.CustomEmbedding.PropertyInContainer; +namespace MrMeeseeks.DIE.Test.UserDefinedElements.FactoryProperty.InContainer; internal class Wrapper { diff --git a/Test/CustomEmbedding/PropertyInContainerTask.cs b/Test/UserDefinedElements/FactoryProperty/InContainerTask.cs similarity index 88% rename from Test/CustomEmbedding/PropertyInContainerTask.cs rename to Test/UserDefinedElements/FactoryProperty/InContainerTask.cs index 3aa6e98e..91799a2e 100644 --- a/Test/CustomEmbedding/PropertyInContainerTask.cs +++ b/Test/UserDefinedElements/FactoryProperty/InContainerTask.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.CustomEmbedding.PropertyInContainerTask; +namespace MrMeeseeks.DIE.Test.UserDefinedElements.FactoryProperty.InContainerTask; internal class Wrapper { diff --git a/Test/CustomEmbedding/PropertyInContainerValueTask.cs b/Test/UserDefinedElements/FactoryProperty/InContainerValueTask.cs similarity index 88% rename from Test/CustomEmbedding/PropertyInContainerValueTask.cs rename to Test/UserDefinedElements/FactoryProperty/InContainerValueTask.cs index 2aeb2cf6..6b65aca7 100644 --- a/Test/CustomEmbedding/PropertyInContainerValueTask.cs +++ b/Test/UserDefinedElements/FactoryProperty/InContainerValueTask.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.CustomEmbedding.PropertyInContainerValueTask; +namespace MrMeeseeks.DIE.Test.UserDefinedElements.FactoryProperty.InContainerValueTask; internal class Wrapper { diff --git a/Test/CustomEmbedding/PropertyInScope.cs b/Test/UserDefinedElements/FactoryProperty/InScope.cs similarity index 89% rename from Test/CustomEmbedding/PropertyInScope.cs rename to Test/UserDefinedElements/FactoryProperty/InScope.cs index 24b10f01..bab2c0cd 100644 --- a/Test/CustomEmbedding/PropertyInScope.cs +++ b/Test/UserDefinedElements/FactoryProperty/InScope.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.CustomEmbedding.PropertyInScope; +namespace MrMeeseeks.DIE.Test.UserDefinedElements.FactoryProperty.InScope; internal class ScopeRoot : IScopeRoot { diff --git a/Test/CustomEmbedding/PropertyInTransientScope.cs b/Test/UserDefinedElements/FactoryProperty/InTransientScope.cs similarity index 89% rename from Test/CustomEmbedding/PropertyInTransientScope.cs rename to Test/UserDefinedElements/FactoryProperty/InTransientScope.cs index 3195bd58..25f0c913 100644 --- a/Test/CustomEmbedding/PropertyInTransientScope.cs +++ b/Test/UserDefinedElements/FactoryProperty/InTransientScope.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.CustomEmbedding.PropertyInTransientScope; +namespace MrMeeseeks.DIE.Test.UserDefinedElements.FactoryProperty.InTransientScope; internal class TransientScopeRoot : ITransientScopeRoot { diff --git a/Test/CustomEmbedding/ConstrParam/Vanilla.cs b/Test/UserDefinedElements/InjectionConstrParams/Vanilla.cs similarity index 80% rename from Test/CustomEmbedding/ConstrParam/Vanilla.cs rename to Test/UserDefinedElements/InjectionConstrParams/Vanilla.cs index c2a21610..32776d25 100644 --- a/Test/CustomEmbedding/ConstrParam/Vanilla.cs +++ b/Test/UserDefinedElements/InjectionConstrParams/Vanilla.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.CustomEmbedding.ConstrParam.Vanilla; +namespace MrMeeseeks.DIE.Test.UserDefinedElements.InjectionConstrParams.Vanilla; internal class Dependency { @@ -14,7 +14,7 @@ internal class Dependency [CreateFunction(typeof(Dependency), "Create")] internal sealed partial class Container { - [UserDefinedConstrParamsInjection(typeof(Dependency))] + [UserDefinedConstructorParametersInjection(typeof(Dependency))] private void DIE_ConstrParam_Dependency(out int number) => number = 69; } diff --git a/Test/CustomEmbedding/ConstrParam/VanillaInScope.cs b/Test/UserDefinedElements/InjectionConstrParams/VanillaInScope.cs similarity index 84% rename from Test/CustomEmbedding/ConstrParam/VanillaInScope.cs rename to Test/UserDefinedElements/InjectionConstrParams/VanillaInScope.cs index 04524412..759cb4d0 100644 --- a/Test/CustomEmbedding/ConstrParam/VanillaInScope.cs +++ b/Test/UserDefinedElements/InjectionConstrParams/VanillaInScope.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.CustomEmbedding.ConstrParam.VanillaInScope; +namespace MrMeeseeks.DIE.Test.UserDefinedElements.InjectionConstrParams.VanillaInScope; internal class Dependency { @@ -24,7 +24,7 @@ internal sealed partial class Container { private sealed partial class DIE_DefaultScope { - [UserDefinedConstrParamsInjection(typeof(Dependency))] + [UserDefinedConstructorParametersInjection(typeof(Dependency))] private void DIE_ConstrParam_Dependency(out int number) => number = 69; } } diff --git a/Test/CustomEmbedding/ConstrParam/VanillaInTransientScope.cs b/Test/UserDefinedElements/InjectionConstrParams/VanillaInTransientScope.cs similarity index 83% rename from Test/CustomEmbedding/ConstrParam/VanillaInTransientScope.cs rename to Test/UserDefinedElements/InjectionConstrParams/VanillaInTransientScope.cs index 6aa3601e..e22b8397 100644 --- a/Test/CustomEmbedding/ConstrParam/VanillaInTransientScope.cs +++ b/Test/UserDefinedElements/InjectionConstrParams/VanillaInTransientScope.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.CustomEmbedding.ConstrParam.VanillaInTransientScope; +namespace MrMeeseeks.DIE.Test.UserDefinedElements.InjectionConstrParams.VanillaInTransientScope; internal class Dependency { @@ -24,7 +24,7 @@ internal sealed partial class Container { private sealed partial class DIE_DefaultTransientScope { - [UserDefinedConstrParamsInjection(typeof(Dependency))] + [UserDefinedConstructorParametersInjection(typeof(Dependency))] private void DIE_ConstrParam_Dependency(out int number) => number = 69; } } diff --git a/Test/CustomEmbedding/ConstrParam/WithAsyncDependency.cs b/Test/UserDefinedElements/InjectionConstrParams/WithAsyncDependency.cs similarity index 83% rename from Test/CustomEmbedding/ConstrParam/WithAsyncDependency.cs rename to Test/UserDefinedElements/InjectionConstrParams/WithAsyncDependency.cs index acb46869..e931a774 100644 --- a/Test/CustomEmbedding/ConstrParam/WithAsyncDependency.cs +++ b/Test/UserDefinedElements/InjectionConstrParams/WithAsyncDependency.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.CustomEmbedding.ConstrParam.WithAsyncDependency; +namespace MrMeeseeks.DIE.Test.UserDefinedElements.InjectionConstrParams.WithAsyncDependency; internal class Dependency { @@ -20,7 +20,7 @@ internal class OtherDependency : IValueTaskTypeInitializer [CreateFunction(typeof(Dependency), "Create")] internal sealed partial class Container { - [UserDefinedConstrParamsInjection(typeof(Dependency))] + [UserDefinedConstructorParametersInjection(typeof(Dependency))] private void DIE_ConstrParam_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; } diff --git a/Test/CustomEmbedding/ConstrParam/WithAsyncDependencyInScope.cs b/Test/UserDefinedElements/InjectionConstrParams/WithAsyncDependencyInScope.cs similarity index 86% rename from Test/CustomEmbedding/ConstrParam/WithAsyncDependencyInScope.cs rename to Test/UserDefinedElements/InjectionConstrParams/WithAsyncDependencyInScope.cs index c211383f..a9481ffe 100644 --- a/Test/CustomEmbedding/ConstrParam/WithAsyncDependencyInScope.cs +++ b/Test/UserDefinedElements/InjectionConstrParams/WithAsyncDependencyInScope.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.CustomEmbedding.ConstrParam.WithAsyncDependencyInScope; +namespace MrMeeseeks.DIE.Test.UserDefinedElements.InjectionConstrParams.WithAsyncDependencyInScope; internal class Dependency { @@ -30,7 +30,7 @@ internal sealed partial class Container { private sealed partial class DIE_DefaultScope { - [UserDefinedConstrParamsInjection(typeof(Dependency))] + [UserDefinedConstructorParametersInjection(typeof(Dependency))] private void DIE_ConstrParam_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; } } diff --git a/Test/CustomEmbedding/ConstrParam/WithAsyncDependencyInTransientScope.cs b/Test/UserDefinedElements/InjectionConstrParams/WithAsyncDependencyInTransientScope.cs similarity index 86% rename from Test/CustomEmbedding/ConstrParam/WithAsyncDependencyInTransientScope.cs rename to Test/UserDefinedElements/InjectionConstrParams/WithAsyncDependencyInTransientScope.cs index d8c4fdfb..d6c01b73 100644 --- a/Test/CustomEmbedding/ConstrParam/WithAsyncDependencyInTransientScope.cs +++ b/Test/UserDefinedElements/InjectionConstrParams/WithAsyncDependencyInTransientScope.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.CustomEmbedding.ConstrParam.WithAsyncDependencyInTransientScope; +namespace MrMeeseeks.DIE.Test.UserDefinedElements.InjectionConstrParams.WithAsyncDependencyInTransientScope; internal class Dependency { @@ -30,7 +30,7 @@ internal sealed partial class Container { private sealed partial class DIE_DefaultTransientScope { - [UserDefinedConstrParamsInjection(typeof(Dependency))] + [UserDefinedConstructorParametersInjection(typeof(Dependency))] private void DIE_ConstrParam_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; } } diff --git a/Test/CustomEmbedding/ConstrParam/WithDependency.cs b/Test/UserDefinedElements/InjectionConstrParams/WithDependency.cs similarity index 82% rename from Test/CustomEmbedding/ConstrParam/WithDependency.cs rename to Test/UserDefinedElements/InjectionConstrParams/WithDependency.cs index 345711e8..b02179d3 100644 --- a/Test/CustomEmbedding/ConstrParam/WithDependency.cs +++ b/Test/UserDefinedElements/InjectionConstrParams/WithDependency.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.CustomEmbedding.ConstrParam.WithDependency; +namespace MrMeeseeks.DIE.Test.UserDefinedElements.InjectionConstrParams.WithDependency; internal class Dependency { @@ -19,7 +19,7 @@ internal class OtherDependency [CreateFunction(typeof(Dependency), "Create")] internal sealed partial class Container { - [UserDefinedConstrParamsInjection(typeof(Dependency))] + [UserDefinedConstructorParametersInjection(typeof(Dependency))] private void DIE_ConstrParam_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; } diff --git a/Test/CustomEmbedding/ConstrParam/WithDependencyInScope.cs b/Test/UserDefinedElements/InjectionConstrParams/WithDependencyInScope.cs similarity index 85% rename from Test/CustomEmbedding/ConstrParam/WithDependencyInScope.cs rename to Test/UserDefinedElements/InjectionConstrParams/WithDependencyInScope.cs index 37b07526..02903f73 100644 --- a/Test/CustomEmbedding/ConstrParam/WithDependencyInScope.cs +++ b/Test/UserDefinedElements/InjectionConstrParams/WithDependencyInScope.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.CustomEmbedding.ConstrParam.WithDependencyInScope; +namespace MrMeeseeks.DIE.Test.UserDefinedElements.InjectionConstrParams.WithDependencyInScope; internal class Dependency { @@ -29,7 +29,7 @@ internal sealed partial class Container { private sealed partial class DIE_DefaultScope { - [UserDefinedConstrParamsInjection(typeof(Dependency))] + [UserDefinedConstructorParametersInjection(typeof(Dependency))] private void DIE_ConstrParam_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; } } diff --git a/Test/CustomEmbedding/ConstrParam/WithDependencyInTransientScope.cs b/Test/UserDefinedElements/InjectionConstrParams/WithDependencyInTransientScope.cs similarity index 85% rename from Test/CustomEmbedding/ConstrParam/WithDependencyInTransientScope.cs rename to Test/UserDefinedElements/InjectionConstrParams/WithDependencyInTransientScope.cs index 93c7484d..38db7e81 100644 --- a/Test/CustomEmbedding/ConstrParam/WithDependencyInTransientScope.cs +++ b/Test/UserDefinedElements/InjectionConstrParams/WithDependencyInTransientScope.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.CustomEmbedding.ConstrParam.WithDependencyInTransientScope; +namespace MrMeeseeks.DIE.Test.UserDefinedElements.InjectionConstrParams.WithDependencyInTransientScope; internal class Dependency { @@ -29,7 +29,7 @@ internal sealed partial class Container { private sealed partial class DIE_DefaultTransientScope { - [UserDefinedConstrParamsInjection(typeof(Dependency))] + [UserDefinedConstructorParametersInjection(typeof(Dependency))] private void DIE_ConstrParam_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; } } diff --git a/Test/CustomEmbedding/Properties/Vanilla.cs b/Test/UserDefinedElements/InjectionProps/Vanilla.cs similarity index 78% rename from Test/CustomEmbedding/Properties/Vanilla.cs rename to Test/UserDefinedElements/InjectionProps/Vanilla.cs index 0b81f365..e6d305c8 100644 --- a/Test/CustomEmbedding/Properties/Vanilla.cs +++ b/Test/UserDefinedElements/InjectionProps/Vanilla.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.CustomEmbedding.Properties.Vanilla; +namespace MrMeeseeks.DIE.Test.UserDefinedElements.InjectionProps.Vanilla; internal class Dependency { @@ -13,7 +13,7 @@ internal class Dependency internal sealed partial class Container { [UserDefinedPropertiesInjection(typeof(Dependency))] - private void DIE_Properties_Dependency(out int Number) => Number = 69; + private void DIE_Props_Dependency(out int Number) => Number = 69; } public class Tests diff --git a/Test/CustomEmbedding/Properties/VanillaInScope.cs b/Test/UserDefinedElements/InjectionProps/VanillaInScope.cs similarity index 83% rename from Test/CustomEmbedding/Properties/VanillaInScope.cs rename to Test/UserDefinedElements/InjectionProps/VanillaInScope.cs index eae4a45c..268da8fc 100644 --- a/Test/CustomEmbedding/Properties/VanillaInScope.cs +++ b/Test/UserDefinedElements/InjectionProps/VanillaInScope.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.CustomEmbedding.Properties.VanillaInScope; +namespace MrMeeseeks.DIE.Test.UserDefinedElements.InjectionProps.VanillaInScope; internal class Dependency { @@ -23,7 +23,7 @@ internal sealed partial class Container private sealed partial class DIE_DefaultScope { [UserDefinedPropertiesInjection(typeof(Dependency))] - private void DIE_Properties_Dependency(out int Number) => Number = 69; + private void DIE_Props_Dependency(out int Number) => Number = 69; } } diff --git a/Test/CustomEmbedding/Properties/VanillaInTransientScope.cs b/Test/UserDefinedElements/InjectionProps/VanillaInTransientScope.cs similarity index 83% rename from Test/CustomEmbedding/Properties/VanillaInTransientScope.cs rename to Test/UserDefinedElements/InjectionProps/VanillaInTransientScope.cs index 0abc51e8..0712fc77 100644 --- a/Test/CustomEmbedding/Properties/VanillaInTransientScope.cs +++ b/Test/UserDefinedElements/InjectionProps/VanillaInTransientScope.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.CustomEmbedding.Properties.VanillaInTransientScope; +namespace MrMeeseeks.DIE.Test.UserDefinedElements.InjectionProps.VanillaInTransientScope; internal class Dependency { @@ -23,7 +23,7 @@ internal sealed partial class Container private sealed partial class DIE_DefaultTransientScope { [UserDefinedPropertiesInjection(typeof(Dependency))] - private void DIE_Properties_Dependency(out int Number) => Number = 69; + private void DIE_Props_Dependency(out int Number) => Number = 69; } } diff --git a/Test/CustomEmbedding/Properties/WithAsyncDependency.cs b/Test/UserDefinedElements/InjectionProps/WithAsyncDependency.cs similarity index 77% rename from Test/CustomEmbedding/Properties/WithAsyncDependency.cs rename to Test/UserDefinedElements/InjectionProps/WithAsyncDependency.cs index 4a1f543b..2a774382 100644 --- a/Test/CustomEmbedding/Properties/WithAsyncDependency.cs +++ b/Test/UserDefinedElements/InjectionProps/WithAsyncDependency.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.CustomEmbedding.Properties.WithAsyncDependency; +namespace MrMeeseeks.DIE.Test.UserDefinedElements.InjectionProps.WithAsyncDependency; internal class Dependency { @@ -19,7 +19,7 @@ internal class OtherDependency : IValueTaskTypeInitializer internal sealed partial class Container { [UserDefinedPropertiesInjection(typeof(Dependency))] - private void DIE_Properties_Dependency(OtherDependency otherDependency, out int Number) => Number = otherDependency.Number; + private void DIE_Props_Dependency(OtherDependency otherDependency, out int Number) => Number = otherDependency.Number; } public class Tests diff --git a/Test/CustomEmbedding/Properties/WithAsyncDependencyInScope.cs b/Test/UserDefinedElements/InjectionProps/WithAsyncDependencyInScope.cs similarity index 81% rename from Test/CustomEmbedding/Properties/WithAsyncDependencyInScope.cs rename to Test/UserDefinedElements/InjectionProps/WithAsyncDependencyInScope.cs index 83ceec39..1b849aa7 100644 --- a/Test/CustomEmbedding/Properties/WithAsyncDependencyInScope.cs +++ b/Test/UserDefinedElements/InjectionProps/WithAsyncDependencyInScope.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.CustomEmbedding.Properties.WithAsyncDependencyInScope; +namespace MrMeeseeks.DIE.Test.UserDefinedElements.InjectionProps.WithAsyncDependencyInScope; internal class Dependency { @@ -29,7 +29,7 @@ internal sealed partial class Container private sealed partial class DIE_DefaultScope { [UserDefinedPropertiesInjection(typeof(Dependency))] - private void DIE_Properties_Dependency(OtherDependency otherDependency, out int Number) => Number = otherDependency.Number; + private void DIE_Props_Dependency(OtherDependency otherDependency, out int Number) => Number = otherDependency.Number; } } diff --git a/Test/CustomEmbedding/Properties/WithAsyncDependencyInTransientScope.cs b/Test/UserDefinedElements/InjectionProps/WithAsyncDependencyInTransientScope.cs similarity index 81% rename from Test/CustomEmbedding/Properties/WithAsyncDependencyInTransientScope.cs rename to Test/UserDefinedElements/InjectionProps/WithAsyncDependencyInTransientScope.cs index 52637f99..681c7f90 100644 --- a/Test/CustomEmbedding/Properties/WithAsyncDependencyInTransientScope.cs +++ b/Test/UserDefinedElements/InjectionProps/WithAsyncDependencyInTransientScope.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.CustomEmbedding.Properties.WithAsyncDependencyInTransientScope; +namespace MrMeeseeks.DIE.Test.UserDefinedElements.InjectionProps.WithAsyncDependencyInTransientScope; internal class Dependency { @@ -29,7 +29,7 @@ internal sealed partial class Container private sealed partial class DIE_DefaultTransientScope { [UserDefinedPropertiesInjection(typeof(Dependency))] - private void DIE_Properties_Dependency(OtherDependency otherDependency, out int Number) => Number = otherDependency.Number; + private void DIE_Props_Dependency(OtherDependency otherDependency, out int Number) => Number = otherDependency.Number; } } diff --git a/Test/CustomEmbedding/Properties/WithDependency.cs b/Test/UserDefinedElements/InjectionProps/WithDependency.cs similarity index 74% rename from Test/CustomEmbedding/Properties/WithDependency.cs rename to Test/UserDefinedElements/InjectionProps/WithDependency.cs index cb492c35..16d51d53 100644 --- a/Test/CustomEmbedding/Properties/WithDependency.cs +++ b/Test/UserDefinedElements/InjectionProps/WithDependency.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.CustomEmbedding.Properties.WithDependency; +namespace MrMeeseeks.DIE.Test.UserDefinedElements.InjectionProps.WithDependency; internal class Dependency { @@ -18,7 +18,7 @@ internal class OtherDependency internal sealed partial class Container { [UserDefinedPropertiesInjection(typeof(Dependency))] - private void DIE_Properties_Dependency(OtherDependency otherDependency, out int Number) => Number = otherDependency.Number; + private void DIE_Props_Dependency(OtherDependency otherDependency, out int Number) => Number = otherDependency.Number; } public class Tests diff --git a/Test/CustomEmbedding/Properties/WithDependencyInScope.cs b/Test/UserDefinedElements/InjectionProps/WithDependencyInScope.cs similarity index 79% rename from Test/CustomEmbedding/Properties/WithDependencyInScope.cs rename to Test/UserDefinedElements/InjectionProps/WithDependencyInScope.cs index 935ca1f3..2670745f 100644 --- a/Test/CustomEmbedding/Properties/WithDependencyInScope.cs +++ b/Test/UserDefinedElements/InjectionProps/WithDependencyInScope.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.CustomEmbedding.Properties.WithDependencyInScope; +namespace MrMeeseeks.DIE.Test.UserDefinedElements.InjectionProps.WithDependencyInScope; internal class Dependency { @@ -28,7 +28,7 @@ internal sealed partial class Container private sealed partial class DIE_DefaultScope { [UserDefinedPropertiesInjection(typeof(Dependency))] - private void DIE_Properties_Dependency(OtherDependency otherDependency, out int Number) => Number = otherDependency.Number; + private void DIE_Props_Dependency(OtherDependency otherDependency, out int Number) => Number = otherDependency.Number; } } diff --git a/Test/CustomEmbedding/Properties/WithDependencyInTransientScope.cs b/Test/UserDefinedElements/InjectionProps/WithDependencyInTransientScope.cs similarity index 79% rename from Test/CustomEmbedding/Properties/WithDependencyInTransientScope.cs rename to Test/UserDefinedElements/InjectionProps/WithDependencyInTransientScope.cs index a52ab50d..6ebe4d14 100644 --- a/Test/CustomEmbedding/Properties/WithDependencyInTransientScope.cs +++ b/Test/UserDefinedElements/InjectionProps/WithDependencyInTransientScope.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.CustomEmbedding.Properties.WithDependencyInTransientScope; +namespace MrMeeseeks.DIE.Test.UserDefinedElements.InjectionProps.WithDependencyInTransientScope; internal class Dependency { @@ -28,7 +28,7 @@ internal sealed partial class Container private sealed partial class DIE_DefaultTransientScope { [UserDefinedPropertiesInjection(typeof(Dependency))] - private void DIE_Properties_Dependency(OtherDependency otherDependency, out int Number) => Number = otherDependency.Number; + private void DIE_Props_Dependency(OtherDependency otherDependency, out int Number) => Number = otherDependency.Number; } } From 7425e62898852e11ad7683c856db664a3f552b29 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Thu, 25 Aug 2022 20:14:59 +0200 Subject: [PATCH 127/162] Testing abstraction support --- Test/Abstraction/AbstractClass/Collection.cs | 31 +++++++++++++++++++ .../AbstractClass/CollectionWithoutChoice.cs | 26 ++++++++++++++++ .../AbstractClass/SingleInCollection.cs | 26 ++++++++++++++++ Test/Abstraction/AbstractClass/Vanilla.cs | 26 ++++++++++++++++ .../AbstractClass/VanillaWithoutChoice.cs | 23 ++++++++++++++ .../AbstractClass/WithSingleInCollection.cs | 27 ++++++++++++++++ Test/Abstraction/Interface/Collection.cs | 31 +++++++++++++++++++ .../Interface/CollectionWithoutChoice.cs | 26 ++++++++++++++++ .../Interface/SingleInCollection.cs | 26 ++++++++++++++++ Test/Abstraction/Interface/Vanilla.cs | 26 ++++++++++++++++ .../Interface/VanillaWithoutChoice.cs | 23 ++++++++++++++ .../Interface/WithSingleInCollection.cs | 27 ++++++++++++++++ 12 files changed, 318 insertions(+) create mode 100644 Test/Abstraction/AbstractClass/Collection.cs create mode 100644 Test/Abstraction/AbstractClass/CollectionWithoutChoice.cs create mode 100644 Test/Abstraction/AbstractClass/SingleInCollection.cs create mode 100644 Test/Abstraction/AbstractClass/Vanilla.cs create mode 100644 Test/Abstraction/AbstractClass/VanillaWithoutChoice.cs create mode 100644 Test/Abstraction/AbstractClass/WithSingleInCollection.cs create mode 100644 Test/Abstraction/Interface/Collection.cs create mode 100644 Test/Abstraction/Interface/CollectionWithoutChoice.cs create mode 100644 Test/Abstraction/Interface/SingleInCollection.cs create mode 100644 Test/Abstraction/Interface/Vanilla.cs create mode 100644 Test/Abstraction/Interface/VanillaWithoutChoice.cs create mode 100644 Test/Abstraction/Interface/WithSingleInCollection.cs diff --git a/Test/Abstraction/AbstractClass/Collection.cs b/Test/Abstraction/AbstractClass/Collection.cs new file mode 100644 index 00000000..3f82d250 --- /dev/null +++ b/Test/Abstraction/AbstractClass/Collection.cs @@ -0,0 +1,31 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Abstraction.AbstractClass.Collection; + +internal abstract class Class {} + +internal class SubClassA : Class {} + +internal class SubClassB : Class {} + +internal class SubClassC : Class {} + +[ImplementationCollectionChoice(typeof(Class), typeof(SubClassA), typeof(SubClassB))] +[CreateFunction(typeof(IReadOnlyList), "Create")] +internal sealed partial class Container {} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var instances = container.Create(); + Assert.True(instances.Count == 2); + Assert.True(instances[0].GetType() == typeof(SubClassA) && instances[1].GetType() == typeof(SubClassB) + || instances[0].GetType() == typeof(SubClassB) && instances[1].GetType() == typeof(SubClassA)); + } +} \ No newline at end of file diff --git a/Test/Abstraction/AbstractClass/CollectionWithoutChoice.cs b/Test/Abstraction/AbstractClass/CollectionWithoutChoice.cs new file mode 100644 index 00000000..517ee647 --- /dev/null +++ b/Test/Abstraction/AbstractClass/CollectionWithoutChoice.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Abstraction.AbstractClass.CollectionWithoutChoice; + +internal abstract class Class {} + +internal class SubClassA : Class {} + +internal class SubClassB : Class {} + +[CreateFunction(typeof(IReadOnlyList), "Create")] +internal sealed partial class Container {} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var instances = container.Create(); + Assert.True(instances.Count == 2); + } +} \ No newline at end of file diff --git a/Test/Abstraction/AbstractClass/SingleInCollection.cs b/Test/Abstraction/AbstractClass/SingleInCollection.cs new file mode 100644 index 00000000..714bcb62 --- /dev/null +++ b/Test/Abstraction/AbstractClass/SingleInCollection.cs @@ -0,0 +1,26 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Abstraction.AbstractClass.SingleInCollection; + +internal abstract class Class {} + +internal class SubClassA : Class {} + +internal class SubClassB : Class {} + +[ImplementationCollectionChoice(typeof(Class), typeof(SubClassA))] +[CreateFunction(typeof(Class), "Create")] +internal sealed partial class Container {} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var instance = container.Create(); + Assert.IsType(instance); + } +} \ No newline at end of file diff --git a/Test/Abstraction/AbstractClass/Vanilla.cs b/Test/Abstraction/AbstractClass/Vanilla.cs new file mode 100644 index 00000000..23affc82 --- /dev/null +++ b/Test/Abstraction/AbstractClass/Vanilla.cs @@ -0,0 +1,26 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Abstraction.AbstractClass.Vanilla; + +internal abstract class Class {} + +internal class SubClassA : Class {} + +internal class SubClassB : Class {} + +[ImplementationChoice(typeof(Class), typeof(SubClassA))] +[CreateFunction(typeof(Class), "Create")] +internal sealed partial class Container {} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var instance = container.Create(); + Assert.IsType(instance); + } +} \ No newline at end of file diff --git a/Test/Abstraction/AbstractClass/VanillaWithoutChoice.cs b/Test/Abstraction/AbstractClass/VanillaWithoutChoice.cs new file mode 100644 index 00000000..7a46181c --- /dev/null +++ b/Test/Abstraction/AbstractClass/VanillaWithoutChoice.cs @@ -0,0 +1,23 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Abstraction.AbstractClass.VanillaWithoutChoice; + +internal abstract class Class {} + +internal class SubClass : Class {} + +[CreateFunction(typeof(Class), "Create")] +internal sealed partial class Container {} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var instance = container.Create(); + Assert.IsType(instance); + } +} \ No newline at end of file diff --git a/Test/Abstraction/AbstractClass/WithSingleInCollection.cs b/Test/Abstraction/AbstractClass/WithSingleInCollection.cs new file mode 100644 index 00000000..7a5e2b3f --- /dev/null +++ b/Test/Abstraction/AbstractClass/WithSingleInCollection.cs @@ -0,0 +1,27 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Abstraction.AbstractClass.WithSingleInCollection; + +internal abstract class Class {} + +internal class SubClassA : Class {} + +internal class SubClassB : Class {} + +[ImplementationChoice(typeof(Class), typeof(SubClassA))] +[ImplementationCollectionChoice(typeof(Class), typeof(SubClassB))] +[CreateFunction(typeof(Class), "Create")] +internal sealed partial class Container {} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var instance = container.Create(); + Assert.IsType(instance); + } +} \ No newline at end of file diff --git a/Test/Abstraction/Interface/Collection.cs b/Test/Abstraction/Interface/Collection.cs new file mode 100644 index 00000000..a8213f5c --- /dev/null +++ b/Test/Abstraction/Interface/Collection.cs @@ -0,0 +1,31 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Abstraction.Interface.Collection; + +internal interface IInterface {} + +internal class SubClassA : IInterface {} + +internal class SubClassB : IInterface {} + +internal class SubClassC : IInterface {} + +[ImplementationCollectionChoice(typeof(IInterface), typeof(SubClassA), typeof(SubClassB))] +[CreateFunction(typeof(IReadOnlyList), "Create")] +internal sealed partial class Container {} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var instances = container.Create(); + Assert.True(instances.Count == 2); + Assert.True(instances[0].GetType() == typeof(SubClassA) && instances[1].GetType() == typeof(SubClassB) + || instances[0].GetType() == typeof(SubClassB) && instances[1].GetType() == typeof(SubClassA)); + } +} \ No newline at end of file diff --git a/Test/Abstraction/Interface/CollectionWithoutChoice.cs b/Test/Abstraction/Interface/CollectionWithoutChoice.cs new file mode 100644 index 00000000..a0094dac --- /dev/null +++ b/Test/Abstraction/Interface/CollectionWithoutChoice.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Abstraction.Interface.CollectionWithoutChoice; + +internal interface IInterface {} + +internal class SubClassA : IInterface {} + +internal class SubClassB : IInterface {} + +[CreateFunction(typeof(IReadOnlyList), "Create")] +internal sealed partial class Container {} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var instances = container.Create(); + Assert.True(instances.Count == 2); + } +} \ No newline at end of file diff --git a/Test/Abstraction/Interface/SingleInCollection.cs b/Test/Abstraction/Interface/SingleInCollection.cs new file mode 100644 index 00000000..5c51aa76 --- /dev/null +++ b/Test/Abstraction/Interface/SingleInCollection.cs @@ -0,0 +1,26 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Abstraction.Interface.SingleInCollection; + +internal interface IInterface {} + +internal class SubClassA : IInterface {} + +internal class SubClassB : IInterface {} + +[ImplementationCollectionChoice(typeof(IInterface), typeof(SubClassA))] +[CreateFunction(typeof(IInterface), "Create")] +internal sealed partial class Container {} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var instance = container.Create(); + Assert.IsType(instance); + } +} \ No newline at end of file diff --git a/Test/Abstraction/Interface/Vanilla.cs b/Test/Abstraction/Interface/Vanilla.cs new file mode 100644 index 00000000..c01bd9c8 --- /dev/null +++ b/Test/Abstraction/Interface/Vanilla.cs @@ -0,0 +1,26 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Abstraction.Interface.Vanilla; + +internal interface IInterface {} + +internal class SubClassA : IInterface {} + +internal class SubClassB : IInterface {} + +[ImplementationChoice(typeof(IInterface), typeof(SubClassA))] +[CreateFunction(typeof(IInterface), "Create")] +internal sealed partial class Container {} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var instance = container.Create(); + Assert.IsType(instance); + } +} \ No newline at end of file diff --git a/Test/Abstraction/Interface/VanillaWithoutChoice.cs b/Test/Abstraction/Interface/VanillaWithoutChoice.cs new file mode 100644 index 00000000..a24a6aec --- /dev/null +++ b/Test/Abstraction/Interface/VanillaWithoutChoice.cs @@ -0,0 +1,23 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Abstraction.Interface.VanillaWithoutChoice; + +internal interface IInterface {} + +internal class SubClass : IInterface {} + +[CreateFunction(typeof(IInterface), "Create")] +internal sealed partial class Container {} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var instance = container.Create(); + Assert.IsType(instance); + } +} \ No newline at end of file diff --git a/Test/Abstraction/Interface/WithSingleInCollection.cs b/Test/Abstraction/Interface/WithSingleInCollection.cs new file mode 100644 index 00000000..28a6fd66 --- /dev/null +++ b/Test/Abstraction/Interface/WithSingleInCollection.cs @@ -0,0 +1,27 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Abstraction.Interface.WithSingleInCollection; + +internal interface IInterface {} + +internal class SubClassA : IInterface {} + +internal class SubClassB : IInterface {} + +[ImplementationChoice(typeof(IInterface), typeof(SubClassA))] +[ImplementationCollectionChoice(typeof(IInterface), typeof(SubClassB))] +[CreateFunction(typeof(IInterface), "Create")] +internal sealed partial class Container {} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var instance = container.Create(); + Assert.IsType(instance); + } +} \ No newline at end of file From 7ba83bc484f122e4745a08c40f9276b7fdcb9de4 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Tue, 30 Aug 2022 21:54:03 +0200 Subject: [PATCH 128/162] Fixing factory injections with async wrapped return type --- Main/CodeBuilding/RangeCodeBaseBuilder.cs | 29 ++++-- .../Function/FunctionResolutionBuilder.cs | 97 ++++++++++++++++--- Main/ResolutionTreeItem.cs | 46 ++++++++- Sample/Container.cs | 29 +++--- Test/Async/Wrapped/Lazy.cs | 1 - Test/Func/AsyncWrapped/MultipleTaskAtStart.cs | 39 ++++++++ .../AsyncWrapped/MultipleValueTaskAtStart.cs | 39 ++++++++ Test/Func/AsyncWrapped/SingleTask.cs | 39 ++++++++ Test/Func/AsyncWrapped/SingleValueTask.cs | 39 ++++++++ Test/Lazy/AsyncWrapped/MultipleTaskAtStart.cs | 39 ++++++++ .../AsyncWrapped/MultipleValueTaskAtStart.cs | 39 ++++++++ Test/Lazy/AsyncWrapped/SingleTask.cs | 39 ++++++++ Test/Lazy/AsyncWrapped/SingleValueTask.cs | 39 ++++++++ 13 files changed, 474 insertions(+), 40 deletions(-) create mode 100644 Test/Func/AsyncWrapped/MultipleTaskAtStart.cs create mode 100644 Test/Func/AsyncWrapped/MultipleValueTaskAtStart.cs create mode 100644 Test/Func/AsyncWrapped/SingleTask.cs create mode 100644 Test/Func/AsyncWrapped/SingleValueTask.cs create mode 100644 Test/Lazy/AsyncWrapped/MultipleTaskAtStart.cs create mode 100644 Test/Lazy/AsyncWrapped/MultipleValueTaskAtStart.cs create mode 100644 Test/Lazy/AsyncWrapped/SingleTask.cs create mode 100644 Test/Lazy/AsyncWrapped/SingleValueTask.cs diff --git a/Main/CodeBuilding/RangeCodeBaseBuilder.cs b/Main/CodeBuilding/RangeCodeBaseBuilder.cs index 312a752f..b63debc4 100644 --- a/Main/CodeBuilding/RangeCodeBaseBuilder.cs +++ b/Main/CodeBuilding/RangeCodeBaseBuilder.cs @@ -211,9 +211,12 @@ private StringBuilder GenerateResolutions( { switch (resolution) { - case DeferringResolvable { Resolvable: {} resolvable}: + case DeferringResolvable { Resolvable: { } resolvable }: stringBuilder = GenerateResolutions(stringBuilder, resolvable); break; + case AsyncFactoryCallResolution { Inner: { } inner }: + stringBuilder = GenerateResolutions(stringBuilder, inner); + break; case MultiTaskResolution { SelectedResolvable: {} resolvable}: stringBuilder = GenerateResolutions(stringBuilder, resolvable); break; @@ -228,17 +231,29 @@ private StringBuilder GenerateResolutions( case MultiSynchronicityFunctionCallResolution { SelectedFunctionCall: {} selectedFunctionCall}: stringBuilder = GenerateResolutions(stringBuilder, selectedFunctionCall); break; - case LazyResolution(var reference, var typeFullName, var innerCallOfLambda): - if (innerCallOfLambda.SelectedFunctionCall != innerCallOfLambda.Sync) + case LazyResolution(var reference, var typeFullName, var inner): + if (inner is MultiSynchronicityFunctionCallResolution { LazySynchronicityDecision.Value: not SynchronicityDecision.Sync }) throw new Exception("Lazy resolution has to call sync function"); // todo + var innerResolvable = (Resolvable)inner; + stringBuilder = stringBuilder + .AppendLine($"{typeFullName} {reference} = new {typeFullName}(() =>") + .AppendLine($"{{"); + GenerateResolutions(stringBuilder, innerResolvable); stringBuilder = stringBuilder - .AppendLine($"{typeFullName} {reference} = new {typeFullName}(() => {Constants.ThisKeyword}.{innerCallOfLambda.Sync.FunctionReference}({string.Join(", ", innerCallOfLambda.Sync.Parameters.Select(p => $"{p.Name}: {p.Reference}"))}));"); + .AppendLine($"return {(innerResolvable as AsyncFactoryCallResolution)?.Inner.Reference ?? innerResolvable.Reference};") + .AppendLine($"}});"); break; - case FuncResolution(var reference, var typeFullName, var lambdaParameters, var innerCallOfLambda): - if (innerCallOfLambda.SelectedFunctionCall != innerCallOfLambda.Sync) + case FuncResolution(var reference, var typeFullName, var lambdaParameters, var inner): + if (inner is MultiSynchronicityFunctionCallResolution { LazySynchronicityDecision.Value: not SynchronicityDecision.Sync }) throw new Exception("Func resolution has to call sync function"); // todo + var innerResolvableFunc = (Resolvable)inner; + stringBuilder = stringBuilder + .AppendLine($"{typeFullName} {reference} = ({string.Join(", " ,lambdaParameters.Select(p => p.Reference))}) =>") + .AppendLine($"{{"); + GenerateResolutions(stringBuilder, innerResolvableFunc); stringBuilder = stringBuilder - .AppendLine($"{typeFullName} {reference} = ({string.Join(", " ,lambdaParameters.Select(p => p.Reference))}) => {Constants.ThisKeyword}.{innerCallOfLambda.Sync.FunctionReference}({string.Join(", ", innerCallOfLambda.Sync.Parameters.Select(p => $"{p.Name}: {p.Reference}"))});"); + .AppendLine($"return {(innerResolvableFunc as AsyncFactoryCallResolution)?.Inner.Reference ?? innerResolvableFunc.Reference};") + .AppendLine($"}};"); break; case FunctionCallResolution(var reference, _, _, var functionReference, var functionOwner, var parameters) functionCallResolution: string owner2 = ""; diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs index c8ab776f..b20a8bac 100644 --- a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs @@ -335,18 +335,11 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup new KeyValuePair( cp.Value.Item1.FullName(), cp.Value))); - - var newCreateFunction = _rangeResolutionBaseBuilder.CreateCreateFunctionResolution( - genericType, - currentParameters, - Constants.PrivateKeyword); - + var constructorInjection = new LazyResolution( RootReferenceGenerator.Generate(namedTypeSymbol), namedTypeSymbol.FullName(), - newCreateFunction.BuildFunctionCall( - currentParameters, - Constants.ThisKeyword)); + CreateFactoryResolution(genericType, currentParameters)); return (constructorInjection, null); } @@ -384,18 +377,13 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup nextCurrentParameters = nextCurrentParameters.SetItem(lambdaParameter.Type.FullName(), lambdaParameter); } - - var newCreateFunction = _rangeResolutionBaseBuilder.CreateCreateFunctionResolution( - returnType, - nextCurrentParameters, - Constants.PrivateKeyword); return ( new FuncResolution( RootReferenceGenerator.Generate(type), type.FullName(), lambdaParameters.Select(t => t.Resolution).ToImmutableArray(), - newCreateFunction.BuildFunctionCall(nextCurrentParameters, Constants.ThisKeyword)), + CreateFactoryResolution(returnType, nextCurrentParameters)), null); } @@ -495,6 +483,85 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup new ErrorTreeItem(Diagnostics.CompilationError( ErrorMessage(implementationStack, type, "Couldn't process in resolution tree creation."), _rangeResolutionBaseBuilder.ErrorContext.Location)), null); + + IFactoryResolution CreateFactoryResolution( + INamedTypeSymbol mostOuterInnerType, + ImmutableSortedDictionary currentParameters) + { + var asynchronicityStack = new Stack(); + + var mostInnerType = UnwrapAsynchronicity(mostOuterInnerType, asynchronicityStack); + + var newCreateFunction = _rangeResolutionBaseBuilder.CreateCreateFunctionResolution( + mostInnerType, + currentParameters, + Constants.PrivateKeyword); + + var functionCall = newCreateFunction.BuildFunctionCall( + currentParameters, + Constants.ThisKeyword); + + var currentResolution = (IFactoryResolution)functionCall; + var currentType = mostInnerType; + + if (asynchronicityStack.Any() && asynchronicityStack.Pop() is { } firstAsynchronicity) + { + currentType = firstAsynchronicity switch + { + Function.SynchronicityDecision.AsyncValueTask => _wellKnownTypes.ValueTask1.Construct(currentType), + Function.SynchronicityDecision.AsyncTask => _wellKnownTypes.Task1.Construct(currentType), + _ => throw new Exception("Shouldn't happen") // todo + }; + currentResolution = new AsyncFactoryCallResolution( + RootReferenceGenerator.Generate(currentType), + currentType.FullName(), + functionCall, + firstAsynchronicity); + + while (asynchronicityStack.Any() && asynchronicityStack.Pop() is { } nextAsynchronicity) + { + currentType = nextAsynchronicity switch + { + Function.SynchronicityDecision.AsyncValueTask => _wellKnownTypes.ValueTask1.Construct(currentType), + Function.SynchronicityDecision.AsyncTask => _wellKnownTypes.Task1.Construct(currentType), + _ => throw new Exception("Shouldn't happen") // todo + }; + currentResolution = nextAsynchronicity switch + { + Function.SynchronicityDecision.AsyncValueTask => new ValueTaskFromSyncResolution( + (Resolvable) currentResolution, + RootReferenceGenerator.Generate(currentType), + currentType.FullName()), + Function.SynchronicityDecision.AsyncTask => new TaskFromSyncResolution( + (Resolvable) currentResolution, + RootReferenceGenerator.Generate(currentType), + currentType.FullName()), + _ => throw new Exception("Shouldn't happen") // todo + }; + } + } + + return currentResolution; + + INamedTypeSymbol UnwrapAsynchronicity(INamedTypeSymbol currentWrappedType, Stack stack) + { + if (currentWrappedType.OriginalDefinition.Equals(_wellKnownTypes.ValueTask1, SymbolEqualityComparer.Default) + && currentWrappedType.TypeArguments.FirstOrDefault() is INamedTypeSymbol innerValueTaskType) + { + stack.Push(Function.SynchronicityDecision.AsyncValueTask); + return UnwrapAsynchronicity(innerValueTaskType, stack); + } + + if (currentWrappedType.OriginalDefinition.Equals(_wellKnownTypes.Task1, SymbolEqualityComparer.Default) + && currentWrappedType.TypeArguments.FirstOrDefault() is INamedTypeSymbol innerTaskType) + { + stack.Push(Function.SynchronicityDecision.AsyncTask); + return UnwrapAsynchronicity(innerTaskType, stack); + } + + return currentWrappedType; + } + } } private (Resolvable, ITaskConsumableResolution?) SwitchTask(SwitchTaskParameter parameter) diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index b9320631..3786b34f 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -117,7 +117,7 @@ internal record ConstructorResolution( internal record LazyResolution( string Reference, string TypeFullName, - MultiSynchronicityFunctionCallResolution InnerCallOfLambda) : Resolvable(Reference, TypeFullName); + IFactoryResolution Inner) : Resolvable(Reference, TypeFullName); internal record SyntaxValueTupleResolution( string Reference, @@ -157,7 +157,7 @@ internal record FuncResolution( string Reference, string TypeFullName, IReadOnlyList LambdaParameters, - MultiSynchronicityFunctionCallResolution InnerCallOfLambda) : Resolvable(Reference, TypeFullName); + IFactoryResolution Inner) : Resolvable(Reference, TypeFullName); internal record FactoryResolution( string Reference, @@ -337,7 +337,7 @@ internal record TaskFromValueTaskResolution( internal record TaskFromSyncResolution( Resolvable WrappedResolvable, string TaskReference, - string TaskFullName) : TaskBaseResolution(WrappedResolvable, TaskReference, TaskFullName); + string TaskFullName) : TaskBaseResolution(WrappedResolvable, TaskReference, TaskFullName), IFactoryResolution; internal record ValueTaskFromTaskResolution( Resolvable WrappedResolvable, @@ -352,7 +352,7 @@ internal record ValueTaskFromValueTaskResolution( internal record ValueTaskFromSyncResolution( Resolvable WrappedResolvable, string ValueTaskReference, - string ValueTaskFullName) : TaskBaseResolution(WrappedResolvable, ValueTaskReference, ValueTaskFullName); + string ValueTaskFullName) : TaskBaseResolution(WrappedResolvable, ValueTaskReference, ValueTaskFullName), IFactoryResolution; internal record TaskFromWrappedValueTaskResolution( Resolvable WrappedResolvable, @@ -380,12 +380,48 @@ internal record MultiTaskResolution( }; } +internal interface IFactoryResolution {} + +internal record AsyncFactoryCallResolution( + string Reference, + string TypeFullName, + MultiSynchronicityFunctionCallResolution FunctionCall, + SynchronicityDecision FirstWrapping) : Resolvable(Reference, TypeFullName), IFactoryResolution +{ + + internal Resolvable Inner + { + get + { + FunctionCall.SelectedFunctionCall.Await = false; + switch (FunctionCall.LazySynchronicityDecision.Value, FirstWrapping) + { + case (SynchronicityDecision.Sync, SynchronicityDecision.AsyncValueTask): + return new ValueTaskFromSyncResolution(FunctionCall.SelectedFunctionCall, Reference, TypeFullName); + case (SynchronicityDecision.Sync, SynchronicityDecision.AsyncTask): + return new TaskFromSyncResolution(FunctionCall.SelectedFunctionCall, Reference, TypeFullName); + case (SynchronicityDecision.AsyncTask, SynchronicityDecision.AsyncValueTask): + return new ValueTaskFromWrappedTaskResolution(FunctionCall.SelectedFunctionCall, Reference, TypeFullName); + case (SynchronicityDecision.AsyncTask, SynchronicityDecision.AsyncTask): + return new NewReferenceResolvable(Reference, TypeFullName, FunctionCall.SelectedFunctionCall); + case (SynchronicityDecision.AsyncValueTask, SynchronicityDecision.AsyncValueTask): + return new NewReferenceResolvable(Reference, TypeFullName, FunctionCall.SelectedFunctionCall); + case (SynchronicityDecision.AsyncValueTask, SynchronicityDecision.AsyncTask): + return new TaskFromWrappedValueTaskResolution(FunctionCall.SelectedFunctionCall, Reference, TypeFullName); + default: + throw new ArgumentOutOfRangeException(); // todo + } + } + } +}; + internal record MultiSynchronicityFunctionCallResolution( FunctionCallResolution Sync, FunctionCallResolution AsyncTask, FunctionCallResolution AsyncValueTask, Lazy LazySynchronicityDecision, - FunctionResolutionBuilderHandle FunctionResolutionBuilderHandle) : Resolvable(Sync.Reference, ""), IAwaitableResolution, ITaskConsumableResolution + FunctionResolutionBuilderHandle FunctionResolutionBuilderHandle) + : Resolvable(Sync.Reference, ""), IAwaitableResolution, ITaskConsumableResolution, IFactoryResolution { internal FunctionCallResolution SelectedFunctionCall => LazySynchronicityDecision.Value switch diff --git a/Sample/Container.cs b/Sample/Container.cs index a686f565..c49eb785 100644 --- a/Sample/Container.cs +++ b/Sample/Container.cs @@ -1,23 +1,28 @@ using System; +using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; +using MrMeeseeks.DIE.Sample; -namespace MrMeeseeks.DIE.Test.ValueTuple.NonSyntaxVariantSingleItem; +namespace MrMeeseeks.DIE.Test.Func.AsyncWrapped.SingleValueTask; -internal class Wrapper +internal class Dependency : IValueTaskTypeInitializer { - public Wrapper( - ValueTuple - dependency) => - Dependency = dependency; + public ValueTask InitializeAsync() + { + return ValueTask.CompletedTask; + } +} - public ValueTuple - Dependency { get; } +internal class OuterDependency +{ + internal OuterDependency( + Dependency dependency) + { + + } } -[CreateFunction(typeof(Wrapper), "Create")] +[CreateFunction(typeof(Func>), "Create")] internal sealed partial class Container { - private int _i; - - private int DIE_Counter() => _i++; } \ No newline at end of file diff --git a/Test/Async/Wrapped/Lazy.cs b/Test/Async/Wrapped/Lazy.cs index 216f5536..6558faf7 100644 --- a/Test/Async/Wrapped/Lazy.cs +++ b/Test/Async/Wrapped/Lazy.cs @@ -5,7 +5,6 @@ namespace MrMeeseeks.DIE.Test.Async.Wrapped.Lazy; - internal class Dependency : ITaskTypeInitializer { public bool IsInitialized { get; private set; } diff --git a/Test/Func/AsyncWrapped/MultipleTaskAtStart.cs b/Test/Func/AsyncWrapped/MultipleTaskAtStart.cs new file mode 100644 index 00000000..931c4cac --- /dev/null +++ b/Test/Func/AsyncWrapped/MultipleTaskAtStart.cs @@ -0,0 +1,39 @@ +using System; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Func.AsyncWrapped.MultipleTaskAtStart; + +internal class Dependency : IValueTaskTypeInitializer +{ + public ValueTask InitializeAsync() + { + return ValueTask.CompletedTask; + } +} + +internal class OuterDependency +{ + internal OuterDependency( + Dependency dependency) + { + + } +} + +[CreateFunction(typeof(Func>>>>), "Create")] +internal sealed partial class Container +{ +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var func = container.Create(); + var _ = func(); + } +} diff --git a/Test/Func/AsyncWrapped/MultipleValueTaskAtStart.cs b/Test/Func/AsyncWrapped/MultipleValueTaskAtStart.cs new file mode 100644 index 00000000..cb828495 --- /dev/null +++ b/Test/Func/AsyncWrapped/MultipleValueTaskAtStart.cs @@ -0,0 +1,39 @@ +using System; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Func.AsyncWrapped.MultipleValueTaskAtStart; + +internal class Dependency : IValueTaskTypeInitializer +{ + public ValueTask InitializeAsync() + { + return ValueTask.CompletedTask; + } +} + +internal class OuterDependency +{ + internal OuterDependency( + Dependency dependency) + { + + } +} + +[CreateFunction(typeof(Func>>>>), "Create")] +internal sealed partial class Container +{ +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var func = container.Create(); + var _ = func(); + } +} diff --git a/Test/Func/AsyncWrapped/SingleTask.cs b/Test/Func/AsyncWrapped/SingleTask.cs new file mode 100644 index 00000000..a0140240 --- /dev/null +++ b/Test/Func/AsyncWrapped/SingleTask.cs @@ -0,0 +1,39 @@ +using System; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Func.AsyncWrapped.SingleTask; + +internal class Dependency : IValueTaskTypeInitializer +{ + public ValueTask InitializeAsync() + { + return ValueTask.CompletedTask; + } +} + +internal class OuterDependency +{ + internal OuterDependency( + Dependency dependency) + { + + } +} + +[CreateFunction(typeof(Func>), "Create")] +internal sealed partial class Container +{ +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var func = container.Create(); + var _ = func(); + } +} diff --git a/Test/Func/AsyncWrapped/SingleValueTask.cs b/Test/Func/AsyncWrapped/SingleValueTask.cs new file mode 100644 index 00000000..2d769e57 --- /dev/null +++ b/Test/Func/AsyncWrapped/SingleValueTask.cs @@ -0,0 +1,39 @@ +using System; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Func.AsyncWrapped.SingleValueTask; + +internal class Dependency : IValueTaskTypeInitializer +{ + public ValueTask InitializeAsync() + { + return ValueTask.CompletedTask; + } +} + +internal class OuterDependency +{ + internal OuterDependency( + Dependency dependency) + { + + } +} + +[CreateFunction(typeof(Func>), "Create")] +internal sealed partial class Container +{ +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var func = container.Create(); + var _ = func(); + } +} diff --git a/Test/Lazy/AsyncWrapped/MultipleTaskAtStart.cs b/Test/Lazy/AsyncWrapped/MultipleTaskAtStart.cs new file mode 100644 index 00000000..f7b5507e --- /dev/null +++ b/Test/Lazy/AsyncWrapped/MultipleTaskAtStart.cs @@ -0,0 +1,39 @@ +using System; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Lazy.AsyncWrapped.MultipleTaskAtStart; + +internal class Dependency : IValueTaskTypeInitializer +{ + public ValueTask InitializeAsync() + { + return ValueTask.CompletedTask; + } +} + +internal class OuterDependency +{ + internal OuterDependency( + Dependency dependency) + { + + } +} + +[CreateFunction(typeof(Lazy>>>>), "Create")] +internal sealed partial class Container +{ +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var lazy = container.Create(); + var _ = lazy.Value; + } +} diff --git a/Test/Lazy/AsyncWrapped/MultipleValueTaskAtStart.cs b/Test/Lazy/AsyncWrapped/MultipleValueTaskAtStart.cs new file mode 100644 index 00000000..25a2757c --- /dev/null +++ b/Test/Lazy/AsyncWrapped/MultipleValueTaskAtStart.cs @@ -0,0 +1,39 @@ +using System; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Lazy.AsyncWrapped.MultipleValueTaskAtStart; + +internal class Dependency : IValueTaskTypeInitializer +{ + public ValueTask InitializeAsync() + { + return ValueTask.CompletedTask; + } +} + +internal class OuterDependency +{ + internal OuterDependency( + Dependency dependency) + { + + } +} + +[CreateFunction(typeof(Lazy>>>>), "Create")] +internal sealed partial class Container +{ +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var lazy = container.Create(); + var _ = lazy.Value; + } +} diff --git a/Test/Lazy/AsyncWrapped/SingleTask.cs b/Test/Lazy/AsyncWrapped/SingleTask.cs new file mode 100644 index 00000000..8e044bd2 --- /dev/null +++ b/Test/Lazy/AsyncWrapped/SingleTask.cs @@ -0,0 +1,39 @@ +using System; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Lazy.AsyncWrapped.SingleTask; + +internal class Dependency : IValueTaskTypeInitializer +{ + public ValueTask InitializeAsync() + { + return ValueTask.CompletedTask; + } +} + +internal class OuterDependency +{ + internal OuterDependency( + Dependency dependency) + { + + } +} + +[CreateFunction(typeof(Lazy>), "Create")] +internal sealed partial class Container +{ +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var lazy = container.Create(); + var _ = lazy.Value; + } +} diff --git a/Test/Lazy/AsyncWrapped/SingleValueTask.cs b/Test/Lazy/AsyncWrapped/SingleValueTask.cs new file mode 100644 index 00000000..f1e11c50 --- /dev/null +++ b/Test/Lazy/AsyncWrapped/SingleValueTask.cs @@ -0,0 +1,39 @@ +using System; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Lazy.AsyncWrapped.SingleValueTask; + +internal class Dependency : IValueTaskTypeInitializer +{ + public ValueTask InitializeAsync() + { + return ValueTask.CompletedTask; + } +} + +internal class OuterDependency +{ + internal OuterDependency( + Dependency dependency) + { + + } +} + +[CreateFunction(typeof(Lazy>), "Create")] +internal sealed partial class Container +{ +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var lazy = container.Create(); + var _ = lazy.Value; + } +} From eb352fb721e2779ceeae882888be570b786222d8 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Tue, 30 Aug 2022 23:29:53 +0200 Subject: [PATCH 129/162] Outputting stacktrace on exception --- Main/CodeBuilding/RangeCodeBaseBuilder.cs | 2 +- Main/ContainerDieExceptionGenerator.cs | 7 ++++--- Main/DieException.cs | 1 + Main/ExecuteImpl.cs | 8 +++++++- .../Function/FunctionResolutionBuilder.cs | 4 ++-- 5 files changed, 15 insertions(+), 7 deletions(-) diff --git a/Main/CodeBuilding/RangeCodeBaseBuilder.cs b/Main/CodeBuilding/RangeCodeBaseBuilder.cs index b63debc4..cd44a43d 100644 --- a/Main/CodeBuilding/RangeCodeBaseBuilder.cs +++ b/Main/CodeBuilding/RangeCodeBaseBuilder.cs @@ -455,7 +455,7 @@ private StringBuilder GenerateResolutions( case FieldResolution(var reference, var typeFullName, var fieldName, var isAwait): stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference} = {(isAwait ? "await " : "")}this.{fieldName};"); break; - case FactoryResolution(var reference, var typeFullName, var functionName, var parameters, bool isAwait): + case FactoryResolution(var reference, var typeFullName, var functionName, var parameters, var isAwait): stringBuilder = parameters.Aggregate(stringBuilder, (builder, tuple) => GenerateResolutions(builder, tuple.Dependency ?? throw new Exception())); stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference} = {(isAwait ? "await " : "")}this.{functionName}({string.Join(", ", parameters.Select(t => $"{t.Name}: {t.Dependency.Reference}"))});"); diff --git a/Main/ContainerDieExceptionGenerator.cs b/Main/ContainerDieExceptionGenerator.cs index 35a34f64..479780c8 100644 --- a/Main/ContainerDieExceptionGenerator.cs +++ b/Main/ContainerDieExceptionGenerator.cs @@ -5,7 +5,7 @@ namespace MrMeeseeks.DIE; internal interface IContainerDieExceptionGenerator { - void Generate(string namespaceName, string containerClassName, DieException exception); + void Generate(string namespaceName, string containerClassName, Exception exception); } internal class ContainerDieExceptionGenerator : IContainerDieExceptionGenerator @@ -21,7 +21,7 @@ internal ContainerDieExceptionGenerator( _wellKnownTypesMiscellaneous = wellKnownTypesMiscellaneous; } - public void Generate(string namespaceName, string containerClassName, DieException exception) + public void Generate(string namespaceName, string containerClassName, Exception exception) { var generatedContainer = new StringBuilder() .AppendLine($"#nullable enable") @@ -29,7 +29,8 @@ public void Generate(string namespaceName, string containerClassName, DieExcepti .AppendLine($"{{") .AppendLine($"partial class {containerClassName}") .AppendLine($"{{") - .AppendLine($"public {_wellKnownTypesMiscellaneous.DieExceptionKind.FullName()} ExceptionKind_0_0 => {_wellKnownTypesMiscellaneous.DieExceptionKind.FullName()}.{exception.Kind.ToString()};") + .AppendLine($"public {_wellKnownTypesMiscellaneous.DieExceptionKind.FullName()} ExceptionKind_0_0 => {_wellKnownTypesMiscellaneous.DieExceptionKind.FullName()}.{((exception as DieException)?.Kind ?? DieExceptionKind.NoneDIE).ToString()};") + .AppendLine($"public string ExceptionToString_0_1 => @\"{exception}\";") .AppendLine($"}}") .AppendLine($"}}") .AppendLine($"#nullable disable"); diff --git a/Main/DieException.cs b/Main/DieException.cs index 3d1e9804..4ed3281b 100644 --- a/Main/DieException.cs +++ b/Main/DieException.cs @@ -2,6 +2,7 @@ namespace MrMeeseeks.DIE; public enum DieExceptionKind { + NoneDIE, ImplementationCycle, FunctionCycle, Validation, diff --git a/Main/ExecuteImpl.cs b/Main/ExecuteImpl.cs index 82c4fb6e..63be8c83 100644 --- a/Main/ExecuteImpl.cs +++ b/Main/ExecuteImpl.cs @@ -97,7 +97,13 @@ public void Execute() } catch (Exception exception) { - _diagLogger.Log(Diagnostics.UnexpectedException(exception)); + if (_errorDescriptionInsteadOfBuildFailure) + _containerDieExceptionGenerator.Generate( + containerSymbol.ContainingNamespace.FullName(), + containerSymbol.Name, + exception); + else + _diagLogger.Log(Diagnostics.UnexpectedException(exception)); } } } diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs index b20a8bac..e015c760 100644 --- a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs @@ -504,7 +504,7 @@ IFactoryResolution CreateFactoryResolution( var currentResolution = (IFactoryResolution)functionCall; var currentType = mostInnerType; - if (asynchronicityStack.Any() && asynchronicityStack.Pop() is { } firstAsynchronicity) + if (asynchronicityStack.Any() && asynchronicityStack.Pop() is var firstAsynchronicity) { currentType = firstAsynchronicity switch { @@ -518,7 +518,7 @@ IFactoryResolution CreateFactoryResolution( functionCall, firstAsynchronicity); - while (asynchronicityStack.Any() && asynchronicityStack.Pop() is { } nextAsynchronicity) + while (asynchronicityStack.Any() && asynchronicityStack.Pop() is var nextAsynchronicity) { currentType = nextAsynchronicity switch { From 6e89f45e3657ba8eb3ede05061a6d61e25a89fb3 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sun, 4 Sep 2022 17:50:38 +0200 Subject: [PATCH 130/162] Fixing IndexOutOfRangeException with empty names --- Main/ReferenceGenerator.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Main/ReferenceGenerator.cs b/Main/ReferenceGenerator.cs index 98757b46..e99a1c73 100644 --- a/Main/ReferenceGenerator.cs +++ b/Main/ReferenceGenerator.cs @@ -16,8 +16,13 @@ internal class ReferenceGenerator : IReferenceGenerator internal ReferenceGenerator(int j) => _j = j; public string Generate(ITypeSymbol type) => - GenerateInner(string.Empty, $"{char.ToLower(type.Name[0])}{type.Name.Substring(1)}", string.Empty); - + GenerateInner( + string.Empty, + type.Name is { Length: > 1 } + ? $"{char.ToLower(type.Name[0])}{type.Name.Substring(1)}" + : "empty", + string.Empty); + public string Generate(string prefix, ITypeSymbol type) => GenerateInner(prefix, type.Name, string.Empty); From 0b6177e20ba8bc49833728575caaf887577db227 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Mon, 5 Sep 2022 21:56:34 +0200 Subject: [PATCH 131/162] Allow parameters for initializers And also user-defined initializer parameter injection --- Main/CodeBuilding/RangeCodeBaseBuilder.cs | 23 ++++--- .../Configuration/Attributes/Miscellaneous.cs | 16 +++-- .../Configuration/CurrentlyConsideredTypes.cs | 8 +-- Main/Configuration/TypesFromAttributes.cs | 26 +++----- Main/Constants.cs | 3 +- Main/Properties/launchSettings.json | 4 ++ Main/ReferenceGenerator.cs | 2 +- .../Function/FunctionResolutionBuilder.cs | 66 ++++++++++++++----- Main/ResolutionTreeItem.cs | 46 +++++++++---- Main/SourceGenerator.cs | 4 ++ Main/UserDefinedElements.cs | 8 +++ ...edConstructorParametersInjectionMethod.cs} | 0 ...nedInitializerParametersInjectionMethod.cs | 14 ++++ Main/Validation/Range/ValidateContainer.cs | 2 + Main/Validation/Range/ValidateRange.cs | 5 ++ Main/Validation/Range/ValidateScope.cs | 2 + Main/Validation/Range/ValidateScopeBase.cs | 2 + .../Range/ValidateTransientScope.cs | 2 + Main/WellKnownTypesMiscellaneous.cs | 22 ++++--- Sample/Container.cs | 33 +++++----- Sample/MarkerInterfaces.cs | 12 ++-- Test/AssemblyInfo.cs | 6 +- .../Async/Awaited/AsyncScopeRootCallAsTask.cs | 4 +- .../Awaited/AsyncScopeRootCallAsValueTask.cs | 4 +- .../Awaited/AsyncScopeRootCallAwaited.cs | 4 +- .../ContainerInstanceFunctionAsTask.cs | 4 +- .../ContainerInstanceFunctionAsValueTask.cs | 4 +- .../Awaited/ScopeInstanceFunctionAsTask.cs | 4 +- .../ScopeInstanceFunctionAsValueTask.cs | 4 +- Test/Async/Awaited/TaskTypeInitializerTask.cs | 6 +- .../Awaited/TaskTypeInitializerValueTask.cs | 6 +- .../TransientScopeInstanceFunctionAsTask.cs | 4 +- ...ansientScopeInstanceFunctionAsValueTask.cs | 4 +- ...InstanceFunction_DifferentSynchronicity.cs | 4 +- .../ContainerInstanceFunctionAsTask.cs | 4 +- .../ContainerInstanceFunctionAsValueTask.cs | 4 +- Test/Async/Wrapped/DecorationChaining.cs | 12 ++-- Test/Async/Wrapped/Func.cs | 4 +- Test/Async/Wrapped/Lazy.cs | 4 +- .../Wrapped/ScopeInstanceFunctionAsTask.cs | 4 +- .../ScopeInstanceFunctionAsValueTask.cs | 4 +- Test/Async/Wrapped/SyncToTask.cs | 4 +- Test/Async/Wrapped/SyncToValueTask.cs | 4 +- Test/Async/Wrapped/TaskCollection.cs | 12 ++-- Test/Async/Wrapped/TaskComposition.cs | 14 ++-- Test/Async/Wrapped/TaskToTask.cs | 4 +- Test/Async/Wrapped/TaskToValueTask.cs | 4 +- .../TransientScopeInstanceFunctionAsTask.cs | 4 +- ...ceFunctionAsTask_DifferentSynchronicity.cs | 4 +- ...ansientScopeInstanceFunctionAsValueTask.cs | 4 +- ...ctionAsValueTask_DifferentSynchronicity.cs | 4 +- Test/Async/Wrapped/ValueTaskCollection.cs | 12 ++-- Test/Async/Wrapped/ValueTaskComposition.cs | 14 ++-- Test/Async/Wrapped/ValueTaskToTask.cs | 4 +- Test/Async/Wrapped/ValueTaskToValueTask.cs | 4 +- Test/Func/AsyncWrapped/MultipleTaskAtStart.cs | 2 +- .../AsyncWrapped/MultipleValueTaskAtStart.cs | 2 +- Test/Func/AsyncWrapped/SingleTask.cs | 2 +- Test/Func/AsyncWrapped/SingleValueTask.cs | 2 +- .../InitializerImplementationAsync.cs | 2 +- .../InitializerImplementationAsyncValue.cs | 2 +- .../InitializerImplementationSync.cs | 2 +- .../InitializerInterfaceAsync.cs | 4 +- .../InitializerInterfaceAsyncValue.cs | 4 +- .../Configuration/InitializerInterfaceSync.cs | 4 +- .../AsyncTask.cs | 6 +- .../AsyncValueTask.cs | 6 +- Test/{TypeInitializer => Initializer}/Sync.cs | 6 +- Test/Initializer/WithParameters.cs | 42 ++++++++++++ Test/Lazy/AsyncWrapped/MultipleTaskAtStart.cs | 2 +- .../AsyncWrapped/MultipleValueTaskAtStart.cs | 2 +- Test/Lazy/AsyncWrapped/SingleTask.cs | 2 +- Test/Lazy/AsyncWrapped/SingleValueTask.cs | 2 +- Test/MarkerInterfaces.cs | 6 +- .../InjectionConstrParams/Vanilla.cs | 2 +- .../InjectionConstrParams/VanillaInScope.cs | 2 +- .../VanillaInTransientScope.cs | 2 +- .../WithAsyncDependency.cs | 4 +- .../WithAsyncDependencyInScope.cs | 4 +- .../WithAsyncDependencyInTransientScope.cs | 4 +- .../InjectionConstrParams/WithDependency.cs | 2 +- .../WithDependencyInScope.cs | 2 +- .../WithDependencyInTransientScope.cs | 2 +- .../InjectionInitParams/Vanilla.cs | 31 +++++++++ .../InjectionInitParams/VanillaInScope.cs | 42 ++++++++++++ .../VanillaInTransientScope.cs | 42 ++++++++++++ .../WithAsyncDependency.cs | 37 +++++++++++ .../WithAsyncDependencyInScope.cs | 48 ++++++++++++++ .../WithAsyncDependencyInTransientScope.cs | 48 ++++++++++++++ .../InjectionInitParams/WithDependency.cs | 36 ++++++++++ .../WithDependencyInScope.cs | 47 +++++++++++++ .../WithDependencyInTransientScope.cs | 47 +++++++++++++ .../InjectionProps/WithAsyncDependency.cs | 2 +- .../WithAsyncDependencyInScope.cs | 2 +- .../WithAsyncDependencyInTransientScope.cs | 2 +- 95 files changed, 759 insertions(+), 235 deletions(-) rename Main/Validation/Range/UserDefined/{ValidateUserDefinedConstrParamsInjectionMethod.cs => ValidateUserDefinedConstructorParametersInjectionMethod.cs} (100%) create mode 100644 Main/Validation/Range/UserDefined/ValidateUserDefinedInitializerParametersInjectionMethod.cs rename Test/{TypeInitializer => Initializer}/AsyncTask.cs (78%) rename Test/{TypeInitializer => Initializer}/AsyncValueTask.cs (77%) rename Test/{TypeInitializer => Initializer}/Sync.cs (74%) create mode 100644 Test/Initializer/WithParameters.cs create mode 100644 Test/UserDefinedElements/InjectionInitParams/Vanilla.cs create mode 100644 Test/UserDefinedElements/InjectionInitParams/VanillaInScope.cs create mode 100644 Test/UserDefinedElements/InjectionInitParams/VanillaInTransientScope.cs create mode 100644 Test/UserDefinedElements/InjectionInitParams/WithAsyncDependency.cs create mode 100644 Test/UserDefinedElements/InjectionInitParams/WithAsyncDependencyInScope.cs create mode 100644 Test/UserDefinedElements/InjectionInitParams/WithAsyncDependencyInTransientScope.cs create mode 100644 Test/UserDefinedElements/InjectionInitParams/WithDependency.cs create mode 100644 Test/UserDefinedElements/InjectionInitParams/WithDependencyInScope.cs create mode 100644 Test/UserDefinedElements/InjectionInitParams/WithDependencyInTransientScope.cs diff --git a/Main/CodeBuilding/RangeCodeBaseBuilder.cs b/Main/CodeBuilding/RangeCodeBaseBuilder.cs index cd44a43d..daa51fe7 100644 --- a/Main/CodeBuilding/RangeCodeBaseBuilder.cs +++ b/Main/CodeBuilding/RangeCodeBaseBuilder.cs @@ -429,16 +429,23 @@ private StringBuilder GenerateResolutions( stringBuilder = stringBuilder.AppendLine($"{disposableCollectionReference}.Add(({interfaceType}) {reference});"); } - if (initialization is {} init) + if (initialization is { Parameters: {} initParameters }) { - stringBuilder = init switch + if (initialization.UserDefinedInitializerParametersInjectionResolution is {} userDefinedInitializerParametersInjection) + GenerateResolutions(stringBuilder, userDefinedInitializerParametersInjection); + stringBuilder = initParameters.Aggregate(stringBuilder, + (builder, tuple) => GenerateResolutions(builder, tuple.Dependency)); + var initializerParameters = + string.Join(", ", initParameters.Select(d => $"{d.Name}: {d.Dependency.Reference}")); + + stringBuilder = initialization switch { - SyncTypeInitializationResolution (var initInterfaceTypeName, var initMethodName) => - stringBuilder.AppendLine($"(({initInterfaceTypeName}) {reference}).{initMethodName}();"), - TaskBaseTypeInitializationResolution { Await: true, TypeFullName: {} initInterfaceTypeName, MethodName: {} initMethodName} => - stringBuilder.AppendLine($"await (({initInterfaceTypeName}) {reference}).{initMethodName}();"), - TaskBaseTypeInitializationResolution { Await: false, TypeFullName: {} initInterfaceTypeName, MethodName: {} initMethodName, TaskReference: {} taskReference} taskInit => - stringBuilder.AppendLine($"{taskInit.TaskTypeFullName} {taskReference} = (({initInterfaceTypeName}) {reference}).{initMethodName}();"), + SyncInitializationResolution (var initInterfaceTypeName, var initMethodName, _, _) => + stringBuilder.AppendLine($"(({initInterfaceTypeName}) {reference}).{initMethodName}({initializerParameters});"), + TaskBaseInitializationResolution { Await: true, TypeFullName: {} initInterfaceTypeName, MethodName: {} initMethodName} => + stringBuilder.AppendLine($"await (({initInterfaceTypeName}) {reference}).{initMethodName}({initializerParameters});"), + TaskBaseInitializationResolution { Await: false, TypeFullName: {} initInterfaceTypeName, MethodName: {} initMethodName, TaskReference: {} taskReference} taskInit => + stringBuilder.AppendLine($"{taskInit.TaskTypeFullName} {taskReference} = (({initInterfaceTypeName}) {reference}).{initMethodName}({initializerParameters});"), _ => stringBuilder }; } diff --git a/Main/Configuration/Attributes/Miscellaneous.cs b/Main/Configuration/Attributes/Miscellaneous.cs index e09fc4bc..5b952c4b 100644 --- a/Main/Configuration/Attributes/Miscellaneous.cs +++ b/Main/Configuration/Attributes/Miscellaneous.cs @@ -25,18 +25,26 @@ public UserDefinedPropertiesInjectionAttribute(Type type) } } +[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] +public class UserDefinedInitializerParametersInjectionAttribute : Attribute +{ + public UserDefinedInitializerParametersInjectionAttribute(Type type) + { + } +} + [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] -public class TypeInitializerAttribute : Attribute +public class InitializerAttribute : Attribute { - public TypeInitializerAttribute(Type type, string methodName) + public InitializerAttribute(Type type, string methodName) { } } [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] -public class FilterTypeInitializerAttribute : Attribute +public class FilterInitializerAttribute : Attribute { - public FilterTypeInitializerAttribute(Type type) + public FilterInitializerAttribute(Type type) { } } diff --git a/Main/Configuration/CurrentlyConsideredTypes.cs b/Main/Configuration/CurrentlyConsideredTypes.cs index aae86a50..75c8bb11 100644 --- a/Main/Configuration/CurrentlyConsideredTypes.cs +++ b/Main/Configuration/CurrentlyConsideredTypes.cs @@ -329,7 +329,7 @@ public CurrentlyConsideredTypes( foreach (var types in typesFromAttributes) { var filterInterfaceTypes = types - .FilterTypeInitializers + .FilterInitializers .Where(t => t is { TypeKind: TypeKind.Interface} or { TypeKind: not TypeKind.Interface, IsAbstract: true}); foreach (var interfaceType in filterInterfaceTypes) @@ -338,7 +338,7 @@ public CurrentlyConsideredTypes( initializers.Remove(concreteType.UnboundIfGeneric()); var filterConcreteTypes = types - .FilterTypeInitializers + .FilterInitializers .Where(t => t is { TypeKind: TypeKind.Class or TypeKind.Struct, IsAbstract: false }) .ToList(); @@ -346,7 +346,7 @@ public CurrentlyConsideredTypes( initializers.Remove(filterConcreteType.UnboundIfGeneric()); var interfaceTypes = types - .TypeInitializers + .Initializers .Where(t => t.Item1 is { TypeKind: TypeKind.Interface} or { TypeKind: not TypeKind.Interface, IsAbstract: true}) .ToList(); @@ -356,7 +356,7 @@ public CurrentlyConsideredTypes( initializers[concreteType.UnboundIfGeneric()] = (tuple.Item1.UnboundIfGeneric(), tuple.Item2); var concreteTypes = types - .TypeInitializers + .Initializers .Where(t => t.Item1 is { TypeKind: TypeKind.Class or TypeKind.Struct, IsAbstract: false }) .ToList(); diff --git a/Main/Configuration/TypesFromAttributes.cs b/Main/Configuration/TypesFromAttributes.cs index a11b3072..1ea1ae0a 100644 --- a/Main/Configuration/TypesFromAttributes.cs +++ b/Main/Configuration/TypesFromAttributes.cs @@ -26,7 +26,7 @@ internal interface ITypesFromAttributes IImmutableSet ScopeRootImplementation { get; } IImmutableSet<(INamedTypeSymbol, INamedTypeSymbol, IReadOnlyList)> DecoratorSequenceChoices { get; } IImmutableSet<(INamedTypeSymbol, IMethodSymbol)> ConstructorChoices { get; } - IImmutableSet<(INamedTypeSymbol, IMethodSymbol)> TypeInitializers { get; } + IImmutableSet<(INamedTypeSymbol, IMethodSymbol)> Initializers { get; } IImmutableSet<(INamedTypeSymbol, ITypeParameterSymbol, IReadOnlyList)> GenericParameterSubstitutesChoices { get; } IImmutableSet<(INamedTypeSymbol, ITypeParameterSymbol, INamedTypeSymbol)> GenericParameterChoices { get; } IImmutableSet<(INamedTypeSymbol, IReadOnlyList)> PropertyChoices { get; } @@ -55,7 +55,7 @@ internal interface ITypesFromAttributes IImmutableSet FilterScopeRootImplementation { get; } IImmutableSet<(INamedTypeSymbol, INamedTypeSymbol)> FilterDecoratorSequenceChoices { get; } IImmutableSet FilterConstructorChoices { get; } - IImmutableSet FilterTypeInitializers { get; } + IImmutableSet FilterInitializers { get; } IImmutableSet<(INamedTypeSymbol, ITypeParameterSymbol)> FilterGenericParameterSubstitutesChoices { get; } IImmutableSet<(INamedTypeSymbol, ITypeParameterSymbol)> FilterGenericParameterChoices { get; } IImmutableSet FilterPropertyChoices { get; } @@ -410,8 +410,8 @@ void NotParsableAttribute(AttributeData attributeData) => .Select(SingleTypeArgument) .OfType()); - TypeInitializers = ImmutableHashSet.CreateRange( - (AttributeDictionary.TryGetValue(wellKnownTypesMiscellaneous.TypeInitializerAttribute, out var typeInitializerAttributes) + Initializers = ImmutableHashSet.CreateRange( + (AttributeDictionary.TryGetValue(wellKnownTypesMiscellaneous.InitializerAttribute, out var typeInitializerAttributes) ? typeInitializerAttributes : Enumerable.Empty()) .Select(ad => @@ -432,14 +432,6 @@ void NotParsableAttribute(AttributeData attributeData) => if (initializationMethod is { }) { - if (initializationMethod.Parameters.Any()) - { - _errors.Add(Diagnostics.ValidationConfigurationAttribute( - ad, - _rangeType, - _containerType, - $"If method \"{methodName}\" on \"{type.FullName()}\" is to be used as initialize method, then it isn't allowed to have parameters.")); - } if (!initializationMethod.ReturnsVoid && !SymbolEqualityComparer.Default.Equals(initializationMethod.ReturnType, wellKnownTypes.ValueTask) && !SymbolEqualityComparer.Default.Equals(initializationMethod.ReturnType, wellKnownTypes.Task)) @@ -464,10 +456,10 @@ void NotParsableAttribute(AttributeData attributeData) => }) .OfType<(INamedTypeSymbol, IMethodSymbol)>()); - FilterTypeInitializers = ImmutableHashSet.CreateRange( + FilterInitializers = ImmutableHashSet.CreateRange( SymbolEqualityComparer.Default, - (AttributeDictionary.TryGetValue(wellKnownTypesMiscellaneous.FilterTypeInitializerAttribute, out var filterTypeInitializerAttributes) - ? filterTypeInitializerAttributes + (AttributeDictionary.TryGetValue(wellKnownTypesMiscellaneous.FilterInitializerAttribute, out var filterInitializerAttributes) + ? filterInitializerAttributes : Enumerable.Empty()) .Select(SingleTypeArgument) .OfType()); @@ -874,7 +866,7 @@ protected IImmutableSet GetImplementationTypesFromAttribute( public IImmutableSet ScopeRootImplementation { get; protected init; } public IImmutableSet<(INamedTypeSymbol, INamedTypeSymbol, IReadOnlyList)> DecoratorSequenceChoices { get; } public IImmutableSet<(INamedTypeSymbol, IMethodSymbol)> ConstructorChoices { get; } - public IImmutableSet<(INamedTypeSymbol, IMethodSymbol)> TypeInitializers { get; } + public IImmutableSet<(INamedTypeSymbol, IMethodSymbol)> Initializers { get; } public IImmutableSet<(INamedTypeSymbol, ITypeParameterSymbol, IReadOnlyList)> GenericParameterSubstitutesChoices { get; } public IImmutableSet<(INamedTypeSymbol, ITypeParameterSymbol, INamedTypeSymbol)> GenericParameterChoices { get; } public IImmutableSet<(INamedTypeSymbol, IReadOnlyList)> PropertyChoices { get; } @@ -903,7 +895,7 @@ protected IImmutableSet GetImplementationTypesFromAttribute( public IImmutableSet FilterScopeRootImplementation { get; protected init; } public IImmutableSet<(INamedTypeSymbol, INamedTypeSymbol)> FilterDecoratorSequenceChoices { get; } public IImmutableSet FilterConstructorChoices { get; } - public IImmutableSet FilterTypeInitializers { get; } + public IImmutableSet FilterInitializers { get; } public IImmutableSet<(INamedTypeSymbol, ITypeParameterSymbol)> FilterGenericParameterSubstitutesChoices { get; } public IImmutableSet<(INamedTypeSymbol, ITypeParameterSymbol)> FilterGenericParameterChoices { get; } public IImmutableSet FilterPropertyChoices { get; } diff --git a/Main/Constants.cs b/Main/Constants.cs index c3909a8b..fa1f198f 100644 --- a/Main/Constants.cs +++ b/Main/Constants.cs @@ -19,8 +19,9 @@ internal static class Constants // User-defined scope elements internal const string UserDefinedFactory = $"{DieAbbreviation}_Factory"; - internal const string UserDefinedConstrParams = $"{DieAbbreviation}_ConstrParam"; + internal const string UserDefinedConstrParams = $"{DieAbbreviation}_ConstrParams"; internal const string UserDefinedProps = $"{DieAbbreviation}_Props"; + internal const string UserDefinedInitParams = $"{DieAbbreviation}_InitParams"; internal const string UserDefinedAddForDisposal = $"{DieAbbreviation}_AddForDisposal"; internal const string UserDefinedAddForDisposalAsync = $"{DieAbbreviation}_AddForDisposalAsync"; diff --git a/Main/Properties/launchSettings.json b/Main/Properties/launchSettings.json index 32517e43..7d72a8fc 100644 --- a/Main/Properties/launchSettings.json +++ b/Main/Properties/launchSettings.json @@ -11,6 +11,10 @@ "Main_BFF": { "commandName": "DebugRoslynComponent", "targetProject": "..\\..\\BFF\\develop\\Composition.DIE\\Composition.DIE.csproj" + }, + "Main_Central": { + "commandName": "DebugRoslynComponent", + "targetProject": "..\\..\\Private.ZeroInstall.UI\\Central.Container\\Central.Container.csproj" } } } \ No newline at end of file diff --git a/Main/ReferenceGenerator.cs b/Main/ReferenceGenerator.cs index e99a1c73..ef4540f3 100644 --- a/Main/ReferenceGenerator.cs +++ b/Main/ReferenceGenerator.cs @@ -20,7 +20,7 @@ public string Generate(ITypeSymbol type) => string.Empty, type.Name is { Length: > 1 } ? $"{char.ToLower(type.Name[0])}{type.Name.Substring(1)}" - : "empty", + : "empty", // todo warning type without name seems strange string.Empty); public string Generate(string prefix, ITypeSymbol type) => diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs index e015c760..9774cbfe 100644 --- a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs @@ -575,18 +575,18 @@ INamedTypeSymbol UnwrapAsynchronicity(INamedTypeSymbol currentWrappedType, Stack var wrappedTaskReference = RootReferenceGenerator.Generate(_wellKnownTypes.Task); if (resolution.Item2 is ConstructorResolution constructorResolution) { - if (constructorResolution.Initialization is TaskBaseTypeInitializationResolution taskBaseResolution) + if (constructorResolution.Initialization is TaskBaseInitializationResolution taskBaseResolution) taskBaseResolution.Await = false; var taskResolution = constructorResolution.Initialization switch { - TaskTypeInitializationResolution taskTypeInitialization => new TaskFromTaskResolution( + TaskInitializationResolution taskInitialization => new TaskFromTaskResolution( resolution.Item1, - taskTypeInitialization, + taskInitialization, wrappedTaskReference, boundTaskTypeFullName), - ValueTaskTypeInitializationResolution taskTypeInitialization => new TaskFromValueTaskResolution( + ValueTaskInitializationResolution taskInitialization => new TaskFromValueTaskResolution( resolution.Item1, - taskTypeInitialization, + taskInitialization, wrappedTaskReference, boundTaskTypeFullName), _ => (Resolvable) new TaskFromSyncResolution(resolution.Item1, wrappedTaskReference, boundTaskTypeFullName) @@ -626,18 +626,18 @@ INamedTypeSymbol UnwrapAsynchronicity(INamedTypeSymbol currentWrappedType, Stack var wrappedValueTaskReference = RootReferenceGenerator.Generate(_wellKnownTypes.ValueTask); if (resolution.Item2 is ConstructorResolution constructorResolution) { - if (constructorResolution.Initialization is TaskBaseTypeInitializationResolution taskBaseResolution) + if (constructorResolution.Initialization is TaskBaseInitializationResolution taskBaseResolution) taskBaseResolution.Await = false; var taskResolution = constructorResolution.Initialization switch { - TaskTypeInitializationResolution taskTypeInitialization => new ValueTaskFromTaskResolution( + TaskInitializationResolution taskInitialization => new ValueTaskFromTaskResolution( resolution.Item1, - taskTypeInitialization, + taskInitialization, wrappedValueTaskReference, boundValueTaskTypeFullName), - ValueTaskTypeInitializationResolution taskTypeInitialization => new ValueTaskFromValueTaskResolution( + ValueTaskInitializationResolution taskInitialization => new ValueTaskFromValueTaskResolution( resolution.Item1, - taskTypeInitialization, + taskInitialization, wrappedValueTaskReference, boundValueTaskTypeFullName), _ => (Resolvable) new ValueTaskFromSyncResolution(resolution.Item1, wrappedValueTaskReference, boundValueTaskTypeFullName) @@ -918,7 +918,7 @@ INamedTypeSymbol UnwrapAsynchronicity(INamedTypeSymbol currentWrappedType, Stack var isTransientScopeRoot = _checkTypeProperties.ShouldBeScopeRoot(implementationType) == ScopeLevel.TransientScope; - var (userDefinedConstructorParametersInjection, outConstructorsParameters) = GetUserDefinedInjectionResolution( + var (userDefinedConstructorParametersInjection, outConstructorParameters) = GetUserDefinedInjectionResolution( _userDefinedElements.GetConstructorParametersInjectionFor(implementationType), (name, parameters) => new UserDefinedConstructorParametersInjectionResolution(name, parameters)); @@ -926,28 +926,47 @@ INamedTypeSymbol UnwrapAsynchronicity(INamedTypeSymbol currentWrappedType, Stack _userDefinedElements.GetPropertiesInjectionFor(implementationType), (name, parameters) => new UserDefinedPropertiesInjectionResolution(name, parameters)); - ITypeInitializationResolution? typeInitializationResolution = null; + IInitializationResolution? typeInitializationResolution = null; if (_checkTypeProperties.GetInitializerFor(implementationType) is { } tuple) { + var (userDefinedInitializerParametersInjection, outInitializerParameters) = GetUserDefinedInjectionResolution( + _userDefinedElements.GetInitializerParametersInjectionFor(implementationType), + (name, parameters) => new UserDefinedInitializerParametersInjectionResolution(name, parameters)); + var (initializationInterface, initializationMethod) = tuple; var initializationTypeFullName = initializationInterface.FullName(); var initializationMethodName = initializationMethod.Name; + + var parameters = new ReadOnlyCollection<(string Name, Resolvable Dependency)>(tuple + .Initializer + .Parameters + .Select(p => ProcessInitializerParametersChildType(p.Type, p.Name, currentParameters)) + .ToList()); + typeInitializationResolution = initializationMethod.ReturnsVoid switch { - true => new SyncTypeInitializationResolution(initializationTypeFullName, initializationMethodName), + true => new SyncInitializationResolution( + initializationTypeFullName, + initializationMethodName, + parameters, + userDefinedInitializerParametersInjection), false when initializationMethod.ReturnType.Equals(_wellKnownTypes.Task, SymbolEqualityComparer.Default) => - new TaskTypeInitializationResolution( + new TaskInitializationResolution( initializationTypeFullName, initializationMethodName, _wellKnownTypes.Task.FullName(), - RootReferenceGenerator.Generate(_wellKnownTypes.Task)), + RootReferenceGenerator.Generate(_wellKnownTypes.Task), + parameters, + userDefinedInitializerParametersInjection), false when initializationMethod.ReturnType.Equals(_wellKnownTypes.ValueTask, SymbolEqualityComparer.Default) => - new ValueTaskTypeInitializationResolution( + new ValueTaskInitializationResolution( initializationTypeFullName, initializationMethodName, _wellKnownTypes.ValueTask.FullName(), - RootReferenceGenerator.Generate(_wellKnownTypes.ValueTask)), + RootReferenceGenerator.Generate(_wellKnownTypes.ValueTask), + parameters, + userDefinedInitializerParametersInjection), _ => typeInitializationResolution }; @@ -955,6 +974,17 @@ false when initializationMethod.ReturnType.Equals(_wellKnownTypes.ValueTask, Sym { _synchronicityDecisionMaker.Register(awaitableResolution); } + + (string Name, Resolvable Dependency) ProcessInitializerParametersChildType( + ITypeSymbol typeSymbol, + string parameterName, + ImmutableSortedDictionary currParameter) + { + if (outInitializerParameters.TryGetValue(parameterName, out var outParameterResolution)) + return (parameterName, + new ParameterResolution(outParameterResolution.Reference, outParameterResolution.TypeFullName)); + return ProcessChildType(typeSymbol, parameterName, currParameter); + } } var resolution = new ConstructorResolution( @@ -985,7 +1015,7 @@ false when initializationMethod.ReturnType.Equals(_wellKnownTypes.ValueTask, Sym string parameterName, ImmutableSortedDictionary currParameter) { - if (outConstructorsParameters.TryGetValue(parameterName, out var outParameterResolution)) + if (outConstructorParameters.TryGetValue(parameterName, out var outParameterResolution)) return (parameterName, new ParameterResolution(outParameterResolution.Reference, outParameterResolution.TypeFullName)); return ProcessChildType(typeSymbol, parameterName, currParameter); diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index 3786b34f..566527cb 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -70,11 +70,17 @@ internal record InterfaceResolution( string TypeFullName, ResolutionTreeItem Dependency) : Resolvable(Reference, TypeFullName); -internal interface ITypeInitializationResolution {} +internal interface IInitializationResolution +{ + IReadOnlyList<(string Name, Resolvable Dependency)> Parameters { get; } + UserDefinedInitializerParametersInjectionResolution? UserDefinedInitializerParametersInjectionResolution { get; } +} -internal record SyncTypeInitializationResolution( +internal record SyncInitializationResolution( string TypeFullName, - string MethodName) : ITypeInitializationResolution; + string MethodName, + IReadOnlyList<(string Name, Resolvable Dependency)> Parameters, + UserDefinedInitializerParametersInjectionResolution? UserDefinedInitializerParametersInjectionResolution) : IInitializationResolution; internal interface IAwaitableResolution { @@ -83,26 +89,34 @@ internal interface IAwaitableResolution internal interface ITaskConsumableResolution {} -internal record TaskBaseTypeInitializationResolution( +internal record TaskBaseInitializationResolution( string TypeFullName, string MethodName, string TaskTypeFullName, - string TaskReference) : ITypeInitializationResolution, IAwaitableResolution + string TaskReference, + IReadOnlyList<(string Name, Resolvable Dependency)> Parameters, + UserDefinedInitializerParametersInjectionResolution? UserDefinedInitializerParametersInjectionResolution) : IInitializationResolution, IAwaitableResolution { public bool Await { get; set; } = true; } -internal record TaskTypeInitializationResolution( +internal record TaskInitializationResolution( string TypeFullName, string MethodName, string TaskTypeFullName, - string TaskReference) : TaskBaseTypeInitializationResolution(TypeFullName, MethodName, TaskTypeFullName, TaskReference); + string TaskReference, + IReadOnlyList<(string Name, Resolvable Dependency)> Parameters, + UserDefinedInitializerParametersInjectionResolution? UserDefinedInitializerParametersInjectionResolution) + : TaskBaseInitializationResolution(TypeFullName, MethodName, TaskTypeFullName, TaskReference, Parameters, UserDefinedInitializerParametersInjectionResolution); -internal record ValueTaskTypeInitializationResolution( +internal record ValueTaskInitializationResolution( string TypeFullName, string MethodName, string TaskTypeFullName, - string TaskReference) : TaskBaseTypeInitializationResolution(TypeFullName, MethodName, TaskTypeFullName, TaskReference); + string TaskReference, + IReadOnlyList<(string Name, Resolvable Dependency)> Parameters, + UserDefinedInitializerParametersInjectionResolution? UserDefinedInitializerParametersInjectionResolution) + : TaskBaseInitializationResolution(TypeFullName, MethodName, TaskTypeFullName, TaskReference, Parameters, UserDefinedInitializerParametersInjectionResolution); internal record ConstructorResolution( string Reference, @@ -110,7 +124,7 @@ internal record ConstructorResolution( DisposalType DisposalType, IReadOnlyList<(string Name, Resolvable Dependency)> Parameter, IReadOnlyList<(string Name, Resolvable Dependency)> InitializedProperties, - ITypeInitializationResolution? Initialization, + IInitializationResolution? Initialization, UserDefinedConstructorParametersInjectionResolution? UserDefinedConstructorParametersInjection, UserDefinedPropertiesInjectionResolution? UserDefinedPropertiesInjection) : Resolvable(Reference, TypeFullName), ITaskConsumableResolution; @@ -182,6 +196,10 @@ internal record UserDefinedPropertiesInjectionResolution( string FunctionName, IReadOnlyList<(string Name, Resolvable Dependency, bool isOut)> Parameter) : UserDefinedInjectionResolution(FunctionName, Parameter); +internal record UserDefinedInitializerParametersInjectionResolution( + string FunctionName, + IReadOnlyList<(string Name, Resolvable Dependency, bool isOut)> Parameter) : UserDefinedInjectionResolution(FunctionName, Parameter); + internal record CollectionResolution( string Reference, string TypeFullName, @@ -326,12 +344,12 @@ internal abstract record TaskBaseResolution( internal record TaskFromTaskResolution( Resolvable WrappedResolvable, - TaskTypeInitializationResolution Initialization, + TaskInitializationResolution Initialization, string TaskReference, string TaskFullName) : TaskBaseResolution(WrappedResolvable, TaskReference, TaskFullName); internal record TaskFromValueTaskResolution( Resolvable WrappedResolvable, - ValueTaskTypeInitializationResolution Initialization, + ValueTaskInitializationResolution Initialization, string TaskReference, string TaskFullName) : TaskBaseResolution(WrappedResolvable, TaskReference, TaskFullName); internal record TaskFromSyncResolution( @@ -341,12 +359,12 @@ internal record TaskFromSyncResolution( internal record ValueTaskFromTaskResolution( Resolvable WrappedResolvable, - TaskTypeInitializationResolution Initialization, + TaskInitializationResolution Initialization, string ValueTaskReference, string ValueTaskFullName) : TaskBaseResolution(WrappedResolvable, ValueTaskReference, ValueTaskFullName); internal record ValueTaskFromValueTaskResolution( Resolvable WrappedResolvable, - ValueTaskTypeInitializationResolution Initialization, + ValueTaskInitializationResolution Initialization, string ValueTaskReference, string ValueTaskFullName) : TaskBaseResolution(WrappedResolvable, ValueTaskReference, ValueTaskFullName); internal record ValueTaskFromSyncResolution( diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index f54254ee..cfbff0a6 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -31,6 +31,7 @@ public void Execute(GeneratorExecutionContext context) var validateUserDefinedAddForDisposalAsync = new ValidateUserDefinedAddForDisposalAsync(wellKnownTypes); var validateUserDefinedConstructorParametersInjectionMethod = new ValidateUserDefinedConstructorParametersInjectionMethod(wellKnownTypesMiscellaneous); var validateUserDefinedPropertiesInjectionMethod = new ValidateUserDefinedPropertiesInjectionMethod(wellKnownTypesMiscellaneous); + var validateUserDefinedInitializerParametersInjectionMethod = new ValidateUserDefinedInitializerParametersInjectionMethod(wellKnownTypesMiscellaneous); var validateUserDefinedFactoryField = new ValidateUserDefinedFactoryField(); var validateUserDefinedFactoryMethod = new ValidateUserDefinedFactoryMethod(); var validateAttributes = new ValidateAttributes(); @@ -39,6 +40,7 @@ public void Execute(GeneratorExecutionContext context) validateUserDefinedAddForDisposalAsync, validateUserDefinedConstructorParametersInjectionMethod, validateUserDefinedPropertiesInjectionMethod, + validateUserDefinedInitializerParametersInjectionMethod, validateUserDefinedFactoryMethod, validateUserDefinedFactoryField, wellKnownTypes, @@ -49,6 +51,7 @@ public void Execute(GeneratorExecutionContext context) validateUserDefinedAddForDisposalAsync, validateUserDefinedConstructorParametersInjectionMethod, validateUserDefinedPropertiesInjectionMethod, + validateUserDefinedInitializerParametersInjectionMethod, validateUserDefinedFactoryMethod, validateUserDefinedFactoryField, wellKnownTypes, @@ -61,6 +64,7 @@ public void Execute(GeneratorExecutionContext context) validateUserDefinedAddForDisposalAsync, validateUserDefinedConstructorParametersInjectionMethod, validateUserDefinedPropertiesInjectionMethod, + validateUserDefinedInitializerParametersInjectionMethod, validateUserDefinedFactoryMethod, validateUserDefinedFactoryField, wellKnownTypes, diff --git a/Main/UserDefinedElements.cs b/Main/UserDefinedElements.cs index 7f61b88e..2feeb675 100644 --- a/Main/UserDefinedElements.cs +++ b/Main/UserDefinedElements.cs @@ -9,6 +9,7 @@ internal interface IUserDefinedElements IMethodSymbol? AddForDisposalAsync { get; } IMethodSymbol? GetConstructorParametersInjectionFor(INamedTypeSymbol type); IMethodSymbol? GetPropertiesInjectionFor(INamedTypeSymbol type); + IMethodSymbol? GetInitializerParametersInjectionFor(INamedTypeSymbol type); } internal class EmptyUserDefinedElements : IUserDefinedElements @@ -20,6 +21,7 @@ internal class EmptyUserDefinedElements : IUserDefinedElements public IMethodSymbol? AddForDisposalAsync => null; public IMethodSymbol? GetConstructorParametersInjectionFor(INamedTypeSymbol type) => null; public IMethodSymbol? GetPropertiesInjectionFor(INamedTypeSymbol type) => null; + public IMethodSymbol? GetInitializerParametersInjectionFor(INamedTypeSymbol type) => null; } internal class UserDefinedElements : IUserDefinedElements @@ -29,6 +31,7 @@ internal class UserDefinedElements : IUserDefinedElements private readonly IReadOnlyDictionary _typeToMethod; private readonly IReadOnlyDictionary _constructorParametersInjectionMethods; private readonly IReadOnlyDictionary _propertiesInjectionMethods; + private readonly IReadOnlyDictionary _initializerParametersInjectionMethods; public UserDefinedElements( // parameter @@ -123,6 +126,8 @@ public UserDefinedElements( _constructorParametersInjectionMethods = GetInjectionMethods(Constants.UserDefinedConstrParams, wellKnownTypesMiscellaneous.UserDefinedConstructorParametersInjectionAttribute); _propertiesInjectionMethods = GetInjectionMethods(Constants.UserDefinedProps, wellKnownTypesMiscellaneous.UserDefinedPropertiesInjectionAttribute); + + _initializerParametersInjectionMethods = GetInjectionMethods(Constants.UserDefinedInitParams, wellKnownTypesMiscellaneous.UserDefinedInitializerParametersInjectionAttribute); if (validationErrors.Any()) throw new ValidationDieException(validationErrors.ToImmutableArray()); @@ -193,4 +198,7 @@ public UserDefinedElements( public IMethodSymbol? GetPropertiesInjectionFor(INamedTypeSymbol type) => _propertiesInjectionMethods.TryGetValue(type, out var ret) ? ret : null; + + public IMethodSymbol? GetInitializerParametersInjectionFor(INamedTypeSymbol type) => + _initializerParametersInjectionMethods.TryGetValue(type, out var ret) ? ret : null; } \ No newline at end of file diff --git a/Main/Validation/Range/UserDefined/ValidateUserDefinedConstrParamsInjectionMethod.cs b/Main/Validation/Range/UserDefined/ValidateUserDefinedConstructorParametersInjectionMethod.cs similarity index 100% rename from Main/Validation/Range/UserDefined/ValidateUserDefinedConstrParamsInjectionMethod.cs rename to Main/Validation/Range/UserDefined/ValidateUserDefinedConstructorParametersInjectionMethod.cs diff --git a/Main/Validation/Range/UserDefined/ValidateUserDefinedInitializerParametersInjectionMethod.cs b/Main/Validation/Range/UserDefined/ValidateUserDefinedInitializerParametersInjectionMethod.cs new file mode 100644 index 00000000..5beb94c7 --- /dev/null +++ b/Main/Validation/Range/UserDefined/ValidateUserDefinedInitializerParametersInjectionMethod.cs @@ -0,0 +1,14 @@ +namespace MrMeeseeks.DIE.Validation.Range.UserDefined; + +internal interface IValidateUserDefinedInitializerParametersInjectionMethod : IValidateUserDefinedInjectionMethod +{ + +} + +internal class ValidateUserDefinedInitializerParametersInjectionMethod : ValidateUserDefinedInjectionMethod, IValidateUserDefinedInitializerParametersInjectionMethod +{ + internal ValidateUserDefinedInitializerParametersInjectionMethod(WellKnownTypesMiscellaneous wellKnownTypesMiscellaneous) => + InjectionAttribute = wellKnownTypesMiscellaneous.UserDefinedInitializerParametersInjectionAttribute; + + protected override INamedTypeSymbol InjectionAttribute { get; } +} \ No newline at end of file diff --git a/Main/Validation/Range/ValidateContainer.cs b/Main/Validation/Range/ValidateContainer.cs index 21f54c29..2319bd93 100644 --- a/Main/Validation/Range/ValidateContainer.cs +++ b/Main/Validation/Range/ValidateContainer.cs @@ -21,6 +21,7 @@ internal ValidateContainer( IValidateUserDefinedAddForDisposalAsync validateUserDefinedAddForDisposalAsync, IValidateUserDefinedConstructorParametersInjectionMethod validateUserDefinedConstructorParametersInjectionMethod, IValidateUserDefinedPropertiesMethod validateUserDefinedPropertiesMethod, + IValidateUserDefinedInitializerParametersInjectionMethod validateUserDefinedInitializerParametersInjectionMethod, IValidateUserDefinedFactoryMethod validateUserDefinedFactoryMethod, IValidateUserDefinedFactoryField validateUserDefinedFactoryField, WellKnownTypes wellKnownTypes, @@ -30,6 +31,7 @@ internal ValidateContainer( validateUserDefinedAddForDisposalAsync, validateUserDefinedConstructorParametersInjectionMethod, validateUserDefinedPropertiesMethod, + validateUserDefinedInitializerParametersInjectionMethod, validateUserDefinedFactoryMethod, validateUserDefinedFactoryField, wellKnownTypes) diff --git a/Main/Validation/Range/ValidateRange.cs b/Main/Validation/Range/ValidateRange.cs index d66b230f..ebaad069 100644 --- a/Main/Validation/Range/ValidateRange.cs +++ b/Main/Validation/Range/ValidateRange.cs @@ -14,6 +14,7 @@ internal abstract class ValidateRange : IValidateRange private readonly IValidateUserDefinedAddForDisposalAsync _validateUserDefinedAddForDisposalAsync; private readonly IValidateUserDefinedConstructorParametersInjectionMethod _validateUserDefinedConstructorParametersInjectionMethod; private readonly IValidateUserDefinedPropertiesMethod _validateUserDefinedPropertiesMethod; + private readonly IValidateUserDefinedInitializerParametersInjectionMethod _validateUserDefinedInitializerParametersInjectionMethod; private readonly IValidateUserDefinedFactoryMethod _validateUserDefinedFactoryMethod; private readonly IValidateUserDefinedFactoryField _validateUserDefinedFactoryField; private readonly WellKnownTypes _wellKnownTypes; @@ -24,6 +25,7 @@ internal ValidateRange( IValidateUserDefinedAddForDisposalAsync validateUserDefinedAddForDisposalAsync, IValidateUserDefinedConstructorParametersInjectionMethod validateUserDefinedConstructorParametersInjectionMethod, IValidateUserDefinedPropertiesMethod validateUserDefinedPropertiesMethod, + IValidateUserDefinedInitializerParametersInjectionMethod validateUserDefinedInitializerParametersInjectionMethod, IValidateUserDefinedFactoryMethod validateUserDefinedFactoryMethod, IValidateUserDefinedFactoryField validateUserDefinedFactoryField, WellKnownTypes wellKnownTypes) @@ -32,6 +34,7 @@ internal ValidateRange( _validateUserDefinedAddForDisposalAsync = validateUserDefinedAddForDisposalAsync; _validateUserDefinedConstructorParametersInjectionMethod = validateUserDefinedConstructorParametersInjectionMethod; _validateUserDefinedPropertiesMethod = validateUserDefinedPropertiesMethod; + _validateUserDefinedInitializerParametersInjectionMethod = validateUserDefinedInitializerParametersInjectionMethod; _validateUserDefinedFactoryMethod = validateUserDefinedFactoryMethod; _validateUserDefinedFactoryField = validateUserDefinedFactoryField; _wellKnownTypes = wellKnownTypes; @@ -111,6 +114,8 @@ public virtual IEnumerable Validate(INamedTypeSymbol rangeType, INam yield return diagnostic; foreach (var diagnostic in ValidateUserDefinedInjection(Constants.UserDefinedProps, _validateUserDefinedPropertiesMethod)) yield return diagnostic; + foreach (var diagnostic in ValidateUserDefinedInjection(Constants.UserDefinedInitParams, _validateUserDefinedInitializerParametersInjectionMethod)) + yield return diagnostic; var userDefinedFactories = rangeType .GetMembers() diff --git a/Main/Validation/Range/ValidateScope.cs b/Main/Validation/Range/ValidateScope.cs index 80197913..53872f5b 100644 --- a/Main/Validation/Range/ValidateScope.cs +++ b/Main/Validation/Range/ValidateScope.cs @@ -13,6 +13,7 @@ internal ValidateScope( IValidateUserDefinedAddForDisposalAsync validateUserDefinedAddForDisposalAsync, IValidateUserDefinedConstructorParametersInjectionMethod validateUserDefinedConstructorParametersInjectionMethod, IValidateUserDefinedPropertiesMethod validateUserDefinedPropertiesMethod, + IValidateUserDefinedInitializerParametersInjectionMethod validateUserDefinedInitializerParametersInjectionMethod, IValidateUserDefinedFactoryMethod validateUserDefinedFactoryMethod, IValidateUserDefinedFactoryField validateUserDefinedFactoryField, WellKnownTypes wellKnownTypes, @@ -23,6 +24,7 @@ internal ValidateScope( validateUserDefinedAddForDisposalAsync, validateUserDefinedConstructorParametersInjectionMethod, validateUserDefinedPropertiesMethod, + validateUserDefinedInitializerParametersInjectionMethod, validateUserDefinedFactoryMethod, validateUserDefinedFactoryField, wellKnownTypes, diff --git a/Main/Validation/Range/ValidateScopeBase.cs b/Main/Validation/Range/ValidateScopeBase.cs index e1d26186..744cf1f0 100644 --- a/Main/Validation/Range/ValidateScopeBase.cs +++ b/Main/Validation/Range/ValidateScopeBase.cs @@ -16,6 +16,7 @@ internal ValidateScopeBase( IValidateUserDefinedAddForDisposalAsync validateUserDefinedAddForDisposalAsync, IValidateUserDefinedConstructorParametersInjectionMethod validateUserDefinedConstructorParametersInjectionMethod, IValidateUserDefinedPropertiesMethod validateUserDefinedPropertiesMethod, + IValidateUserDefinedInitializerParametersInjectionMethod validateUserDefinedInitializerParametersInjectionMethod, IValidateUserDefinedFactoryMethod validateUserDefinedFactoryMethod, IValidateUserDefinedFactoryField validateUserDefinedFactoryField, WellKnownTypes wellKnownTypes, @@ -26,6 +27,7 @@ internal ValidateScopeBase( validateUserDefinedAddForDisposalAsync, validateUserDefinedConstructorParametersInjectionMethod, validateUserDefinedPropertiesMethod, + validateUserDefinedInitializerParametersInjectionMethod, validateUserDefinedFactoryMethod, validateUserDefinedFactoryField, wellKnownTypes) diff --git a/Main/Validation/Range/ValidateTransientScope.cs b/Main/Validation/Range/ValidateTransientScope.cs index b9e21365..8b0668a6 100644 --- a/Main/Validation/Range/ValidateTransientScope.cs +++ b/Main/Validation/Range/ValidateTransientScope.cs @@ -13,6 +13,7 @@ internal ValidateTransientScope( IValidateUserDefinedAddForDisposalAsync validateUserDefinedAddForDisposalAsync, IValidateUserDefinedConstructorParametersInjectionMethod validateUserDefinedConstructorParametersInjectionMethod, IValidateUserDefinedPropertiesMethod validateUserDefinedPropertiesMethod, + IValidateUserDefinedInitializerParametersInjectionMethod validateUserDefinedInitializerParametersInjectionMethod, IValidateUserDefinedFactoryMethod validateUserDefinedFactoryMethod, IValidateUserDefinedFactoryField validateUserDefinedFactoryField, WellKnownTypes wellKnownTypes, @@ -23,6 +24,7 @@ internal ValidateTransientScope( validateUserDefinedAddForDisposalAsync, validateUserDefinedConstructorParametersInjectionMethod, validateUserDefinedPropertiesMethod, + validateUserDefinedInitializerParametersInjectionMethod, validateUserDefinedFactoryMethod, validateUserDefinedFactoryField, wellKnownTypes, diff --git a/Main/WellKnownTypesMiscellaneous.cs b/Main/WellKnownTypesMiscellaneous.cs index 44814efe..5df18509 100644 --- a/Main/WellKnownTypesMiscellaneous.cs +++ b/Main/WellKnownTypesMiscellaneous.cs @@ -3,11 +3,12 @@ namespace MrMeeseeks.DIE; internal record WellKnownTypesMiscellaneous( - INamedTypeSymbol TypeInitializerAttribute, - INamedTypeSymbol FilterTypeInitializerAttribute, + INamedTypeSymbol InitializerAttribute, + INamedTypeSymbol FilterInitializerAttribute, INamedTypeSymbol CustomScopeForRootTypesAttribute, INamedTypeSymbol UserDefinedConstructorParametersInjectionAttribute, INamedTypeSymbol UserDefinedPropertiesInjectionAttribute, + INamedTypeSymbol UserDefinedInitializerParametersInjectionAttribute, INamedTypeSymbol CreateFunctionAttribute, INamedTypeSymbol ErrorDescriptionInsteadOfBuildFailureAttribute, INamedTypeSymbol DieExceptionKind) @@ -20,14 +21,17 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypesMiscel var userDefinedConstructorParametersInjectionAttribute = compilation .GetTypeByMetadataName(typeof(UserDefinedConstructorParametersInjectionAttribute).FullName ?? ""); + var userDefinedInitializerParametersInjectionAttribute = compilation + .GetTypeByMetadataName(typeof(UserDefinedInitializerParametersInjectionAttribute).FullName ?? ""); + var userDefinedPropertiesInjectionAttribute = compilation .GetTypeByMetadataName(typeof(UserDefinedPropertiesInjectionAttribute).FullName ?? ""); var typeInitializerAttribute = compilation - .GetTypeByMetadataName(typeof(TypeInitializerAttribute).FullName ?? ""); + .GetTypeByMetadataName(typeof(InitializerAttribute).FullName ?? ""); - var filterTypeInitializerAttribute = compilation - .GetTypeByMetadataName(typeof(FilterTypeInitializerAttribute).FullName ?? ""); + var filterInitializerAttribute = compilation + .GetTypeByMetadataName(typeof(FilterInitializerAttribute).FullName ?? ""); var createFunctionAttribute = compilation .GetTypeByMetadataName(typeof(CreateFunctionAttribute).FullName ?? ""); @@ -39,21 +43,23 @@ internal static bool TryCreate(Compilation compilation, out WellKnownTypesMiscel .GetTypeByMetadataName(typeof(DieExceptionKind).FullName ?? ""); if (typeInitializerAttribute is not null - && filterTypeInitializerAttribute is not null + && filterInitializerAttribute is not null && customScopeForRootTypesAttribute is not null && userDefinedConstructorParametersInjectionAttribute is not null && userDefinedPropertiesInjectionAttribute is not null + && userDefinedInitializerParametersInjectionAttribute is not null && createFunctionAttribute is not null && errorDescriptionInsteadOfBuildFailureAttribute is not null && dieExceptionKind is not null) { wellKnownTypes = new WellKnownTypesMiscellaneous( - TypeInitializerAttribute: typeInitializerAttribute, - FilterTypeInitializerAttribute: filterTypeInitializerAttribute, + InitializerAttribute: typeInitializerAttribute, + FilterInitializerAttribute: filterInitializerAttribute, CustomScopeForRootTypesAttribute: customScopeForRootTypesAttribute, UserDefinedConstructorParametersInjectionAttribute: userDefinedConstructorParametersInjectionAttribute, UserDefinedPropertiesInjectionAttribute: userDefinedPropertiesInjectionAttribute, + UserDefinedInitializerParametersInjectionAttribute: userDefinedInitializerParametersInjectionAttribute, CreateFunctionAttribute: createFunctionAttribute, ErrorDescriptionInsteadOfBuildFailureAttribute: errorDescriptionInsteadOfBuildFailureAttribute, DieExceptionKind: dieExceptionKind); diff --git a/Sample/Container.cs b/Sample/Container.cs index c49eb785..c0d1c937 100644 --- a/Sample/Container.cs +++ b/Sample/Container.cs @@ -1,28 +1,27 @@ -using System; -using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration.Attributes; -using MrMeeseeks.DIE.Sample; +using MrMeeseeks.DIE.Configuration.Attributes; -namespace MrMeeseeks.DIE.Test.Func.AsyncWrapped.SingleValueTask; +namespace MrMeeseeks.DIE.Test.Initializer.WithParameters; -internal class Dependency : IValueTaskTypeInitializer +internal class Dependency { - public ValueTask InitializeAsync() - { - return ValueTask.CompletedTask; - } -} + public bool IsInitialized { get; private set; } -internal class OuterDependency -{ - internal OuterDependency( - Dependency dependency) + public int Number { get; private set; } + + public string Text { get; private set; } = ""; + + internal void Initialize(int number, string text) { - + IsInitialized = true; + Number = number; + Text = text; } } -[CreateFunction(typeof(Func>), "Create")] +[Initializer(typeof(Dependency), nameof(Dependency.Initialize))] +[CreateFunction(typeof(Dependency), "Create")] internal sealed partial class Container { + private readonly int DIE_Factory_Number = 69; + private readonly string DIE_Factory_Text = "foo"; } \ No newline at end of file diff --git a/Sample/MarkerInterfaces.cs b/Sample/MarkerInterfaces.cs index ad965cfd..fe2c2ae0 100644 --- a/Sample/MarkerInterfaces.cs +++ b/Sample/MarkerInterfaces.cs @@ -14,9 +14,9 @@ [assembly:AsyncTransientAbstractionAggregation(typeof(IAsyncTransient))] [assembly:DecoratorAbstractionAggregation(typeof(IDecorator<>))] [assembly:CompositeAbstractionAggregation(typeof(IComposite<>))] -[assembly:TypeInitializer(typeof(ITypeInitializer), nameof(ITypeInitializer.Initialize))] -[assembly:TypeInitializer(typeof(ITaskTypeInitializer), nameof(ITaskTypeInitializer.InitializeAsync))] -[assembly:TypeInitializer(typeof(IValueTaskTypeInitializer), nameof(IValueTaskTypeInitializer.InitializeAsync))] +[assembly:Initializer(typeof(IInitializer), nameof(IInitializer.Initialize))] +[assembly:Initializer(typeof(ITaskInitializer), nameof(ITaskInitializer.InitializeAsync))] +[assembly:Initializer(typeof(IValueTaskInitializer), nameof(IValueTaskInitializer.InitializeAsync))] [assembly:AllImplementationsAggregation] @@ -32,15 +32,15 @@ public interface ISyncTransient { } public interface IAsyncTransient { } public interface IDecorator { } public interface IComposite { } -public interface ITypeInitializer +public interface IInitializer { void Initialize(); } -public interface ITaskTypeInitializer +public interface ITaskInitializer { Task InitializeAsync(); } -public interface IValueTaskTypeInitializer +public interface IValueTaskInitializer { ValueTask InitializeAsync(); } \ No newline at end of file diff --git a/Test/AssemblyInfo.cs b/Test/AssemblyInfo.cs index bf61ebde..0359365f 100644 --- a/Test/AssemblyInfo.cs +++ b/Test/AssemblyInfo.cs @@ -11,9 +11,9 @@ [assembly:AsyncTransientAbstractionAggregation(typeof(IAsyncTransient))] [assembly:DecoratorAbstractionAggregation(typeof(IDecorator<>))] [assembly:CompositeAbstractionAggregation(typeof(IComposite<>))] -[assembly:TypeInitializer(typeof(ITypeInitializer), nameof(ITypeInitializer.Initialize))] -[assembly:TypeInitializer(typeof(ITaskTypeInitializer), nameof(ITaskTypeInitializer.InitializeAsync))] -[assembly:TypeInitializer(typeof(IValueTaskTypeInitializer), nameof(IValueTaskTypeInitializer.InitializeAsync))] +[assembly:Initializer(typeof(IInitializer), nameof(IInitializer.Initialize))] +[assembly:Initializer(typeof(ITaskInitializer), nameof(ITaskInitializer.InitializeAsync))] +[assembly:Initializer(typeof(IValueTaskInitializer), nameof(IValueTaskInitializer.InitializeAsync))] [assembly:AllImplementationsAggregation] diff --git a/Test/Async/Awaited/AsyncScopeRootCallAsTask.cs b/Test/Async/Awaited/AsyncScopeRootCallAsTask.cs index 1aedd920..5e3a933b 100644 --- a/Test/Async/Awaited/AsyncScopeRootCallAsTask.cs +++ b/Test/Async/Awaited/AsyncScopeRootCallAsTask.cs @@ -5,11 +5,11 @@ namespace MrMeeseeks.DIE.Test.Async.Awaited.AsyncScopeRootCallAsTask; -internal class Dependency : ITaskTypeInitializer +internal class Dependency : ITaskInitializer { public bool IsInitialized { get; private set; } - async Task ITaskTypeInitializer.InitializeAsync() + async Task ITaskInitializer.InitializeAsync() { await Task.Delay(500).ConfigureAwait(false); IsInitialized = true; diff --git a/Test/Async/Awaited/AsyncScopeRootCallAsValueTask.cs b/Test/Async/Awaited/AsyncScopeRootCallAsValueTask.cs index ca6a84b5..71fb5250 100644 --- a/Test/Async/Awaited/AsyncScopeRootCallAsValueTask.cs +++ b/Test/Async/Awaited/AsyncScopeRootCallAsValueTask.cs @@ -5,11 +5,11 @@ namespace MrMeeseeks.DIE.Test.Async.Awaited.AsyncScopeRootCallAsValueTask; -internal class Dependency : ITaskTypeInitializer +internal class Dependency : ITaskInitializer { public bool IsInitialized { get; private set; } - async Task ITaskTypeInitializer.InitializeAsync() + async Task ITaskInitializer.InitializeAsync() { await Task.Delay(500).ConfigureAwait(false); IsInitialized = true; diff --git a/Test/Async/Awaited/AsyncScopeRootCallAwaited.cs b/Test/Async/Awaited/AsyncScopeRootCallAwaited.cs index 4b0869fd..fd3ba33c 100644 --- a/Test/Async/Awaited/AsyncScopeRootCallAwaited.cs +++ b/Test/Async/Awaited/AsyncScopeRootCallAwaited.cs @@ -5,11 +5,11 @@ namespace MrMeeseeks.DIE.Test.Async.Awaited.AsyncScopeRootCallAwaited; -internal class Dependency : ITaskTypeInitializer +internal class Dependency : ITaskInitializer { public bool IsInitialized { get; private set; } - async Task ITaskTypeInitializer.InitializeAsync() + async Task ITaskInitializer.InitializeAsync() { await Task.Delay(500).ConfigureAwait(false); IsInitialized = true; diff --git a/Test/Async/Awaited/ContainerInstanceFunctionAsTask.cs b/Test/Async/Awaited/ContainerInstanceFunctionAsTask.cs index 344ab2db..bd2dc127 100644 --- a/Test/Async/Awaited/ContainerInstanceFunctionAsTask.cs +++ b/Test/Async/Awaited/ContainerInstanceFunctionAsTask.cs @@ -5,11 +5,11 @@ namespace MrMeeseeks.DIE.Test.Async.Awaited.ContainerInstanceFunctionAsTask; -internal class Dependency : ITaskTypeInitializer, IContainerInstance +internal class Dependency : ITaskInitializer, IContainerInstance { public bool IsInitialized { get; private set; } - async Task ITaskTypeInitializer.InitializeAsync() + async Task ITaskInitializer.InitializeAsync() { await Task.Delay(500).ConfigureAwait(false); IsInitialized = true; diff --git a/Test/Async/Awaited/ContainerInstanceFunctionAsValueTask.cs b/Test/Async/Awaited/ContainerInstanceFunctionAsValueTask.cs index 039d1fa0..df08f47b 100644 --- a/Test/Async/Awaited/ContainerInstanceFunctionAsValueTask.cs +++ b/Test/Async/Awaited/ContainerInstanceFunctionAsValueTask.cs @@ -5,11 +5,11 @@ namespace MrMeeseeks.DIE.Test.Async.Awaited.ContainerInstanceFunctionAsValueTask; -internal class Dependency : ITaskTypeInitializer, IContainerInstance +internal class Dependency : ITaskInitializer, IContainerInstance { public bool IsInitialized { get; private set; } - async Task ITaskTypeInitializer.InitializeAsync() + async Task ITaskInitializer.InitializeAsync() { await Task.Delay(500).ConfigureAwait(false); IsInitialized = true; diff --git a/Test/Async/Awaited/ScopeInstanceFunctionAsTask.cs b/Test/Async/Awaited/ScopeInstanceFunctionAsTask.cs index 14019d0b..54be62d9 100644 --- a/Test/Async/Awaited/ScopeInstanceFunctionAsTask.cs +++ b/Test/Async/Awaited/ScopeInstanceFunctionAsTask.cs @@ -5,11 +5,11 @@ namespace MrMeeseeks.DIE.Test.Async.Awaited.ScopeInstanceFunctionAsTask; -internal class Dependency : ITaskTypeInitializer, IScopeInstance +internal class Dependency : ITaskInitializer, IScopeInstance { public bool IsInitialized { get; private set; } - async Task ITaskTypeInitializer.InitializeAsync() + async Task ITaskInitializer.InitializeAsync() { await Task.Delay(500).ConfigureAwait(false); IsInitialized = true; diff --git a/Test/Async/Awaited/ScopeInstanceFunctionAsValueTask.cs b/Test/Async/Awaited/ScopeInstanceFunctionAsValueTask.cs index c1be18af..735b7628 100644 --- a/Test/Async/Awaited/ScopeInstanceFunctionAsValueTask.cs +++ b/Test/Async/Awaited/ScopeInstanceFunctionAsValueTask.cs @@ -5,11 +5,11 @@ namespace MrMeeseeks.DIE.Test.Async.Awaited.ScopeInstanceFunctionAsValueTask; -internal class Dependency : ITaskTypeInitializer, IScopeInstance +internal class Dependency : ITaskInitializer, IScopeInstance { public bool IsInitialized { get; private set; } - async Task ITaskTypeInitializer.InitializeAsync() + async Task ITaskInitializer.InitializeAsync() { await Task.Delay(500).ConfigureAwait(false); IsInitialized = true; diff --git a/Test/Async/Awaited/TaskTypeInitializerTask.cs b/Test/Async/Awaited/TaskTypeInitializerTask.cs index 88c19b03..fd820365 100644 --- a/Test/Async/Awaited/TaskTypeInitializerTask.cs +++ b/Test/Async/Awaited/TaskTypeInitializerTask.cs @@ -2,14 +2,14 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.Async.Awaited.TaskTypeInitializerTask; +namespace MrMeeseeks.DIE.Test.Async.Awaited.TaskInitializerTask; -internal class Dependency : ITaskTypeInitializer +internal class Dependency : ITaskInitializer { public bool IsInitialized { get; private set; } - async Task ITaskTypeInitializer.InitializeAsync() + async Task ITaskInitializer.InitializeAsync() { await Task.Delay(500).ConfigureAwait(false); IsInitialized = true; diff --git a/Test/Async/Awaited/TaskTypeInitializerValueTask.cs b/Test/Async/Awaited/TaskTypeInitializerValueTask.cs index e42b8c33..e64dbf5d 100644 --- a/Test/Async/Awaited/TaskTypeInitializerValueTask.cs +++ b/Test/Async/Awaited/TaskTypeInitializerValueTask.cs @@ -2,14 +2,14 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.Async.Awaited.TaskTypeInitializerValueTask; +namespace MrMeeseeks.DIE.Test.Async.Awaited.TaskInitializerValueTask; -internal class Dependency : IValueTaskTypeInitializer +internal class Dependency : IValueTaskInitializer { public bool IsInitialized { get; private set; } - async ValueTask IValueTaskTypeInitializer.InitializeAsync() + async ValueTask IValueTaskInitializer.InitializeAsync() { await Task.Delay(500).ConfigureAwait(false); IsInitialized = true; diff --git a/Test/Async/Awaited/TransientScopeInstanceFunctionAsTask.cs b/Test/Async/Awaited/TransientScopeInstanceFunctionAsTask.cs index 4206385e..ead39ca5 100644 --- a/Test/Async/Awaited/TransientScopeInstanceFunctionAsTask.cs +++ b/Test/Async/Awaited/TransientScopeInstanceFunctionAsTask.cs @@ -4,11 +4,11 @@ namespace MrMeeseeks.DIE.Test.Async.Awaited.TransientScopeInstanceFunctionAsTask; -internal class Dependency : ITaskTypeInitializer, ITransientScopeInstance +internal class Dependency : ITaskInitializer, ITransientScopeInstance { public bool IsInitialized { get; private set; } - async Task ITaskTypeInitializer.InitializeAsync() + async Task ITaskInitializer.InitializeAsync() { await Task.Delay(500).ConfigureAwait(false); IsInitialized = true; diff --git a/Test/Async/Awaited/TransientScopeInstanceFunctionAsValueTask.cs b/Test/Async/Awaited/TransientScopeInstanceFunctionAsValueTask.cs index 95bc2099..a03e0f70 100644 --- a/Test/Async/Awaited/TransientScopeInstanceFunctionAsValueTask.cs +++ b/Test/Async/Awaited/TransientScopeInstanceFunctionAsValueTask.cs @@ -4,11 +4,11 @@ namespace MrMeeseeks.DIE.Test.Async.Awaited.TransientScopeInstanceFunctionAsValueTask; -internal class Dependency : ITaskTypeInitializer, ITransientScopeInstance +internal class Dependency : ITaskInitializer, ITransientScopeInstance { public bool IsInitialized { get; private set; } - async Task ITaskTypeInitializer.InitializeAsync() + async Task ITaskInitializer.InitializeAsync() { await Task.Delay(500).ConfigureAwait(false); IsInitialized = true; diff --git a/Test/Async/Awaited/TransientScopeInstanceFunction_DifferentSynchronicity.cs b/Test/Async/Awaited/TransientScopeInstanceFunction_DifferentSynchronicity.cs index 7ae29a00..7e0d7080 100644 --- a/Test/Async/Awaited/TransientScopeInstanceFunction_DifferentSynchronicity.cs +++ b/Test/Async/Awaited/TransientScopeInstanceFunction_DifferentSynchronicity.cs @@ -6,11 +6,11 @@ namespace MrMeeseeks.DIE.Test.Async.Awaited.TransientScopeInstanceFunction_Diffe internal interface IInterface {} -internal class DependencyA : IInterface, ITaskTypeInitializer +internal class DependencyA : IInterface, ITaskInitializer { public bool IsInitialized { get; private set; } - async Task ITaskTypeInitializer.InitializeAsync() + async Task ITaskInitializer.InitializeAsync() { await Task.Delay(500).ConfigureAwait(false); IsInitialized = true; diff --git a/Test/Async/Wrapped/ContainerInstanceFunctionAsTask.cs b/Test/Async/Wrapped/ContainerInstanceFunctionAsTask.cs index 80bbf889..80d5eb83 100644 --- a/Test/Async/Wrapped/ContainerInstanceFunctionAsTask.cs +++ b/Test/Async/Wrapped/ContainerInstanceFunctionAsTask.cs @@ -5,11 +5,11 @@ namespace MrMeeseeks.DIE.Test.Async.Wrapped.ContainerInstanceFunctionAsTask; -internal class Dependency : ITaskTypeInitializer, IContainerInstance +internal class Dependency : ITaskInitializer, IContainerInstance { public bool IsInitialized { get; private set; } - async Task ITaskTypeInitializer.InitializeAsync() + async Task ITaskInitializer.InitializeAsync() { await Task.Delay(500).ConfigureAwait(false); IsInitialized = true; diff --git a/Test/Async/Wrapped/ContainerInstanceFunctionAsValueTask.cs b/Test/Async/Wrapped/ContainerInstanceFunctionAsValueTask.cs index b9b25f62..4210e742 100644 --- a/Test/Async/Wrapped/ContainerInstanceFunctionAsValueTask.cs +++ b/Test/Async/Wrapped/ContainerInstanceFunctionAsValueTask.cs @@ -5,11 +5,11 @@ namespace MrMeeseeks.DIE.Test.Async.Wrapped.ContainerInstanceFunctionAsValueTask; -internal class Dependency : ITaskTypeInitializer, IContainerInstance +internal class Dependency : ITaskInitializer, IContainerInstance { public bool IsInitialized { get; private set; } - async Task ITaskTypeInitializer.InitializeAsync() + async Task ITaskInitializer.InitializeAsync() { await Task.Delay(500).ConfigureAwait(false); IsInitialized = true; diff --git a/Test/Async/Wrapped/DecorationChaining.cs b/Test/Async/Wrapped/DecorationChaining.cs index a70d2503..78fc9241 100644 --- a/Test/Async/Wrapped/DecorationChaining.cs +++ b/Test/Async/Wrapped/DecorationChaining.cs @@ -9,38 +9,38 @@ internal interface IInterface bool IsInitialized { get; } } -internal class Dependency : ITaskTypeInitializer, IInterface +internal class Dependency : ITaskInitializer, IInterface { public bool IsInitialized { get; private set; } - async Task ITaskTypeInitializer.InitializeAsync() + async Task ITaskInitializer.InitializeAsync() { await Task.Delay(500).ConfigureAwait(false); IsInitialized = true; } } -internal class DecoratorA : ITypeInitializer, IInterface, IDecorator +internal class DecoratorA : IInitializer, IInterface, IDecorator { private readonly Task _task; public bool IsInitialized { get; private set; } internal DecoratorA(Task task) => _task = task; - void ITypeInitializer.Initialize() + void IInitializer.Initialize() { _task.Wait(); IsInitialized = true; } } -internal class DecoratorB : IValueTaskTypeInitializer, IInterface, IDecorator +internal class DecoratorB : IValueTaskInitializer, IInterface, IDecorator { public bool IsInitialized { get; private set; } internal DecoratorB(IInterface _) {} - async ValueTask IValueTaskTypeInitializer.InitializeAsync() + async ValueTask IValueTaskInitializer.InitializeAsync() { await Task.Delay(500).ConfigureAwait(false); IsInitialized = true; diff --git a/Test/Async/Wrapped/Func.cs b/Test/Async/Wrapped/Func.cs index f030f630..fb34b8b3 100644 --- a/Test/Async/Wrapped/Func.cs +++ b/Test/Async/Wrapped/Func.cs @@ -6,11 +6,11 @@ namespace MrMeeseeks.DIE.Test.Async.Wrapped.Func; -internal class Dependency : ITaskTypeInitializer +internal class Dependency : ITaskInitializer { public bool IsInitialized { get; private set; } - async Task ITaskTypeInitializer.InitializeAsync() + async Task ITaskInitializer.InitializeAsync() { await Task.Delay(500).ConfigureAwait(false); IsInitialized = true; diff --git a/Test/Async/Wrapped/Lazy.cs b/Test/Async/Wrapped/Lazy.cs index 6558faf7..09f73dfc 100644 --- a/Test/Async/Wrapped/Lazy.cs +++ b/Test/Async/Wrapped/Lazy.cs @@ -5,11 +5,11 @@ namespace MrMeeseeks.DIE.Test.Async.Wrapped.Lazy; -internal class Dependency : ITaskTypeInitializer +internal class Dependency : ITaskInitializer { public bool IsInitialized { get; private set; } - async Task ITaskTypeInitializer.InitializeAsync() + async Task ITaskInitializer.InitializeAsync() { await Task.Delay(500).ConfigureAwait(false); IsInitialized = true; diff --git a/Test/Async/Wrapped/ScopeInstanceFunctionAsTask.cs b/Test/Async/Wrapped/ScopeInstanceFunctionAsTask.cs index 69ba44a6..33f3da1d 100644 --- a/Test/Async/Wrapped/ScopeInstanceFunctionAsTask.cs +++ b/Test/Async/Wrapped/ScopeInstanceFunctionAsTask.cs @@ -5,11 +5,11 @@ namespace MrMeeseeks.DIE.Test.Async.Wrapped.ScopeInstanceFunctionAsTask; -internal class Dependency : ITaskTypeInitializer, IScopeInstance +internal class Dependency : ITaskInitializer, IScopeInstance { public bool IsInitialized { get; private set; } - async Task ITaskTypeInitializer.InitializeAsync() + async Task ITaskInitializer.InitializeAsync() { await Task.Delay(500).ConfigureAwait(false); IsInitialized = true; diff --git a/Test/Async/Wrapped/ScopeInstanceFunctionAsValueTask.cs b/Test/Async/Wrapped/ScopeInstanceFunctionAsValueTask.cs index 391bdb20..7fec55fc 100644 --- a/Test/Async/Wrapped/ScopeInstanceFunctionAsValueTask.cs +++ b/Test/Async/Wrapped/ScopeInstanceFunctionAsValueTask.cs @@ -5,11 +5,11 @@ namespace MrMeeseeks.DIE.Test.Async.Wrapped.ScopeInstanceFunctionAsValueTask; -internal class Dependency : ITaskTypeInitializer, IScopeInstance +internal class Dependency : ITaskInitializer, IScopeInstance { public bool IsInitialized { get; private set; } - async Task ITaskTypeInitializer.InitializeAsync() + async Task ITaskInitializer.InitializeAsync() { await Task.Delay(500).ConfigureAwait(false); IsInitialized = true; diff --git a/Test/Async/Wrapped/SyncToTask.cs b/Test/Async/Wrapped/SyncToTask.cs index ae73ac4e..17bf4a0a 100644 --- a/Test/Async/Wrapped/SyncToTask.cs +++ b/Test/Async/Wrapped/SyncToTask.cs @@ -4,11 +4,11 @@ namespace MrMeeseeks.DIE.Test.Async.Wrapped.SyncToTask; -internal class Dependency : ITypeInitializer +internal class Dependency : IInitializer { public bool IsInitialized { get; private set; } - void ITypeInitializer.Initialize() + void IInitializer.Initialize() { IsInitialized = true; } diff --git a/Test/Async/Wrapped/SyncToValueTask.cs b/Test/Async/Wrapped/SyncToValueTask.cs index 554b8e70..0fc9d3bf 100644 --- a/Test/Async/Wrapped/SyncToValueTask.cs +++ b/Test/Async/Wrapped/SyncToValueTask.cs @@ -4,11 +4,11 @@ namespace MrMeeseeks.DIE.Test.Async.Wrapped.SyncToValueTask; -internal class Dependency : ITypeInitializer +internal class Dependency : IInitializer { public bool IsInitialized { get; private set; } - void ITypeInitializer.Initialize() + void IInitializer.Initialize() { IsInitialized = true; } diff --git a/Test/Async/Wrapped/TaskCollection.cs b/Test/Async/Wrapped/TaskCollection.cs index f5a72328..3ab6d7d1 100644 --- a/Test/Async/Wrapped/TaskCollection.cs +++ b/Test/Async/Wrapped/TaskCollection.cs @@ -10,33 +10,33 @@ internal interface IInterface bool IsInitialized { get; } } -internal class DependencyA : ITaskTypeInitializer, IInterface +internal class DependencyA : ITaskInitializer, IInterface { public bool IsInitialized { get; private set; } - async Task ITaskTypeInitializer.InitializeAsync() + async Task ITaskInitializer.InitializeAsync() { await Task.Delay(500).ConfigureAwait(false); IsInitialized = true; } } -internal class DependencyB : IValueTaskTypeInitializer, IInterface +internal class DependencyB : IValueTaskInitializer, IInterface { public bool IsInitialized { get; private set; } - async ValueTask IValueTaskTypeInitializer.InitializeAsync() + async ValueTask IValueTaskInitializer.InitializeAsync() { await Task.Delay(500).ConfigureAwait(false); IsInitialized = true; } } -internal class DependencyC : ITypeInitializer, IInterface +internal class DependencyC : IInitializer, IInterface { public bool IsInitialized { get; private set; } - void ITypeInitializer.Initialize() + void IInitializer.Initialize() { IsInitialized = true; } diff --git a/Test/Async/Wrapped/TaskComposition.cs b/Test/Async/Wrapped/TaskComposition.cs index 360f5a22..807c7329 100644 --- a/Test/Async/Wrapped/TaskComposition.cs +++ b/Test/Async/Wrapped/TaskComposition.cs @@ -10,33 +10,33 @@ internal interface IInterface bool IsInitialized { get; } } -internal class DependencyA : ITaskTypeInitializer, IInterface +internal class DependencyA : ITaskInitializer, IInterface { public bool IsInitialized { get; private set; } - async Task ITaskTypeInitializer.InitializeAsync() + async Task ITaskInitializer.InitializeAsync() { await Task.Delay(500).ConfigureAwait(false); IsInitialized = true; } } -internal class DependencyB : IValueTaskTypeInitializer, IInterface +internal class DependencyB : IValueTaskInitializer, IInterface { public bool IsInitialized { get; private set; } - async ValueTask IValueTaskTypeInitializer.InitializeAsync() + async ValueTask IValueTaskInitializer.InitializeAsync() { await Task.Delay(500).ConfigureAwait(false); IsInitialized = true; } } -internal class DependencyC : ITypeInitializer, IInterface +internal class DependencyC : IInitializer, IInterface { public bool IsInitialized { get; private set; } - void ITypeInitializer.Initialize() + void IInitializer.Initialize() { IsInitialized = true; } @@ -47,7 +47,7 @@ internal class DependencyD : IInterface public bool IsInitialized => true; } -internal class Composite : ITaskTypeInitializer, IInterface, IComposite +internal class Composite : ITaskInitializer, IInterface, IComposite { private readonly IReadOnlyList> _composition; diff --git a/Test/Async/Wrapped/TaskToTask.cs b/Test/Async/Wrapped/TaskToTask.cs index 35489231..f746452f 100644 --- a/Test/Async/Wrapped/TaskToTask.cs +++ b/Test/Async/Wrapped/TaskToTask.cs @@ -5,11 +5,11 @@ namespace MrMeeseeks.DIE.Test.Async.Wrapped.TaskToTask; -internal class Dependency : ITaskTypeInitializer +internal class Dependency : ITaskInitializer { public bool IsInitialized { get; private set; } - async Task ITaskTypeInitializer.InitializeAsync() + async Task ITaskInitializer.InitializeAsync() { await Task.Delay(TimeSpan.FromMilliseconds(500)).ConfigureAwait(false); IsInitialized = true; diff --git a/Test/Async/Wrapped/TaskToValueTask.cs b/Test/Async/Wrapped/TaskToValueTask.cs index 0aa3d943..6c62c48c 100644 --- a/Test/Async/Wrapped/TaskToValueTask.cs +++ b/Test/Async/Wrapped/TaskToValueTask.cs @@ -5,11 +5,11 @@ namespace MrMeeseeks.DIE.Test.Async.Wrapped.TaskToValueTask; -internal class Dependency : ITaskTypeInitializer +internal class Dependency : ITaskInitializer { public bool IsInitialized { get; private set; } - async Task ITaskTypeInitializer.InitializeAsync() + async Task ITaskInitializer.InitializeAsync() { await Task.Delay(TimeSpan.FromMilliseconds(500)).ConfigureAwait(false); IsInitialized = true; diff --git a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask.cs b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask.cs index a1e59467..4e442c01 100644 --- a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask.cs +++ b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask.cs @@ -4,11 +4,11 @@ namespace MrMeeseeks.DIE.Test.Async.Wrapped.TransientScopeInstanceFunctionAsTask; -internal class Dependency : ITaskTypeInitializer, ITransientScopeInstance +internal class Dependency : ITaskInitializer, ITransientScopeInstance { public bool IsInitialized { get; private set; } - async Task ITaskTypeInitializer.InitializeAsync() + async Task ITaskInitializer.InitializeAsync() { await Task.Delay(500).ConfigureAwait(false); IsInitialized = true; diff --git a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask_DifferentSynchronicity.cs b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask_DifferentSynchronicity.cs index ab99d8fe..65cf59db 100644 --- a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask_DifferentSynchronicity.cs +++ b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask_DifferentSynchronicity.cs @@ -6,11 +6,11 @@ namespace MrMeeseeks.DIE.Test.Async.Wrapped.TransientScopeInstanceFunctionAsTask internal interface IInterface {} -internal class DependencyA : IInterface, ITaskTypeInitializer +internal class DependencyA : IInterface, ITaskInitializer { public bool IsInitialized { get; private set; } - async Task ITaskTypeInitializer.InitializeAsync() + async Task ITaskInitializer.InitializeAsync() { await Task.Delay(500).ConfigureAwait(false); IsInitialized = true; diff --git a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask.cs b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask.cs index 2726c4ab..1a4d28d7 100644 --- a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask.cs +++ b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask.cs @@ -4,11 +4,11 @@ namespace MrMeeseeks.DIE.Test.Async.Wrapped.TransientScopeInstanceFunctionAsValueTask; -internal class Dependency : ITaskTypeInitializer, ITransientScopeInstance +internal class Dependency : ITaskInitializer, ITransientScopeInstance { public bool IsInitialized { get; private set; } - async Task ITaskTypeInitializer.InitializeAsync() + async Task ITaskInitializer.InitializeAsync() { await Task.Delay(500).ConfigureAwait(false); IsInitialized = true; diff --git a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask_DifferentSynchronicity.cs b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask_DifferentSynchronicity.cs index 71ff96da..a0406c0e 100644 --- a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask_DifferentSynchronicity.cs +++ b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask_DifferentSynchronicity.cs @@ -6,11 +6,11 @@ namespace MrMeeseeks.DIE.Test.Async.Wrapped.TransientScopeInstanceFunctionAsValu internal interface IInterface {} -internal class DependencyA : IInterface, ITaskTypeInitializer +internal class DependencyA : IInterface, ITaskInitializer { public bool IsInitialized { get; private set; } - async Task ITaskTypeInitializer.InitializeAsync() + async Task ITaskInitializer.InitializeAsync() { await Task.Delay(500).ConfigureAwait(false); IsInitialized = true; diff --git a/Test/Async/Wrapped/ValueTaskCollection.cs b/Test/Async/Wrapped/ValueTaskCollection.cs index be98c69a..5358e80f 100644 --- a/Test/Async/Wrapped/ValueTaskCollection.cs +++ b/Test/Async/Wrapped/ValueTaskCollection.cs @@ -10,33 +10,33 @@ internal interface IInterface bool IsInitialized { get; } } -internal class DependencyA : ITaskTypeInitializer, IInterface +internal class DependencyA : ITaskInitializer, IInterface { public bool IsInitialized { get; private set; } - async Task ITaskTypeInitializer.InitializeAsync() + async Task ITaskInitializer.InitializeAsync() { await Task.Delay(500).ConfigureAwait(false); IsInitialized = true; } } -internal class DependencyB : IValueTaskTypeInitializer, IInterface +internal class DependencyB : IValueTaskInitializer, IInterface { public bool IsInitialized { get; private set; } - async ValueTask IValueTaskTypeInitializer.InitializeAsync() + async ValueTask IValueTaskInitializer.InitializeAsync() { await Task.Delay(500).ConfigureAwait(false); IsInitialized = true; } } -internal class DependencyC : ITypeInitializer, IInterface +internal class DependencyC : IInitializer, IInterface { public bool IsInitialized { get; private set; } - void ITypeInitializer.Initialize() + void IInitializer.Initialize() { IsInitialized = true; } diff --git a/Test/Async/Wrapped/ValueTaskComposition.cs b/Test/Async/Wrapped/ValueTaskComposition.cs index 2ec567eb..e231d8ea 100644 --- a/Test/Async/Wrapped/ValueTaskComposition.cs +++ b/Test/Async/Wrapped/ValueTaskComposition.cs @@ -10,33 +10,33 @@ internal interface IInterface bool IsInitialized { get; } } -internal class DependencyA : ITaskTypeInitializer, IInterface +internal class DependencyA : ITaskInitializer, IInterface { public bool IsInitialized { get; private set; } - async Task ITaskTypeInitializer.InitializeAsync() + async Task ITaskInitializer.InitializeAsync() { await Task.Delay(500).ConfigureAwait(false); IsInitialized = true; } } -internal class DependencyB : IValueTaskTypeInitializer, IInterface +internal class DependencyB : IValueTaskInitializer, IInterface { public bool IsInitialized { get; private set; } - async ValueTask IValueTaskTypeInitializer.InitializeAsync() + async ValueTask IValueTaskInitializer.InitializeAsync() { await Task.Delay(500).ConfigureAwait(false); IsInitialized = true; } } -internal class DependencyC : ITypeInitializer, IInterface +internal class DependencyC : IInitializer, IInterface { public bool IsInitialized { get; private set; } - void ITypeInitializer.Initialize() + void IInitializer.Initialize() { IsInitialized = true; } @@ -47,7 +47,7 @@ internal class DependencyD : IInterface public bool IsInitialized => true; } -internal class Composite : ITaskTypeInitializer, IInterface, IComposite +internal class Composite : ITaskInitializer, IInterface, IComposite { private readonly IReadOnlyList> _composition; diff --git a/Test/Async/Wrapped/ValueTaskToTask.cs b/Test/Async/Wrapped/ValueTaskToTask.cs index bf6023db..7c49ab8c 100644 --- a/Test/Async/Wrapped/ValueTaskToTask.cs +++ b/Test/Async/Wrapped/ValueTaskToTask.cs @@ -5,11 +5,11 @@ namespace MrMeeseeks.DIE.Test.Async.Wrapped.ValueTaskToTask; -internal class Dependency : IValueTaskTypeInitializer +internal class Dependency : IValueTaskInitializer { public bool IsInitialized { get; private set; } - async ValueTask IValueTaskTypeInitializer.InitializeAsync() + async ValueTask IValueTaskInitializer.InitializeAsync() { await Task.Delay(TimeSpan.FromMilliseconds(500)).ConfigureAwait(false); IsInitialized = true; diff --git a/Test/Async/Wrapped/ValueTaskToValueTask.cs b/Test/Async/Wrapped/ValueTaskToValueTask.cs index 20283842..bd265997 100644 --- a/Test/Async/Wrapped/ValueTaskToValueTask.cs +++ b/Test/Async/Wrapped/ValueTaskToValueTask.cs @@ -5,11 +5,11 @@ namespace MrMeeseeks.DIE.Test.Async.Wrapped.ValueTaskToValueTask; -internal class Dependency : IValueTaskTypeInitializer +internal class Dependency : IValueTaskInitializer { public bool IsInitialized { get; private set; } - async ValueTask IValueTaskTypeInitializer.InitializeAsync() + async ValueTask IValueTaskInitializer.InitializeAsync() { await Task.Delay(TimeSpan.FromMilliseconds(500)).ConfigureAwait(false); IsInitialized = true; diff --git a/Test/Func/AsyncWrapped/MultipleTaskAtStart.cs b/Test/Func/AsyncWrapped/MultipleTaskAtStart.cs index 931c4cac..13087ee2 100644 --- a/Test/Func/AsyncWrapped/MultipleTaskAtStart.cs +++ b/Test/Func/AsyncWrapped/MultipleTaskAtStart.cs @@ -5,7 +5,7 @@ namespace MrMeeseeks.DIE.Test.Func.AsyncWrapped.MultipleTaskAtStart; -internal class Dependency : IValueTaskTypeInitializer +internal class Dependency : IValueTaskInitializer { public ValueTask InitializeAsync() { diff --git a/Test/Func/AsyncWrapped/MultipleValueTaskAtStart.cs b/Test/Func/AsyncWrapped/MultipleValueTaskAtStart.cs index cb828495..2fdbd8da 100644 --- a/Test/Func/AsyncWrapped/MultipleValueTaskAtStart.cs +++ b/Test/Func/AsyncWrapped/MultipleValueTaskAtStart.cs @@ -5,7 +5,7 @@ namespace MrMeeseeks.DIE.Test.Func.AsyncWrapped.MultipleValueTaskAtStart; -internal class Dependency : IValueTaskTypeInitializer +internal class Dependency : IValueTaskInitializer { public ValueTask InitializeAsync() { diff --git a/Test/Func/AsyncWrapped/SingleTask.cs b/Test/Func/AsyncWrapped/SingleTask.cs index a0140240..861b40e5 100644 --- a/Test/Func/AsyncWrapped/SingleTask.cs +++ b/Test/Func/AsyncWrapped/SingleTask.cs @@ -5,7 +5,7 @@ namespace MrMeeseeks.DIE.Test.Func.AsyncWrapped.SingleTask; -internal class Dependency : IValueTaskTypeInitializer +internal class Dependency : IValueTaskInitializer { public ValueTask InitializeAsync() { diff --git a/Test/Func/AsyncWrapped/SingleValueTask.cs b/Test/Func/AsyncWrapped/SingleValueTask.cs index 2d769e57..cdf0e1ba 100644 --- a/Test/Func/AsyncWrapped/SingleValueTask.cs +++ b/Test/Func/AsyncWrapped/SingleValueTask.cs @@ -5,7 +5,7 @@ namespace MrMeeseeks.DIE.Test.Func.AsyncWrapped.SingleValueTask; -internal class Dependency : IValueTaskTypeInitializer +internal class Dependency : IValueTaskInitializer { public ValueTask InitializeAsync() { diff --git a/Test/Generics/Configuration/InitializerImplementationAsync.cs b/Test/Generics/Configuration/InitializerImplementationAsync.cs index 2838ac39..b642530d 100644 --- a/Test/Generics/Configuration/InitializerImplementationAsync.cs +++ b/Test/Generics/Configuration/InitializerImplementationAsync.cs @@ -15,7 +15,7 @@ internal async Task InitializeAsync() public bool IsInitialized { get; private set; } } -[TypeInitializer(typeof(Dependency<>), nameof(Dependency.InitializeAsync))] +[Initializer(typeof(Dependency<>), nameof(Dependency.InitializeAsync))] [CreateFunction(typeof(Dependency), "Create")] internal sealed partial class Container { diff --git a/Test/Generics/Configuration/InitializerImplementationAsyncValue.cs b/Test/Generics/Configuration/InitializerImplementationAsyncValue.cs index 68ba4f83..6458cb99 100644 --- a/Test/Generics/Configuration/InitializerImplementationAsyncValue.cs +++ b/Test/Generics/Configuration/InitializerImplementationAsyncValue.cs @@ -15,7 +15,7 @@ internal async ValueTask InitializeAsync() public bool IsInitialized { get; private set; } } -[TypeInitializer(typeof(Dependency<>), nameof(Dependency.InitializeAsync))] +[Initializer(typeof(Dependency<>), nameof(Dependency.InitializeAsync))] [CreateFunction(typeof(Dependency), "Create")] internal sealed partial class Container { diff --git a/Test/Generics/Configuration/InitializerImplementationSync.cs b/Test/Generics/Configuration/InitializerImplementationSync.cs index 6b5bb1ea..bbed4024 100644 --- a/Test/Generics/Configuration/InitializerImplementationSync.cs +++ b/Test/Generics/Configuration/InitializerImplementationSync.cs @@ -14,7 +14,7 @@ internal void Initialize() public bool IsInitialized { get; private set; } } -[TypeInitializer(typeof(Dependency<>), nameof(Dependency.Initialize))] +[Initializer(typeof(Dependency<>), nameof(Dependency.Initialize))] [CreateFunction(typeof(Dependency), "Create")] internal sealed partial class Container { diff --git a/Test/Generics/Configuration/InitializerInterfaceAsync.cs b/Test/Generics/Configuration/InitializerInterfaceAsync.cs index 18a5524d..713b8cad 100644 --- a/Test/Generics/Configuration/InitializerInterfaceAsync.cs +++ b/Test/Generics/Configuration/InitializerInterfaceAsync.cs @@ -4,9 +4,9 @@ namespace MrMeeseeks.DIE.Test.Generics.Configuration.InitializerInterfaceAsync; -internal class Dependency : ITaskTypeInitializer +internal class Dependency : ITaskInitializer { - async Task ITaskTypeInitializer.InitializeAsync() + async Task ITaskInitializer.InitializeAsync() { await Task.Delay(500).ConfigureAwait(false); IsInitialized = true; diff --git a/Test/Generics/Configuration/InitializerInterfaceAsyncValue.cs b/Test/Generics/Configuration/InitializerInterfaceAsyncValue.cs index 4e7abafc..df5589f1 100644 --- a/Test/Generics/Configuration/InitializerInterfaceAsyncValue.cs +++ b/Test/Generics/Configuration/InitializerInterfaceAsyncValue.cs @@ -4,9 +4,9 @@ namespace MrMeeseeks.DIE.Test.Generics.Configuration.InitializerInterfaceAsyncValue; -internal class Dependency : IValueTaskTypeInitializer +internal class Dependency : IValueTaskInitializer { - async ValueTask IValueTaskTypeInitializer.InitializeAsync() + async ValueTask IValueTaskInitializer.InitializeAsync() { await Task.Delay(500).ConfigureAwait(false); IsInitialized = true; diff --git a/Test/Generics/Configuration/InitializerInterfaceSync.cs b/Test/Generics/Configuration/InitializerInterfaceSync.cs index 9f9eb390..67c85309 100644 --- a/Test/Generics/Configuration/InitializerInterfaceSync.cs +++ b/Test/Generics/Configuration/InitializerInterfaceSync.cs @@ -4,9 +4,9 @@ namespace MrMeeseeks.DIE.Test.Generics.Configuration.InitializerInterfaceSync; -internal class Dependency : ITypeInitializer +internal class Dependency : IInitializer { - void ITypeInitializer.Initialize() + void IInitializer.Initialize() { IsInitialized = true; } diff --git a/Test/TypeInitializer/AsyncTask.cs b/Test/Initializer/AsyncTask.cs similarity index 78% rename from Test/TypeInitializer/AsyncTask.cs rename to Test/Initializer/AsyncTask.cs index 5d1234e4..17be0e23 100644 --- a/Test/TypeInitializer/AsyncTask.cs +++ b/Test/Initializer/AsyncTask.cs @@ -2,13 +2,13 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.TypeInitializer.AsyncTask; +namespace MrMeeseeks.DIE.Test.Initializer.AsyncTask; -internal class Dependency : ITaskTypeInitializer +internal class Dependency : ITaskInitializer { public bool IsInitialized { get; private set; } - Task ITaskTypeInitializer.InitializeAsync() + Task ITaskInitializer.InitializeAsync() { IsInitialized = true; return Task.CompletedTask; diff --git a/Test/TypeInitializer/AsyncValueTask.cs b/Test/Initializer/AsyncValueTask.cs similarity index 77% rename from Test/TypeInitializer/AsyncValueTask.cs rename to Test/Initializer/AsyncValueTask.cs index 5e3771ff..adfb3d47 100644 --- a/Test/TypeInitializer/AsyncValueTask.cs +++ b/Test/Initializer/AsyncValueTask.cs @@ -2,13 +2,13 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.TypeInitializer.AsyncValueTask; +namespace MrMeeseeks.DIE.Test.Initializer.AsyncValueTask; -internal class Dependency : IValueTaskTypeInitializer +internal class Dependency : IValueTaskInitializer { public bool IsInitialized { get; private set; } - ValueTask IValueTaskTypeInitializer.InitializeAsync() + ValueTask IValueTaskInitializer.InitializeAsync() { IsInitialized = true; return ValueTask.CompletedTask; diff --git a/Test/TypeInitializer/Sync.cs b/Test/Initializer/Sync.cs similarity index 74% rename from Test/TypeInitializer/Sync.cs rename to Test/Initializer/Sync.cs index 521f5e5d..da686846 100644 --- a/Test/TypeInitializer/Sync.cs +++ b/Test/Initializer/Sync.cs @@ -2,13 +2,13 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.TypeInitializer.Sync; +namespace MrMeeseeks.DIE.Test.Initializer.Sync; -internal class Dependency : ITypeInitializer +internal class Dependency : IInitializer { public bool IsInitialized { get; private set; } - void ITypeInitializer.Initialize() => IsInitialized = true; + void IInitializer.Initialize() => IsInitialized = true; } [CreateFunction(typeof(Dependency), "Create")] diff --git a/Test/Initializer/WithParameters.cs b/Test/Initializer/WithParameters.cs new file mode 100644 index 00000000..22afa772 --- /dev/null +++ b/Test/Initializer/WithParameters.cs @@ -0,0 +1,42 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Initializer.WithParameters; + +internal class Dependency +{ + public bool IsInitialized { get; private set; } + + public int Number { get; private set; } + + public string Text { get; private set; } = ""; + + internal void Initialize(int number, string text) + { + IsInitialized = true; + Number = number; + Text = text; + } +} + +[Initializer(typeof(Dependency), nameof(Dependency.Initialize))] +[CreateFunction(typeof(Dependency), "Create")] +internal sealed partial class Container +{ + private readonly int DIE_Factory_Number = 69; + private readonly string DIE_Factory_Text = "foo"; +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var instance = container.Create(); + Assert.True(instance.IsInitialized); + Assert.Equal(69, instance.Number); + Assert.Equal("foo", instance.Text); + } +} \ No newline at end of file diff --git a/Test/Lazy/AsyncWrapped/MultipleTaskAtStart.cs b/Test/Lazy/AsyncWrapped/MultipleTaskAtStart.cs index f7b5507e..95f6fe02 100644 --- a/Test/Lazy/AsyncWrapped/MultipleTaskAtStart.cs +++ b/Test/Lazy/AsyncWrapped/MultipleTaskAtStart.cs @@ -5,7 +5,7 @@ namespace MrMeeseeks.DIE.Test.Lazy.AsyncWrapped.MultipleTaskAtStart; -internal class Dependency : IValueTaskTypeInitializer +internal class Dependency : IValueTaskInitializer { public ValueTask InitializeAsync() { diff --git a/Test/Lazy/AsyncWrapped/MultipleValueTaskAtStart.cs b/Test/Lazy/AsyncWrapped/MultipleValueTaskAtStart.cs index 25a2757c..8096ba38 100644 --- a/Test/Lazy/AsyncWrapped/MultipleValueTaskAtStart.cs +++ b/Test/Lazy/AsyncWrapped/MultipleValueTaskAtStart.cs @@ -5,7 +5,7 @@ namespace MrMeeseeks.DIE.Test.Lazy.AsyncWrapped.MultipleValueTaskAtStart; -internal class Dependency : IValueTaskTypeInitializer +internal class Dependency : IValueTaskInitializer { public ValueTask InitializeAsync() { diff --git a/Test/Lazy/AsyncWrapped/SingleTask.cs b/Test/Lazy/AsyncWrapped/SingleTask.cs index 8e044bd2..cf71b505 100644 --- a/Test/Lazy/AsyncWrapped/SingleTask.cs +++ b/Test/Lazy/AsyncWrapped/SingleTask.cs @@ -5,7 +5,7 @@ namespace MrMeeseeks.DIE.Test.Lazy.AsyncWrapped.SingleTask; -internal class Dependency : IValueTaskTypeInitializer +internal class Dependency : IValueTaskInitializer { public ValueTask InitializeAsync() { diff --git a/Test/Lazy/AsyncWrapped/SingleValueTask.cs b/Test/Lazy/AsyncWrapped/SingleValueTask.cs index f1e11c50..175ed7fa 100644 --- a/Test/Lazy/AsyncWrapped/SingleValueTask.cs +++ b/Test/Lazy/AsyncWrapped/SingleValueTask.cs @@ -5,7 +5,7 @@ namespace MrMeeseeks.DIE.Test.Lazy.AsyncWrapped.SingleValueTask; -internal class Dependency : IValueTaskTypeInitializer +internal class Dependency : IValueTaskInitializer { public ValueTask InitializeAsync() { diff --git a/Test/MarkerInterfaces.cs b/Test/MarkerInterfaces.cs index ce8d1b99..b5c90aae 100644 --- a/Test/MarkerInterfaces.cs +++ b/Test/MarkerInterfaces.cs @@ -12,15 +12,15 @@ public interface ISyncTransient { } public interface IAsyncTransient { } public interface IDecorator { } public interface IComposite { } -public interface ITypeInitializer +public interface IInitializer { void Initialize(); } -public interface ITaskTypeInitializer +public interface ITaskInitializer { Task InitializeAsync(); } -public interface IValueTaskTypeInitializer +public interface IValueTaskInitializer { ValueTask InitializeAsync(); } \ No newline at end of file diff --git a/Test/UserDefinedElements/InjectionConstrParams/Vanilla.cs b/Test/UserDefinedElements/InjectionConstrParams/Vanilla.cs index 32776d25..63771d41 100644 --- a/Test/UserDefinedElements/InjectionConstrParams/Vanilla.cs +++ b/Test/UserDefinedElements/InjectionConstrParams/Vanilla.cs @@ -15,7 +15,7 @@ internal class Dependency internal sealed partial class Container { [UserDefinedConstructorParametersInjection(typeof(Dependency))] - private void DIE_ConstrParam_Dependency(out int number) => number = 69; + private void DIE_ConstrParams_Dependency(out int number) => number = 69; } public class Tests diff --git a/Test/UserDefinedElements/InjectionConstrParams/VanillaInScope.cs b/Test/UserDefinedElements/InjectionConstrParams/VanillaInScope.cs index 759cb4d0..67c34e95 100644 --- a/Test/UserDefinedElements/InjectionConstrParams/VanillaInScope.cs +++ b/Test/UserDefinedElements/InjectionConstrParams/VanillaInScope.cs @@ -25,7 +25,7 @@ internal sealed partial class Container private sealed partial class DIE_DefaultScope { [UserDefinedConstructorParametersInjection(typeof(Dependency))] - private void DIE_ConstrParam_Dependency(out int number) => number = 69; + private void DIE_ConstrParams_Dependency(out int number) => number = 69; } } diff --git a/Test/UserDefinedElements/InjectionConstrParams/VanillaInTransientScope.cs b/Test/UserDefinedElements/InjectionConstrParams/VanillaInTransientScope.cs index e22b8397..fc4ec87b 100644 --- a/Test/UserDefinedElements/InjectionConstrParams/VanillaInTransientScope.cs +++ b/Test/UserDefinedElements/InjectionConstrParams/VanillaInTransientScope.cs @@ -25,7 +25,7 @@ internal sealed partial class Container private sealed partial class DIE_DefaultTransientScope { [UserDefinedConstructorParametersInjection(typeof(Dependency))] - private void DIE_ConstrParam_Dependency(out int number) => number = 69; + private void DIE_ConstrParams_Dependency(out int number) => number = 69; } } diff --git a/Test/UserDefinedElements/InjectionConstrParams/WithAsyncDependency.cs b/Test/UserDefinedElements/InjectionConstrParams/WithAsyncDependency.cs index e931a774..e17c0e2d 100644 --- a/Test/UserDefinedElements/InjectionConstrParams/WithAsyncDependency.cs +++ b/Test/UserDefinedElements/InjectionConstrParams/WithAsyncDependency.cs @@ -11,7 +11,7 @@ internal class Dependency internal Dependency(int number) => Number = number; } -internal class OtherDependency : IValueTaskTypeInitializer +internal class OtherDependency : IValueTaskInitializer { public int Number => 69; public ValueTask InitializeAsync() => new (Task.CompletedTask); @@ -21,7 +21,7 @@ internal class OtherDependency : IValueTaskTypeInitializer internal sealed partial class Container { [UserDefinedConstructorParametersInjection(typeof(Dependency))] - private void DIE_ConstrParam_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; + private void DIE_ConstrParams_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; } public class Tests diff --git a/Test/UserDefinedElements/InjectionConstrParams/WithAsyncDependencyInScope.cs b/Test/UserDefinedElements/InjectionConstrParams/WithAsyncDependencyInScope.cs index a9481ffe..5cfff15a 100644 --- a/Test/UserDefinedElements/InjectionConstrParams/WithAsyncDependencyInScope.cs +++ b/Test/UserDefinedElements/InjectionConstrParams/WithAsyncDependencyInScope.cs @@ -11,7 +11,7 @@ internal class Dependency internal Dependency(int number) => Number = number; } -internal class OtherDependency : IValueTaskTypeInitializer +internal class OtherDependency : IValueTaskInitializer { public int Number => 69; public ValueTask InitializeAsync() => new (Task.CompletedTask); @@ -31,7 +31,7 @@ internal sealed partial class Container private sealed partial class DIE_DefaultScope { [UserDefinedConstructorParametersInjection(typeof(Dependency))] - private void DIE_ConstrParam_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; + private void DIE_ConstrParams_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; } } diff --git a/Test/UserDefinedElements/InjectionConstrParams/WithAsyncDependencyInTransientScope.cs b/Test/UserDefinedElements/InjectionConstrParams/WithAsyncDependencyInTransientScope.cs index d6c01b73..85135f11 100644 --- a/Test/UserDefinedElements/InjectionConstrParams/WithAsyncDependencyInTransientScope.cs +++ b/Test/UserDefinedElements/InjectionConstrParams/WithAsyncDependencyInTransientScope.cs @@ -11,7 +11,7 @@ internal class Dependency internal Dependency(int number) => Number = number; } -internal class OtherDependency : IValueTaskTypeInitializer +internal class OtherDependency : IValueTaskInitializer { public int Number => 69; public ValueTask InitializeAsync() => new (Task.CompletedTask); @@ -31,7 +31,7 @@ internal sealed partial class Container private sealed partial class DIE_DefaultTransientScope { [UserDefinedConstructorParametersInjection(typeof(Dependency))] - private void DIE_ConstrParam_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; + private void DIE_ConstrParams_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; } } diff --git a/Test/UserDefinedElements/InjectionConstrParams/WithDependency.cs b/Test/UserDefinedElements/InjectionConstrParams/WithDependency.cs index b02179d3..3f8f1970 100644 --- a/Test/UserDefinedElements/InjectionConstrParams/WithDependency.cs +++ b/Test/UserDefinedElements/InjectionConstrParams/WithDependency.cs @@ -20,7 +20,7 @@ internal class OtherDependency internal sealed partial class Container { [UserDefinedConstructorParametersInjection(typeof(Dependency))] - private void DIE_ConstrParam_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; + private void DIE_ConstrParams_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; } public class Tests diff --git a/Test/UserDefinedElements/InjectionConstrParams/WithDependencyInScope.cs b/Test/UserDefinedElements/InjectionConstrParams/WithDependencyInScope.cs index 02903f73..52953ba0 100644 --- a/Test/UserDefinedElements/InjectionConstrParams/WithDependencyInScope.cs +++ b/Test/UserDefinedElements/InjectionConstrParams/WithDependencyInScope.cs @@ -30,7 +30,7 @@ internal sealed partial class Container private sealed partial class DIE_DefaultScope { [UserDefinedConstructorParametersInjection(typeof(Dependency))] - private void DIE_ConstrParam_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; + private void DIE_ConstrParams_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; } } diff --git a/Test/UserDefinedElements/InjectionConstrParams/WithDependencyInTransientScope.cs b/Test/UserDefinedElements/InjectionConstrParams/WithDependencyInTransientScope.cs index 38db7e81..50ed9aac 100644 --- a/Test/UserDefinedElements/InjectionConstrParams/WithDependencyInTransientScope.cs +++ b/Test/UserDefinedElements/InjectionConstrParams/WithDependencyInTransientScope.cs @@ -30,7 +30,7 @@ internal sealed partial class Container private sealed partial class DIE_DefaultTransientScope { [UserDefinedConstructorParametersInjection(typeof(Dependency))] - private void DIE_ConstrParam_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; + private void DIE_ConstrParams_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; } } diff --git a/Test/UserDefinedElements/InjectionInitParams/Vanilla.cs b/Test/UserDefinedElements/InjectionInitParams/Vanilla.cs new file mode 100644 index 00000000..43cba0c2 --- /dev/null +++ b/Test/UserDefinedElements/InjectionInitParams/Vanilla.cs @@ -0,0 +1,31 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.UserDefinedElements.InjectionInitParams.Vanilla; + +internal class Dependency +{ + public int Number { get; private set; } + + internal void Initialize(int number) => Number = number; +} + +[Initializer(typeof(Dependency), nameof(Dependency.Initialize))] +[CreateFunction(typeof(Dependency), "Create")] +internal sealed partial class Container +{ + [UserDefinedInitializerParametersInjection(typeof(Dependency))] + private void DIE_InitParams_Dependency(out int number) => number = 69; +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var instance = container.Create(); + Assert.Equal(69, instance.Number); + } +} \ No newline at end of file diff --git a/Test/UserDefinedElements/InjectionInitParams/VanillaInScope.cs b/Test/UserDefinedElements/InjectionInitParams/VanillaInScope.cs new file mode 100644 index 00000000..229f66e1 --- /dev/null +++ b/Test/UserDefinedElements/InjectionInitParams/VanillaInScope.cs @@ -0,0 +1,42 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.UserDefinedElements.InjectionInitParams.VanillaInScope; + +internal class Dependency +{ + public int Number { get; private set; } + + internal void Initialize(int number) => Number = number; +} + +internal class ScopeRoot : IScopeRoot +{ + public Dependency Dependency { get; } + + internal ScopeRoot( + Dependency dependency) => Dependency = dependency; +} + +[Initializer(typeof(Dependency), nameof(Dependency.Initialize))] +[CreateFunction(typeof(ScopeRoot), "Create")] +internal sealed partial class Container +{ + private sealed partial class DIE_DefaultScope + { + [UserDefinedInitializerParametersInjection(typeof(Dependency))] + private void DIE_InitParams_Dependency(out int number) => number = 69; + } +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var instance = container.Create().Dependency; + Assert.Equal(69, instance.Number); + } +} \ No newline at end of file diff --git a/Test/UserDefinedElements/InjectionInitParams/VanillaInTransientScope.cs b/Test/UserDefinedElements/InjectionInitParams/VanillaInTransientScope.cs new file mode 100644 index 00000000..e8a30a73 --- /dev/null +++ b/Test/UserDefinedElements/InjectionInitParams/VanillaInTransientScope.cs @@ -0,0 +1,42 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.UserDefinedElements.InjectionInitParams.VanillaInTransientScope; + +internal class Dependency +{ + public int Number { get; private set; } + + internal void Initialize(int number) => Number = number; +} + +internal class TransientScopeRoot : ITransientScopeRoot +{ + public Dependency Dependency { get; } + + internal TransientScopeRoot( + Dependency dependency) => Dependency = dependency; +} + +[Initializer(typeof(Dependency), nameof(Dependency.Initialize))] +[CreateFunction(typeof(TransientScopeRoot), "Create")] +internal sealed partial class Container +{ + private sealed partial class DIE_DefaultTransientScope + { + [UserDefinedInitializerParametersInjection(typeof(Dependency))] + private void DIE_InitParams_Dependency(out int number) => number = 69; + } +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var instance = container.Create().Dependency; + Assert.Equal(69, instance.Number); + } +} \ No newline at end of file diff --git a/Test/UserDefinedElements/InjectionInitParams/WithAsyncDependency.cs b/Test/UserDefinedElements/InjectionInitParams/WithAsyncDependency.cs new file mode 100644 index 00000000..69fb8eda --- /dev/null +++ b/Test/UserDefinedElements/InjectionInitParams/WithAsyncDependency.cs @@ -0,0 +1,37 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.UserDefinedElements.InjectionInitParams.WithAsyncDependency; + +internal class Dependency +{ + public int Number { get; private set; } + + internal void Initialize(int number) => Number = number; +} + +internal class OtherDependency : IValueTaskInitializer +{ + public int Number => 69; + public ValueTask InitializeAsync() => new (Task.CompletedTask); +} + +[Initializer(typeof(Dependency), nameof(Dependency.Initialize))] +[CreateFunction(typeof(Dependency), "Create")] +internal sealed partial class Container +{ + [UserDefinedInitializerParametersInjection(typeof(Dependency))] + private void DIE_InitParams_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var instance = await container.CreateAsync().ConfigureAwait(false); + Assert.Equal(69, instance.Number); + } +} \ No newline at end of file diff --git a/Test/UserDefinedElements/InjectionInitParams/WithAsyncDependencyInScope.cs b/Test/UserDefinedElements/InjectionInitParams/WithAsyncDependencyInScope.cs new file mode 100644 index 00000000..a8fc96dc --- /dev/null +++ b/Test/UserDefinedElements/InjectionInitParams/WithAsyncDependencyInScope.cs @@ -0,0 +1,48 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.UserDefinedElements.InjectionInitParams.WithAsyncDependencyInScope; + +internal class Dependency +{ + public int Number { get; private set; } + + internal void Initialize(int number) => Number = number; +} + +internal class OtherDependency : IValueTaskInitializer +{ + public int Number => 69; + public ValueTask InitializeAsync() => new (Task.CompletedTask); +} + +internal class ScopeRoot : IScopeRoot +{ + public Dependency Dependency { get; } + + internal ScopeRoot( + Dependency dependency) => Dependency = dependency; +} + +[Initializer(typeof(Dependency), nameof(Dependency.Initialize))] +[CreateFunction(typeof(ScopeRoot), "Create")] +internal sealed partial class Container +{ + private sealed partial class DIE_DefaultScope + { + [UserDefinedInitializerParametersInjection(typeof(Dependency))] + private void DIE_InitParams_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; + } +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var instance = await container.CreateAsync().ConfigureAwait(false); + Assert.Equal(69, instance.Dependency.Number); + } +} \ No newline at end of file diff --git a/Test/UserDefinedElements/InjectionInitParams/WithAsyncDependencyInTransientScope.cs b/Test/UserDefinedElements/InjectionInitParams/WithAsyncDependencyInTransientScope.cs new file mode 100644 index 00000000..217372b3 --- /dev/null +++ b/Test/UserDefinedElements/InjectionInitParams/WithAsyncDependencyInTransientScope.cs @@ -0,0 +1,48 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.UserDefinedElements.InjectionInitParams.WithAsyncDependencyInTransientScope; + +internal class Dependency +{ + public int Number { get; private set; } + + internal void Initialize(int number) => Number = number; +} + +internal class OtherDependency : IValueTaskInitializer +{ + public int Number => 69; + public ValueTask InitializeAsync() => new (Task.CompletedTask); +} + +internal class TransientScopeRoot : ITransientScopeRoot +{ + public Dependency Dependency { get; } + + internal TransientScopeRoot( + Dependency dependency) => Dependency = dependency; +} + +[Initializer(typeof(Dependency), nameof(Dependency.Initialize))] +[CreateFunction(typeof(TransientScopeRoot), "Create")] +internal sealed partial class Container +{ + private sealed partial class DIE_DefaultTransientScope + { + [UserDefinedInitializerParametersInjection(typeof(Dependency))] + private void DIE_InitParams_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; + } +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var instance = await container.CreateAsync().ConfigureAwait(false); + Assert.Equal(69, instance.Dependency.Number); + } +} \ No newline at end of file diff --git a/Test/UserDefinedElements/InjectionInitParams/WithDependency.cs b/Test/UserDefinedElements/InjectionInitParams/WithDependency.cs new file mode 100644 index 00000000..45a6e3ae --- /dev/null +++ b/Test/UserDefinedElements/InjectionInitParams/WithDependency.cs @@ -0,0 +1,36 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.UserDefinedElements.InjectionInitParams.WithDependency; + +internal class Dependency +{ + public int Number { get; private set; } + + internal void Initialize(int number) => Number = number; +} + +internal class OtherDependency +{ + public int Number => 69; +} + +[Initializer(typeof(Dependency), nameof(Dependency.Initialize))] +[CreateFunction(typeof(Dependency), "Create")] +internal sealed partial class Container +{ + [UserDefinedInitializerParametersInjection(typeof(Dependency))] + private void DIE_InitParams_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var instance = container.Create(); + Assert.Equal(69, instance.Number); + } +} \ No newline at end of file diff --git a/Test/UserDefinedElements/InjectionInitParams/WithDependencyInScope.cs b/Test/UserDefinedElements/InjectionInitParams/WithDependencyInScope.cs new file mode 100644 index 00000000..1f25f459 --- /dev/null +++ b/Test/UserDefinedElements/InjectionInitParams/WithDependencyInScope.cs @@ -0,0 +1,47 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.UserDefinedElements.InjectionInitParams.WithDependencyInScope; + +internal class Dependency +{ + public int Number { get; private set; } + + internal void Initialize(int number) => Number = number; +} + +internal class OtherDependency +{ + public int Number => 69; +} + +internal class ScopeRoot : IScopeRoot +{ + public Dependency Dependency { get; } + + internal ScopeRoot( + Dependency dependency) => Dependency = dependency; +} + +[Initializer(typeof(Dependency), nameof(Dependency.Initialize))] +[CreateFunction(typeof(ScopeRoot), "Create")] +internal sealed partial class Container +{ + private sealed partial class DIE_DefaultScope + { + [UserDefinedInitializerParametersInjection(typeof(Dependency))] + private void DIE_InitParams_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; + } +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var instance = container.Create(); + Assert.Equal(69, instance.Dependency.Number); + } +} \ No newline at end of file diff --git a/Test/UserDefinedElements/InjectionInitParams/WithDependencyInTransientScope.cs b/Test/UserDefinedElements/InjectionInitParams/WithDependencyInTransientScope.cs new file mode 100644 index 00000000..25c1f9d8 --- /dev/null +++ b/Test/UserDefinedElements/InjectionInitParams/WithDependencyInTransientScope.cs @@ -0,0 +1,47 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.UserDefinedElements.InjectionInitParams.WithDependencyInTransientScope; + +internal class Dependency +{ + public int Number { get; private set; } + + internal void Initialize(int number) => Number = number; +} + +internal class OtherDependency +{ + public int Number => 69; +} + +internal class TransientScopeRoot : ITransientScopeRoot +{ + public Dependency Dependency { get; } + + internal TransientScopeRoot( + Dependency dependency) => Dependency = dependency; +} + +[Initializer(typeof(Dependency), nameof(Dependency.Initialize))] +[CreateFunction(typeof(TransientScopeRoot), "Create")] +internal sealed partial class Container +{ + private sealed partial class DIE_DefaultTransientScope + { + [UserDefinedInitializerParametersInjection(typeof(Dependency))] + private void DIE_InitParams_Dependency(OtherDependency otherDependency, out int number) => number = otherDependency.Number; + } +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var instance = container.Create(); + Assert.Equal(69, instance.Dependency.Number); + } +} \ No newline at end of file diff --git a/Test/UserDefinedElements/InjectionProps/WithAsyncDependency.cs b/Test/UserDefinedElements/InjectionProps/WithAsyncDependency.cs index 2a774382..7a3a8b06 100644 --- a/Test/UserDefinedElements/InjectionProps/WithAsyncDependency.cs +++ b/Test/UserDefinedElements/InjectionProps/WithAsyncDependency.cs @@ -9,7 +9,7 @@ internal class Dependency public int Number { get; init; } } -internal class OtherDependency : IValueTaskTypeInitializer +internal class OtherDependency : IValueTaskInitializer { public int Number => 69; public ValueTask InitializeAsync() => new (Task.CompletedTask); diff --git a/Test/UserDefinedElements/InjectionProps/WithAsyncDependencyInScope.cs b/Test/UserDefinedElements/InjectionProps/WithAsyncDependencyInScope.cs index 1b849aa7..f063efa5 100644 --- a/Test/UserDefinedElements/InjectionProps/WithAsyncDependencyInScope.cs +++ b/Test/UserDefinedElements/InjectionProps/WithAsyncDependencyInScope.cs @@ -9,7 +9,7 @@ internal class Dependency public int Number { get; init; } } -internal class OtherDependency : IValueTaskTypeInitializer +internal class OtherDependency : IValueTaskInitializer { public int Number => 69; public ValueTask InitializeAsync() => new (Task.CompletedTask); diff --git a/Test/UserDefinedElements/InjectionProps/WithAsyncDependencyInTransientScope.cs b/Test/UserDefinedElements/InjectionProps/WithAsyncDependencyInTransientScope.cs index 681c7f90..b5d7e30d 100644 --- a/Test/UserDefinedElements/InjectionProps/WithAsyncDependencyInTransientScope.cs +++ b/Test/UserDefinedElements/InjectionProps/WithAsyncDependencyInTransientScope.cs @@ -9,7 +9,7 @@ internal class Dependency public int Number { get; init; } } -internal class OtherDependency : IValueTaskTypeInitializer +internal class OtherDependency : IValueTaskInitializer { public int Number => 69; public ValueTask InitializeAsync() => new (Task.CompletedTask); From 996aeaaff61bb13ed9b0d429b730493f7b00dbc8 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Thu, 8 Sep 2022 22:48:24 +0200 Subject: [PATCH 132/162] Fixed disposal handling --- Main/CodeBuilding/ContainerCodeBuilder.cs | 14 ++-- Main/CodeBuilding/RangeCodeBaseBuilder.cs | 82 ++++++++----------- Main/CodeBuilding/ScopeCodeBuilder.cs | 8 +- .../CodeBuilding/TransientScopeCodeBuilder.cs | 10 +-- Main/Configuration/CheckTypeProperties.cs | 15 ++-- .../ContainerResolutionBuilder.cs | 5 +- .../Function/FunctionResolutionBuilder.cs | 2 +- Main/ResolutionTreeItem.cs | 2 +- Test/Disposal/Calls/AsyncOnly.cs | 43 ++++++++++ Test/Disposal/Calls/Both.cs | 43 ++++++++++ Test/Disposal/Calls/None.cs | 43 ++++++++++ Test/Disposal/Calls/SyncOnly.cs | 43 ++++++++++ 12 files changed, 233 insertions(+), 77 deletions(-) create mode 100644 Test/Disposal/Calls/AsyncOnly.cs create mode 100644 Test/Disposal/Calls/Both.cs create mode 100644 Test/Disposal/Calls/None.cs create mode 100644 Test/Disposal/Calls/SyncOnly.cs diff --git a/Main/CodeBuilding/ContainerCodeBuilder.cs b/Main/CodeBuilding/ContainerCodeBuilder.cs index 7db1b9a3..4ead6f12 100644 --- a/Main/CodeBuilding/ContainerCodeBuilder.cs +++ b/Main/CodeBuilding/ContainerCodeBuilder.cs @@ -20,7 +20,7 @@ protected override StringBuilder GenerateDisposalFunction_TransientScopeDictiona if (_containerResolution.DisposalType is DisposalType.None) return stringBuilder; - var dictionaryTypeName = _containerResolution.DisposalType is DisposalType.Async + var dictionaryTypeName = _containerResolution.DisposalType.HasFlag(DisposalType.Async) ? WellKnownTypes.ConcurrentDictionaryOfAsyncDisposable.FullName() : WellKnownTypes.ConcurrentDictionaryOfSyncDisposable.FullName(); @@ -37,8 +37,8 @@ protected override StringBuilder GenerateDisposalFunction_TransientScopeDisposal var elementName = _containerResolution.TransientScopeDisposalElement; - var asyncSuffix = _containerResolution.DisposalType is DisposalType.Async ? "Async" : ""; - var awaitPrefix = _containerResolution.DisposalType is DisposalType.Async ? "await " : ""; + var asyncSuffix = _containerResolution.DisposalType.HasFlag(DisposalType.Async) ? "Async" : ""; + var awaitPrefix = _containerResolution.DisposalType.HasFlag(DisposalType.Async) ? "await " : ""; stringBuilder .AppendLine($"while ({_containerResolution.TransientScopeDisposalReference}.Count > 0)") @@ -58,11 +58,9 @@ protected override StringBuilder GenerateDisposalFunction_TransientScopeDisposal public override StringBuilder Build(StringBuilder stringBuilder) { - var disposableImplementation = _containerResolution.DisposalType switch - { - DisposalType.Async => $" : {WellKnownTypes.AsyncDisposable.FullName()}", - _ => $" : {WellKnownTypes.AsyncDisposable.FullName()}, {WellKnownTypes.Disposable.FullName()}" - }; + var disposableImplementation = _containerResolution.DisposalType.HasFlag(DisposalType.Async) + ? $" : {WellKnownTypes.AsyncDisposable.FullName()}" + : $" : {WellKnownTypes.AsyncDisposable.FullName()}, {WellKnownTypes.Disposable.FullName()}"; stringBuilder = stringBuilder .AppendLine($"#nullable enable") diff --git a/Main/CodeBuilding/RangeCodeBaseBuilder.cs b/Main/CodeBuilding/RangeCodeBaseBuilder.cs index daa51fe7..18fc16a0 100644 --- a/Main/CodeBuilding/RangeCodeBaseBuilder.cs +++ b/Main/CodeBuilding/RangeCodeBaseBuilder.cs @@ -76,27 +76,21 @@ private StringBuilder GenerateDisposalFunction( .AppendLine("}"); } - var returnType = _containerResolution.DisposalType switch - { - DisposalType.Async => $"async {WellKnownTypes.ValueTask.FullName()}", - _ => "void" - }; + var returnType = _containerResolution.DisposalType.HasFlag(DisposalType.Async) + ? $"async {WellKnownTypes.ValueTask.FullName()}" + : "void"; - var asyncSuffix = _containerResolution.DisposalType switch - { - DisposalType.Async => "Async", - _ => "" - }; + var asyncSuffix = _containerResolution.DisposalType.HasFlag(DisposalType.Async) + ? "Async" + : ""; - var awaitPrefix = _containerResolution.DisposalType switch - { - DisposalType.Async => "await ", - _ => "" - }; + var awaitPrefix = _containerResolution.DisposalType.HasFlag(DisposalType.Async) + ? "await " + : ""; stringBuilder = GenerateDisposalFunction_TransientScopeDictionary(stringBuilder); - if (_containerResolution.DisposalType == DisposalType.Async) + if (_containerResolution.DisposalType.HasFlag(DisposalType.Async)) { stringBuilder = stringBuilder.AppendLine( $"private {disposalHandling.AsyncDisposableCollection.TypeFullName} {disposalHandling.AsyncDisposableCollection.Reference} = new {disposalHandling.AsyncDisposableCollection.TypeFullName}();"); @@ -121,7 +115,7 @@ private StringBuilder GenerateDisposalFunction( stringBuilder = GenerateDisposalFunction_TransientScopeDisposal(stringBuilder); - if (_containerResolution.DisposalType == DisposalType.Async) + if (_containerResolution.DisposalType.HasFlag(DisposalType.Async)) { stringBuilder = stringBuilder .AppendLine( @@ -164,7 +158,8 @@ private StringBuilder GenerateDisposalFunction( stringBuilder = stringBuilder .AppendLine($"}}") .AppendLine($"}}"); - if (_containerResolution.DisposalType == DisposalType.Sync) + if (_containerResolution.DisposalType.HasFlag(DisposalType.Sync) + && !_containerResolution.DisposalType.HasFlag(DisposalType.Async)) stringBuilder = stringBuilder .AppendLine($"public {WellKnownTypes.ValueTask.FullName()} DisposeAsync()") .AppendLine($"{{") @@ -345,7 +340,7 @@ private StringBuilder GenerateResolutions( .AppendLine($"{transientScopeTypeFullName} {transientScopeReference} = new {transientScopeTypeFullName}({containerInstanceScopeReference});"); if (_containerResolution.DisposalType is not DisposalType.None) { - var disposalType = _containerResolution.DisposalType is DisposalType.Async + var disposalType = _containerResolution.DisposalType.HasFlag(DisposalType.Async) ? WellKnownTypes.AsyncDisposable.FullName() : WellKnownTypes.Disposable.FullName(); stringBuilder = stringBuilder @@ -357,9 +352,9 @@ private StringBuilder GenerateResolutions( case ScopeRootResolution(var scopeReference, var scopeTypeFullName, var containerInstanceScopeReference, var transientInstanceScopeReference, var createFunctionCall): stringBuilder = stringBuilder .AppendLine($"{scopeTypeFullName} {scopeReference} = new {scopeTypeFullName}({containerInstanceScopeReference}, {transientInstanceScopeReference});"); - if (_containerResolution.DisposalType is DisposalType.Async) + if (_containerResolution.DisposalType.HasFlag(DisposalType.Async)) stringBuilder = stringBuilder.AppendLine($"{_rangeResolution.DisposalHandling.AsyncDisposableCollection.Reference}.Add(({WellKnownTypes.AsyncDisposable.FullName()}) {scopeReference});"); - if (_containerResolution.DisposalType is DisposalType.Sync) + else if (_containerResolution.DisposalType.HasFlag(DisposalType.Sync)) stringBuilder = stringBuilder.AppendLine($"{_rangeResolution.DisposalHandling.SyncDisposableCollection.Reference}.Add(({WellKnownTypes.Disposable.FullName()}) {scopeReference});"); stringBuilder = GenerateResolutions(stringBuilder, createFunctionCall); break; @@ -368,23 +363,21 @@ private StringBuilder GenerateResolutions( stringBuilder = stringBuilder.AppendLine( $"{typeFullName} {reference} = ({typeFullName}) {resolutionBase.Reference};"); break; - case TransientScopeAsDisposableResolution(var reference, var typeFullName): - stringBuilder = _containerResolution.DisposalType switch - { - DisposalType.Async => throw new Exception("If the container disposal has to be async, then sync disposal handles in transient scopes are not allowed."), - DisposalType.Sync => stringBuilder.AppendLine($"{typeFullName} {reference} = ({typeFullName}) this;"), - DisposalType.None => stringBuilder.AppendLine($"{typeFullName} {reference} = ({typeFullName}) {_containerResolution.NopDisposable.ClassName}.{_containerResolution.NopDisposable.InstanceReference};"), - _ => stringBuilder - }; + case TransientScopeAsSyncDisposableResolution(var reference, var typeFullName): + if (_containerResolution.DisposalType.HasFlag(DisposalType.Async)) + throw new Exception("If the container disposal has to be async, then sync disposal handles in transient scopes are not allowed."); + else if (_containerResolution.DisposalType.HasFlag(DisposalType.Sync)) + stringBuilder.AppendLine($"{typeFullName} {reference} = ({typeFullName}) this;"); + else + stringBuilder.AppendLine($"{typeFullName} {reference} = ({typeFullName}) {_containerResolution.NopDisposable.ClassName}.{_containerResolution.NopDisposable.InstanceReference};"); break; case TransientScopeAsAsyncDisposableResolution(var reference, var typeFullName): - stringBuilder = _containerResolution.DisposalType switch - { - DisposalType.Async => stringBuilder.AppendLine($"{typeFullName} {reference} = ({typeFullName}) this;"), - DisposalType.Sync => stringBuilder.AppendLine($"{typeFullName} {reference} = ({typeFullName}) new {_containerResolution.SyncToAsyncDisposable.ClassName}(({WellKnownTypes.Disposable.FullName()}) this);"), - DisposalType.None => stringBuilder.AppendLine($"{typeFullName} {reference} = ({typeFullName}) {_containerResolution.NopAsyncDisposable.ClassName}.{_containerResolution.NopAsyncDisposable.InstanceReference};"), - _ => stringBuilder - }; + if (_containerResolution.DisposalType.HasFlag(DisposalType.Async)) + stringBuilder.AppendLine($"{typeFullName} {reference} = ({typeFullName}) this;"); + else if (_containerResolution.DisposalType.HasFlag(DisposalType.Sync)) + stringBuilder.AppendLine($"{typeFullName} {reference} = ({typeFullName}) new {_containerResolution.SyncToAsyncDisposable.ClassName}(({WellKnownTypes.Disposable.FullName()}) this);"); + else + stringBuilder.AppendLine($"{typeFullName} {reference} = ({typeFullName}) {_containerResolution.NopAsyncDisposable.ClassName}.{_containerResolution.NopAsyncDisposable.InstanceReference};"); break; case OutParameterResolution(var reference, var typeFullName): stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference};"); @@ -418,16 +411,13 @@ private StringBuilder GenerateResolutions( : ""; stringBuilder = stringBuilder.AppendLine( $"{typeFullName} {reference} = new {typeFullName}({constructorParameter}){objectInitializerParameter};"); - if (disposalType is not DisposalType.None) - { - var interfaceType = disposalType is DisposalType.Sync - ? WellKnownTypes.Disposable.FullName() - : WellKnownTypes.AsyncDisposable.FullName(); - var disposableCollectionReference = disposalType is DisposalType.Sync - ? _rangeResolution.DisposalHandling.SyncDisposableCollection.Reference - : _rangeResolution.DisposalHandling.AsyncDisposableCollection.Reference; - stringBuilder = stringBuilder.AppendLine($"{disposableCollectionReference}.Add(({interfaceType}) {reference});"); - } + + if (disposalType.HasFlag(DisposalType.Async)) + stringBuilder = stringBuilder.AppendLine( + $"{_rangeResolution.DisposalHandling.AsyncDisposableCollection.Reference}.Add(({WellKnownTypes.AsyncDisposable.FullName()}) {reference});"); + if (disposalType.HasFlag(DisposalType.Sync)) + stringBuilder = stringBuilder.AppendLine( + $"{_rangeResolution.DisposalHandling.SyncDisposableCollection.Reference}.Add(({WellKnownTypes.Disposable.FullName()}) {reference});"); if (initialization is { Parameters: {} initParameters }) { diff --git a/Main/CodeBuilding/ScopeCodeBuilder.cs b/Main/CodeBuilding/ScopeCodeBuilder.cs index 0f88e39a..3c277f57 100644 --- a/Main/CodeBuilding/ScopeCodeBuilder.cs +++ b/Main/CodeBuilding/ScopeCodeBuilder.cs @@ -22,11 +22,9 @@ internal class ScopeCodeBuilder : RangeCodeBaseBuilder, IScopeCodeBuilder public override StringBuilder Build(StringBuilder stringBuilder) { - var disposableImplementation = _containerResolution.DisposalType switch - { - DisposalType.Async => $" : {WellKnownTypes.AsyncDisposable.FullName()}", - _ => $" : {WellKnownTypes.AsyncDisposable.FullName()}, {WellKnownTypes.Disposable.FullName()}" - }; + var disposableImplementation = _containerResolution.DisposalType.HasFlag(DisposalType.Async) + ? $" : {WellKnownTypes.AsyncDisposable.FullName()}" + : $" : {WellKnownTypes.AsyncDisposable.FullName()}, {WellKnownTypes.Disposable.FullName()}"; stringBuilder = stringBuilder .AppendLine( diff --git a/Main/CodeBuilding/TransientScopeCodeBuilder.cs b/Main/CodeBuilding/TransientScopeCodeBuilder.cs index 2f484062..16f55975 100644 --- a/Main/CodeBuilding/TransientScopeCodeBuilder.cs +++ b/Main/CodeBuilding/TransientScopeCodeBuilder.cs @@ -20,7 +20,7 @@ protected override StringBuilder GenerateDisposalFunction_TransientScopeDisposal if (_containerResolution.DisposalType is DisposalType.None) return stringBuilder; - var disposalType = _containerResolution.DisposalType is DisposalType.Async + var disposalType = _containerResolution.DisposalType.HasFlag(DisposalType.Async) ? WellKnownTypes.AsyncDisposable.FullName() : WellKnownTypes.Disposable.FullName(); @@ -34,11 +34,9 @@ protected override StringBuilder GenerateDisposalFunction_TransientScopeDisposal public override StringBuilder Build(StringBuilder stringBuilder) { - var disposableImplementation = _containerResolution.DisposalType switch - { - DisposalType.Async => $", {WellKnownTypes.AsyncDisposable.FullName()}", - _ => $", {WellKnownTypes.AsyncDisposable.FullName()}, {WellKnownTypes.Disposable.FullName()}" - }; + var disposableImplementation = _containerResolution.DisposalType.HasFlag(DisposalType.Async) + ? $", {WellKnownTypes.AsyncDisposable.FullName()}" + : $", {WellKnownTypes.AsyncDisposable.FullName()}, {WellKnownTypes.Disposable.FullName()}"; stringBuilder = stringBuilder .AppendLine($"private partial class {_transientScopeResolution.Name} : {_containerResolution.TransientScopeInterface.Name}{disposableImplementation}") diff --git a/Main/Configuration/CheckTypeProperties.cs b/Main/Configuration/CheckTypeProperties.cs index 2d5b0a24..69bf3f07 100644 --- a/Main/Configuration/CheckTypeProperties.cs +++ b/Main/Configuration/CheckTypeProperties.cs @@ -10,11 +10,12 @@ internal enum ScopeLevel Container } +[Flags] internal enum DisposalType { - None, - Sync, - Async + None = 0, + Sync = 1, + Async = 2 } internal interface ICheckTypeProperties @@ -52,16 +53,18 @@ public DisposalType ShouldDisposalBeManaged(INamedTypeSymbol implementationType) { if (implementationType.TypeKind is TypeKind.Struct or TypeKind.Structure) return DisposalType.None; + + var ret = DisposalType.None; if (implementationType.AllInterfaces.Contains(_wellKnownTypes.AsyncDisposable) && !_currentlyConsideredTypes.AsyncTransientTypes.Contains(implementationType.UnboundIfGeneric())) - return DisposalType.Async; + ret |= DisposalType.Async; if (implementationType.AllInterfaces.Contains(_wellKnownTypes.Disposable) && !_currentlyConsideredTypes.SyncTransientTypes.Contains(implementationType.UnboundIfGeneric())) - return DisposalType.Sync; + ret |= DisposalType.Sync; - return DisposalType.None; + return ret; } public ScopeLevel ShouldBeScopeRoot(INamedTypeSymbol implementationType) diff --git a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs index 2fc0150a..4b913e79 100644 --- a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs @@ -124,10 +124,7 @@ public override ScopeRootResolution CreateScopeRootResolution( _transientScopeAdapterReference, currentParameters); - public override void RegisterDisposalType(DisposalType disposalType) - { - if (disposalType > _disposalType) _disposalType = disposalType; - } + public override void RegisterDisposalType(DisposalType disposalType) => _disposalType |= disposalType; public bool HasWorkToDo => _rootResolutions.Any(r => r.CreateFunction.HasWorkToDo) diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs index 9774cbfe..d619164c 100644 --- a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs @@ -1099,7 +1099,7 @@ false when initializationMethod.ReturnType.Equals(_wellKnownTypes.ValueTask, Sym if (isTransientScopeRoot && typeSymbol.Equals(_wellKnownTypes.Disposable, SymbolEqualityComparer.Default)) - return (parameterName, new TransientScopeAsDisposableResolution( + return (parameterName, new TransientScopeAsSyncDisposableResolution( RootReferenceGenerator.Generate(_wellKnownTypes.Disposable), _wellKnownTypes.Disposable.FullName())); diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index 566527cb..893f5fe6 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -54,7 +54,7 @@ internal record RangedInstanceFunctionGroupResolution( string? IsCreatedForStructs, bool IsTransientScopeInstance); -internal record TransientScopeAsDisposableResolution( +internal record TransientScopeAsSyncDisposableResolution( string Reference, string TypeFullName) : Resolvable(Reference, TypeFullName); diff --git a/Test/Disposal/Calls/AsyncOnly.cs b/Test/Disposal/Calls/AsyncOnly.cs new file mode 100644 index 00000000..c7bab767 --- /dev/null +++ b/Test/Disposal/Calls/AsyncOnly.cs @@ -0,0 +1,43 @@ +using System; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Disposal.Calls.Async; + +internal class Dependency : IDisposable, IAsyncDisposable, ISyncTransient +{ + public bool IsSyncDisposedCalled { get; private set; } + + public bool IsAsyncDisposedCalled { get; private set; } + + public void Dispose() + { + IsSyncDisposedCalled = true; + } + + public async ValueTask DisposeAsync() + { + await Task.Yield(); + IsAsyncDisposedCalled = true; + } +} + +[CreateFunction(typeof(Dependency), "Create")] +internal sealed partial class Container +{ + +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var dependency = container.Create(); + await container.DisposeAsync().ConfigureAwait(false); + Assert.True(dependency.IsAsyncDisposedCalled); + Assert.False(dependency.IsSyncDisposedCalled); + } +} \ No newline at end of file diff --git a/Test/Disposal/Calls/Both.cs b/Test/Disposal/Calls/Both.cs new file mode 100644 index 00000000..cee2b2d0 --- /dev/null +++ b/Test/Disposal/Calls/Both.cs @@ -0,0 +1,43 @@ +using System; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Disposal.Calls.Both; + +internal class Dependency : IDisposable, IAsyncDisposable +{ + public bool IsSyncDisposedCalled { get; private set; } + + public bool IsAsyncDisposedCalled { get; private set; } + + public void Dispose() + { + IsSyncDisposedCalled = true; + } + + public async ValueTask DisposeAsync() + { + await Task.Yield(); + IsAsyncDisposedCalled = true; + } +} + +[CreateFunction(typeof(Dependency), "Create")] +internal sealed partial class Container +{ + +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var dependency = container.Create(); + await container.DisposeAsync().ConfigureAwait(false); + Assert.True(dependency.IsAsyncDisposedCalled); + Assert.True(dependency.IsSyncDisposedCalled); + } +} \ No newline at end of file diff --git a/Test/Disposal/Calls/None.cs b/Test/Disposal/Calls/None.cs new file mode 100644 index 00000000..a5c23093 --- /dev/null +++ b/Test/Disposal/Calls/None.cs @@ -0,0 +1,43 @@ +using System; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Disposal.Calls.None; + +internal class Dependency : IDisposable, IAsyncDisposable, ITransient +{ + public bool IsSyncDisposedCalled { get; private set; } + + public bool IsAsyncDisposedCalled { get; private set; } + + public void Dispose() + { + IsSyncDisposedCalled = true; + } + + public async ValueTask DisposeAsync() + { + await Task.Yield(); + IsAsyncDisposedCalled = true; + } +} + +[CreateFunction(typeof(Dependency), "Create")] +internal sealed partial class Container +{ + +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var dependency = container.Create(); + await container.DisposeAsync().ConfigureAwait(false); + Assert.False(dependency.IsAsyncDisposedCalled); + Assert.False(dependency.IsSyncDisposedCalled); + } +} \ No newline at end of file diff --git a/Test/Disposal/Calls/SyncOnly.cs b/Test/Disposal/Calls/SyncOnly.cs new file mode 100644 index 00000000..b2968526 --- /dev/null +++ b/Test/Disposal/Calls/SyncOnly.cs @@ -0,0 +1,43 @@ +using System; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Disposal.Calls.Sync; + +internal class Dependency : IDisposable, IAsyncDisposable, IAsyncTransient +{ + public bool IsSyncDisposedCalled { get; private set; } + + public bool IsAsyncDisposedCalled { get; private set; } + + public void Dispose() + { + IsSyncDisposedCalled = true; + } + + public async ValueTask DisposeAsync() + { + await Task.Yield(); + IsAsyncDisposedCalled = true; + } +} + +[CreateFunction(typeof(Dependency), "Create")] +internal sealed partial class Container +{ + +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var dependency = container.Create(); + await container.DisposeAsync().ConfigureAwait(false); + Assert.False(dependency.IsAsyncDisposedCalled); + Assert.True(dependency.IsSyncDisposedCalled); + } +} \ No newline at end of file From 59a0e5b0a89912e8dc976ec1d19b3396874dce62 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sat, 10 Sep 2022 11:38:38 +0200 Subject: [PATCH 133/162] Supporting array types in collection injections and as Func-override --- Main/ContainerInfo.cs | 10 ++-- Main/ReferenceGenerator.cs | 22 ++++++--- .../ContainerResolutionBuilder.cs | 6 +-- .../Function/FunctionResolutionBuilder.cs | 49 +++++++++++-------- .../LocalFunctionResolutionBuilder.cs | 4 +- .../RangeResolutionBaseBuilder.cs | 8 +-- .../ScopeResolutionBuilder.cs | 2 +- .../TransientScopeResolutionBuilder.cs | 2 +- Main/SourceGenerator.cs | 2 +- Main/Utility/FunctionResolutionUtility.cs | 2 +- Sample/Container.cs | 27 ++-------- Test/Abstraction/ArrayType.cs | 30 ++++++++++++ Test/Func/WithArrayParameter.cs | 34 +++++++++++++ Test/Implementation/ArrayType.cs | 21 ++++++++ 14 files changed, 150 insertions(+), 69 deletions(-) create mode 100644 Test/Abstraction/ArrayType.cs create mode 100644 Test/Func/WithArrayParameter.cs create mode 100644 Test/Implementation/ArrayType.cs diff --git a/Main/ContainerInfo.cs b/Main/ContainerInfo.cs index e93142d0..761a9df6 100644 --- a/Main/ContainerInfo.cs +++ b/Main/ContainerInfo.cs @@ -6,7 +6,7 @@ internal interface IContainerInfo string Namespace { get; } string FullName { get; } INamedTypeSymbol ContainerType { get; } - IReadOnlyList<(INamedTypeSymbol, string)> CreateFunctionData { get; } + IReadOnlyList<(ITypeSymbol, string)> CreateFunctionData { get; } } internal class ContainerInfo : IContainerInfo @@ -28,12 +28,12 @@ internal ContainerInfo( .Where(ad => wellKnowTypesMiscellaneous.CreateFunctionAttribute.Equals(ad.AttributeClass, SymbolEqualityComparer.Default)) .Select(ad => ad.ConstructorArguments.Length == 2 && ad.ConstructorArguments[0].Kind == TypedConstantKind.Type - && ad.ConstructorArguments[0].Value is INamedTypeSymbol type + && ad.ConstructorArguments[0].Value is ITypeSymbol type && ad.ConstructorArguments[1].Kind == TypedConstantKind.Primitive && ad.ConstructorArguments[1].Value is string methodNamePrefix ? (type, methodNamePrefix) - : ((INamedTypeSymbol, string)?) null) - .OfType<(INamedTypeSymbol, string)>() + : ((ITypeSymbol, string)?) null) + .OfType<(ITypeSymbol, string)>() .ToList(); } @@ -41,5 +41,5 @@ internal ContainerInfo( public string Namespace { get; } public string FullName { get; } public INamedTypeSymbol ContainerType { get; } - public IReadOnlyList<(INamedTypeSymbol, string)> CreateFunctionData { get; } + public IReadOnlyList<(ITypeSymbol, string)> CreateFunctionData { get; } } \ No newline at end of file diff --git a/Main/ReferenceGenerator.cs b/Main/ReferenceGenerator.cs index ef4540f3..b50e799b 100644 --- a/Main/ReferenceGenerator.cs +++ b/Main/ReferenceGenerator.cs @@ -15,14 +15,20 @@ internal class ReferenceGenerator : IReferenceGenerator internal ReferenceGenerator(int j) => _j = j; - public string Generate(ITypeSymbol type) => - GenerateInner( - string.Empty, - type.Name is { Length: > 1 } - ? $"{char.ToLower(type.Name[0])}{type.Name.Substring(1)}" - : "empty", // todo warning type without name seems strange - string.Empty); - + public string Generate(ITypeSymbol type) + { + var baseName = type switch + { + INamedTypeSymbol namedTypeSymbol => + $"{char.ToLower(namedTypeSymbol.Name[0])}{namedTypeSymbol.Name.Substring(1)}", + IArrayTypeSymbol { ElementType: {} elementType } => + $"{char.ToLower(elementType.Name[0])}{elementType.Name.Substring(1)}Array", + _ => "empty" // todo warning type without name seems strange + }; + + return GenerateInner(string.Empty, baseName, string.Empty); + } + public string Generate(string prefix, ITypeSymbol type) => GenerateInner(prefix, type.Name, string.Empty); diff --git a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs index 4b913e79..7c06e142 100644 --- a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs @@ -5,7 +5,7 @@ namespace MrMeeseeks.DIE.ResolutionBuilding; internal interface IContainerResolutionBuilder : IRangeResolutionBaseBuilder, IResolutionBuilder { - void AddCreateResolveFunctions(IReadOnlyList<(INamedTypeSymbol, string)> createFunctionData); + void AddCreateResolveFunctions(IReadOnlyList<(ITypeSymbol, string)> createFunctionData); MultiSynchronicityFunctionCallResolution CreateContainerInstanceReferenceResolution( ForConstructorParameter parameter, @@ -40,7 +40,7 @@ internal ContainerResolutionBuilder( Func synchronicityDecisionMakerFactory, Func< IRangeResolutionBaseBuilder, - INamedTypeSymbol, + ITypeSymbol, ImmutableSortedDictionary, string, ICreateFunctionResolutionBuilder> localFunctionResolutionBuilderFactory, @@ -70,7 +70,7 @@ internal ContainerResolutionBuilder( containerInfo.ContainerType.Locations.FirstOrDefault() ?? Location.None); } - public void AddCreateResolveFunctions(IReadOnlyList<(INamedTypeSymbol, string)> createFunctionData) + public void AddCreateResolveFunctions(IReadOnlyList<(ITypeSymbol, string)> createFunctionData) { foreach (var (typeSymbol, methodNamePrefix) in createFunctionData) _rootResolutions.Add((CreateCreateFunctionResolution( diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs index d619164c..b12a63a0 100644 --- a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs @@ -45,8 +45,8 @@ public void Register(IAwaitableResolution awaitableResolution) internal interface IFunctionResolutionBuilder : IResolutionBuilder { - INamedTypeSymbol OriginalReturnType { get; } - INamedTypeSymbol? ActualReturnType { get; } + ITypeSymbol OriginalReturnType { get; } + ITypeSymbol? ActualReturnType { get; } IReadOnlyList Parameters { get; } IReadOnlyList<(ITypeSymbol, ParameterResolution)> CurrentParameters { get; } @@ -81,13 +81,13 @@ internal abstract partial class FunctionResolutionBuilder : IFunctionResolutionB public IReadOnlyList Parameters { get; } - public INamedTypeSymbol OriginalReturnType { get; } - public INamedTypeSymbol? ActualReturnType { get; protected set; } + public ITypeSymbol OriginalReturnType { get; } + public ITypeSymbol? ActualReturnType { get; protected set; } internal FunctionResolutionBuilder( // parameters IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, - INamedTypeSymbol returnType, + ITypeSymbol returnType, ImmutableSortedDictionary currentParameters, IFunctionResolutionSynchronicityDecisionMaker synchronicityDecisionMaker, object handleIdentity, @@ -363,17 +363,17 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup .Select(ts => (Type: ts, Resolution: new ParameterResolution(RootReferenceGenerator.Generate(ts), ts.FullName()))) .ToArray(); - var setOfProcessedTypes = new HashSet(SymbolEqualityComparer.IncludeNullability); + var setOfProcessedTypes = new HashSet(SymbolEqualityComparer.IncludeNullability); var nextCurrentParameters = currentFuncParameters; foreach (var lambdaParameter in lambdaParameters) { if (setOfProcessedTypes.Contains(lambdaParameter.Type, SymbolEqualityComparer.IncludeNullability) - || lambdaParameter.Type is not INamedTypeSymbol lambdaType) + || lambdaParameter.Type is not INamedTypeSymbol && lambdaParameter.Type is not IArrayTypeSymbol) continue; - setOfProcessedTypes.Add(lambdaType); + setOfProcessedTypes.Add(lambdaParameter.Type); nextCurrentParameters = nextCurrentParameters.SetItem(lambdaParameter.Type.FullName(), lambdaParameter); } @@ -389,25 +389,34 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup if (type.OriginalDefinition.Equals(_wellKnownTypes.Enumerable1, SymbolEqualityComparer.Default) || type.OriginalDefinition.Equals(_wellKnownTypes.ReadOnlyCollection1, SymbolEqualityComparer.Default) - || type.OriginalDefinition.Equals(_wellKnownTypes.ReadOnlyList1, SymbolEqualityComparer.Default)) + || type.OriginalDefinition.Equals(_wellKnownTypes.ReadOnlyList1, SymbolEqualityComparer.Default) + || type is IArrayTypeSymbol) { - if (type is not INamedTypeSymbol collectionType) + if (type is not INamedTypeSymbol && type is not IArrayTypeSymbol) { return ( new ErrorTreeItem(Diagnostics.CompilationError( ErrorMessage(implementationStack, type, "Collection: Collection is not a named type symbol"), _rangeResolutionBaseBuilder.ErrorContext.Location)), null); } - if (collectionType.TypeArguments.SingleOrDefault() is not INamedTypeSymbol wrappedType) + + INamedTypeSymbol wrappedType; + switch (type) { - return (new ErrorTreeItem(Diagnostics.CompilationError(collectionType.TypeArguments.Length switch - { - 0 => ErrorMessage(implementationStack, type, "Collection: No item type argument"), - >1 => ErrorMessage(implementationStack, type, "Collection: More than one item type argument"), - _ => ErrorMessage(implementationStack, type, $"Collection: {collectionType.TypeArguments[0].FullName()} is not a named type symbol") - }, _rangeResolutionBaseBuilder.ErrorContext.Location)), - null); + case INamedTypeSymbol collectionType + when collectionType.TypeArguments.SingleOrDefault() is INamedTypeSymbol innerType: + wrappedType = innerType; + break; + case IArrayTypeSymbol { ElementType: INamedTypeSymbol innerType1 }: + wrappedType = innerType1; + break; + default: + return (new ErrorTreeItem(Diagnostics.CompilationError( + "Collection: Item type couldn't be determined", + _rangeResolutionBaseBuilder.ErrorContext.Location)), + null); } + ITypeSymbol wrappedItemTypeSymbol = wrappedType; ITypeSymbol unwrappedItemTypeSymbol = wrappedType; TaskType? taskType = null; @@ -1109,7 +1118,7 @@ false when initializationMethod.ReturnType.Equals(_wellKnownTypes.ValueTask, Sym RootReferenceGenerator.Generate(_wellKnownTypes.AsyncDisposable), _wellKnownTypes.AsyncDisposable.FullName())); - if (typeSymbol is not INamedTypeSymbol parameterType) + if (typeSymbol is not INamedTypeSymbol && typeSymbol is not IArrayTypeSymbol) return ("", new ErrorTreeItem(Diagnostics.CompilationError( ErrorMessage(implementationStack, typeSymbol, $"Class.Constructor.Parameter: Parameter type {typeSymbol.FullName()} is not a named type symbol"), _rangeResolutionBaseBuilder.ErrorContext.Location))); @@ -1117,7 +1126,7 @@ false when initializationMethod.ReturnType.Equals(_wellKnownTypes.ValueTask, Sym return ( parameterName, SwitchType(new SwitchTypeParameter( - parameterType, + typeSymbol, currParameter, implementationStack)).Item1); } diff --git a/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs index c0930438..49e9e7ce 100644 --- a/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs @@ -6,13 +6,13 @@ internal interface ICreateFunctionResolutionBuilder : IFunctionResolutionBuilder internal class CreateFunctionResolutionBuilder : FunctionResolutionBuilder, ICreateFunctionResolutionBuilder { - private readonly INamedTypeSymbol _returnType; + private readonly ITypeSymbol _returnType; private readonly string _accessModifier; public CreateFunctionResolutionBuilder( // parameter IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, - INamedTypeSymbol returnType, + ITypeSymbol returnType, ImmutableSortedDictionary parameters, IFunctionResolutionSynchronicityDecisionMaker synchronicityDecisionMaker, string accessModifier, diff --git a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs index 818bc057..71580bca 100644 --- a/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs +++ b/Main/ResolutionBuilding/RangeResolutionBaseBuilder.cs @@ -33,7 +33,7 @@ ScopeRootResolution CreateScopeRootResolution( void RegisterDisposalType(DisposalType disposalType); IFunctionResolutionBuilder CreateCreateFunctionResolution( - INamedTypeSymbol type, + ITypeSymbol type, ImmutableSortedDictionary currentParameters, string accessModifier); } @@ -51,7 +51,7 @@ internal abstract class RangeResolutionBaseBuilder : IRangeResolutionBaseBuilder private readonly Func _rangedFunctionGroupResolutionBuilderFactory; private readonly Func< IRangeResolutionBaseBuilder, - INamedTypeSymbol, + ITypeSymbol, ImmutableSortedDictionary, string, ICreateFunctionResolutionBuilder> _localFunctionResolutionBuilderFactory; @@ -78,7 +78,7 @@ protected RangeResolutionBaseBuilder( Func synchronicityDecisionMakerFactory, Func< IRangeResolutionBaseBuilder, - INamedTypeSymbol, + ITypeSymbol, ImmutableSortedDictionary, string, ICreateFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) @@ -124,7 +124,7 @@ public abstract ScopeRootResolution CreateScopeRootResolution( public abstract void RegisterDisposalType(DisposalType disposalType); public IFunctionResolutionBuilder CreateCreateFunctionResolution( - INamedTypeSymbol type, + ITypeSymbol type, ImmutableSortedDictionary currentParameters, string accessModifier) => FunctionResolutionUtility.GetOrCreateFunction( diff --git a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs index 58eaabea..931c1fbf 100644 --- a/Main/ResolutionBuilding/ScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ScopeResolutionBuilder.cs @@ -43,7 +43,7 @@ internal ScopeResolutionBuilder( Func synchronicityDecisionMakerFactory, Func< IRangeResolutionBaseBuilder, - INamedTypeSymbol, + ITypeSymbol, ImmutableSortedDictionary, string, ICreateFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) diff --git a/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs b/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs index 17e06535..fc4c09a2 100644 --- a/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs +++ b/Main/ResolutionBuilding/TransientScopeResolutionBuilder.cs @@ -40,7 +40,7 @@ internal TransientScopeResolutionBuilder( Func synchronicityDecisionMakerFactory, Func< IRangeResolutionBaseBuilder, - INamedTypeSymbol, + ITypeSymbol, ImmutableSortedDictionary, string, ICreateFunctionResolutionBuilder> localFunctionResolutionBuilderFactory) diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index cfbff0a6..75b2dbe7 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -221,7 +221,7 @@ IScopeResolutionBuilder ScopeResolutionBuilderFactory( ICreateFunctionResolutionBuilder CreateFunctionResolutionBuilderFactory( IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, - INamedTypeSymbol returnType, + ITypeSymbol returnType, ImmutableSortedDictionary parameters, string accessModifier) => new CreateFunctionResolutionBuilder( rangeResolutionBaseBuilder, diff --git a/Main/Utility/FunctionResolutionUtility.cs b/Main/Utility/FunctionResolutionUtility.cs index 7e6a5d3f..d4889e9f 100644 --- a/Main/Utility/FunctionResolutionUtility.cs +++ b/Main/Utility/FunctionResolutionUtility.cs @@ -6,7 +6,7 @@ internal static class FunctionResolutionUtility { internal static T GetOrCreateFunction( IDictionary functionMap, - INamedTypeSymbol type, + ITypeSymbol type, ImmutableSortedDictionary currentParameters, Func functionFactory) where T : IFunctionResolutionBuilder diff --git a/Sample/Container.cs b/Sample/Container.cs index c0d1c937..3b1c6c47 100644 --- a/Sample/Container.cs +++ b/Sample/Container.cs @@ -1,27 +1,8 @@ using MrMeeseeks.DIE.Configuration.Attributes; -namespace MrMeeseeks.DIE.Test.Initializer.WithParameters; +namespace MrMeeseeks.DIE.Test.Implementation.ArrayType; -internal class Dependency -{ - public bool IsInitialized { get; private set; } +internal class Dependency {} - public int Number { get; private set; } - - public string Text { get; private set; } = ""; - - internal void Initialize(int number, string text) - { - IsInitialized = true; - Number = number; - Text = text; - } -} - -[Initializer(typeof(Dependency), nameof(Dependency.Initialize))] -[CreateFunction(typeof(Dependency), "Create")] -internal sealed partial class Container -{ - private readonly int DIE_Factory_Number = 69; - private readonly string DIE_Factory_Text = "foo"; -} \ No newline at end of file +[CreateFunction(typeof(Dependency[]), "Create")] +internal sealed partial class Container {} \ No newline at end of file diff --git a/Test/Abstraction/ArrayType.cs b/Test/Abstraction/ArrayType.cs new file mode 100644 index 00000000..93775ffd --- /dev/null +++ b/Test/Abstraction/ArrayType.cs @@ -0,0 +1,30 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Abstraction.ArrayType; + +internal interface IInterface {} + +internal class DependencyA : IInterface {} + +internal class DependencyB : IInterface {} + +internal class DependencyC : IInterface {} + +[CreateFunction(typeof(IInterface[]), "Create")] +internal sealed partial class Container {} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var instance = container.Create(); + Assert.Equal(3, instance.Length); + Assert.IsAssignableFrom(instance[0]); + Assert.IsAssignableFrom(instance[0]); + Assert.IsAssignableFrom(instance[0]); + } +} \ No newline at end of file diff --git a/Test/Func/WithArrayParameter.cs b/Test/Func/WithArrayParameter.cs new file mode 100644 index 00000000..5e168eb5 --- /dev/null +++ b/Test/Func/WithArrayParameter.cs @@ -0,0 +1,34 @@ +using System; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Func.WithArrayParameter; + +internal class ParameterDependency {} + +internal class Dependency +{ + internal Dependency(ParameterDependency[] parameters){} +} + +[CreateFunction(typeof(Func), "Create")] +[CreateFunction(typeof(ParameterDependency), "CreateParameter")] +internal sealed partial class Container +{ +} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var _ = container.Create()(new [] + { + container.CreateParameter(), + container.CreateParameter(), + container.CreateParameter() + }); + } +} diff --git a/Test/Implementation/ArrayType.cs b/Test/Implementation/ArrayType.cs new file mode 100644 index 00000000..ddf8b601 --- /dev/null +++ b/Test/Implementation/ArrayType.cs @@ -0,0 +1,21 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Implementation.ArrayType; + +internal class Dependency {} + +[CreateFunction(typeof(Dependency[]), "Create")] +internal sealed partial class Container {} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var instance = container.Create(); + Assert.IsType(instance[0]); + } +} \ No newline at end of file From 609e3d6f9bb4a3c6e8f376c64d7a0b6e54708ec9 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sat, 10 Sep 2022 12:23:14 +0200 Subject: [PATCH 134/162] Fixing bug with ungeneric implementations and generic interface --- Main/Configuration/CheckTypeProperties.cs | 11 +++++--- Sample/Container.cs | 12 ++++++--- ...UngenericImplementationGenericInterface.cs | 27 +++++++++++++++++++ 3 files changed, 43 insertions(+), 7 deletions(-) create mode 100644 Test/Bugs/UngenericImplementationGenericInterface.cs diff --git a/Main/Configuration/CheckTypeProperties.cs b/Main/Configuration/CheckTypeProperties.cs index 69bf3f07..cbbaeb66 100644 --- a/Main/Configuration/CheckTypeProperties.cs +++ b/Main/Configuration/CheckTypeProperties.cs @@ -272,15 +272,18 @@ private IReadOnlyList GetClosedImplementations( var ret = new List(); foreach (var implementation in rawImplementations) { + var unboundImplementation = implementation.UnboundIfGeneric(); + var originalImplementation = implementation.OriginalDefinitionIfUnbound(); + if (!implementation.IsGenericType || implementation.TypeArguments.All(ta => ta is INamedTypeSymbol and not IErrorTypeSymbol)) { - AddImplementation(ret, implementation); + if (originalImplementation.AllDerivedTypesAndSelf() + .FirstOrDefault(t => + SymbolEqualityComparer.Default.Equals(t, targetType)) is { }) + AddImplementation(ret, implementation); continue; } - var unboundImplementation = implementation.UnboundIfGeneric(); - var originalImplementation = implementation.OriginalDefinitionIfUnbound(); - if (originalImplementation.AllDerivedTypesAndSelf() .FirstOrDefault(t => SymbolEqualityComparer.Default.Equals(t.UnboundIfGeneric(), unboundTargetType)) is { } implementationsTarget) diff --git a/Sample/Container.cs b/Sample/Container.cs index 3b1c6c47..3e8d5176 100644 --- a/Sample/Container.cs +++ b/Sample/Container.cs @@ -1,8 +1,14 @@ using MrMeeseeks.DIE.Configuration.Attributes; -namespace MrMeeseeks.DIE.Test.Implementation.ArrayType; +namespace MrMeeseeks.DIE.Test.Bugs.UngenericImplementationGenericInterface; -internal class Dependency {} +internal interface IInterface {} -[CreateFunction(typeof(Dependency[]), "Create")] +internal class DependencyA : IInterface {} + +internal class DependencyB : IInterface {} + +internal class DependencyC : IInterface {} + +[CreateFunction(typeof(IInterface), "Create")] internal sealed partial class Container {} \ No newline at end of file diff --git a/Test/Bugs/UngenericImplementationGenericInterface.cs b/Test/Bugs/UngenericImplementationGenericInterface.cs new file mode 100644 index 00000000..208db73c --- /dev/null +++ b/Test/Bugs/UngenericImplementationGenericInterface.cs @@ -0,0 +1,27 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Bugs.UngenericImplementationGenericInterface; + +internal interface IInterface {} + +internal class DependencyA : IInterface {} + +internal class DependencyB : IInterface {} + +internal class DependencyC : IInterface {} + +[CreateFunction(typeof(IInterface), "Create")] +internal sealed partial class Container {} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var instance = container.Create(); + Assert.IsType(instance); + } +} \ No newline at end of file From b9bfde3055b136d0ee5bce44b9106f673c223e39 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sun, 11 Sep 2022 13:46:49 +0200 Subject: [PATCH 135/162] Getting started sample code --- GettingStarted/Container.cs | 13 +++++++++++++ GettingStarted/GettingStarted.csproj | 16 ++++++++++++++++ GettingStarted/Logger.cs | 11 +++++++++++ GettingStarted/MrMeeseeks.cs | 17 +++++++++++++++++ GettingStarted/Program.cs | 5 +++++ MrMeeseeks.DIE.sln | 6 ++++++ 6 files changed, 68 insertions(+) create mode 100644 GettingStarted/Container.cs create mode 100644 GettingStarted/GettingStarted.csproj create mode 100644 GettingStarted/Logger.cs create mode 100644 GettingStarted/MrMeeseeks.cs create mode 100644 GettingStarted/Program.cs diff --git a/GettingStarted/Container.cs b/GettingStarted/Container.cs new file mode 100644 index 00000000..f9d3cf3d --- /dev/null +++ b/GettingStarted/Container.cs @@ -0,0 +1,13 @@ +using MrMeeseeks.DIE.Configuration.Attributes; + +namespace GettingStarted; + +[ImplementationAggregation( + typeof(Logger), + typeof(MrMeeseeks))] + +[CreateFunction(typeof(MrMeeseeks), "Create")] +internal sealed partial class Container +{ + +} \ No newline at end of file diff --git a/GettingStarted/GettingStarted.csproj b/GettingStarted/GettingStarted.csproj new file mode 100644 index 00000000..b912f3b0 --- /dev/null +++ b/GettingStarted/GettingStarted.csproj @@ -0,0 +1,16 @@ + + + + Exe + net6.0 + enable + enable + true + $(BaseIntermediateOutputPath)\GeneratedFiles + + + + + + + diff --git a/GettingStarted/Logger.cs b/GettingStarted/Logger.cs new file mode 100644 index 00000000..093311a8 --- /dev/null +++ b/GettingStarted/Logger.cs @@ -0,0 +1,11 @@ +namespace GettingStarted; + +public interface ILogger +{ + void Log(string message); +} + +internal class Logger : ILogger +{ + public void Log(string message) => Console.WriteLine(message); +} \ No newline at end of file diff --git a/GettingStarted/MrMeeseeks.cs b/GettingStarted/MrMeeseeks.cs new file mode 100644 index 00000000..fc5d5a28 --- /dev/null +++ b/GettingStarted/MrMeeseeks.cs @@ -0,0 +1,17 @@ +namespace GettingStarted; + +internal interface IMrMeeseeks +{ + void Greet(); +} + +internal class MrMeeseeks : IMrMeeseeks +{ + private readonly ILogger _logger; + + internal MrMeeseeks(ILogger logger) => + _logger = logger; + + public void Greet() => + _logger.Log("I'm MrMeeseeks! Look at me!"); +} \ No newline at end of file diff --git a/GettingStarted/Program.cs b/GettingStarted/Program.cs new file mode 100644 index 00000000..6cbbce8c --- /dev/null +++ b/GettingStarted/Program.cs @@ -0,0 +1,5 @@ +// See https://aka.ms/new-console-template for more information + +using var container = new GettingStarted.Container(); +var mrMeeseeks = container.Create(); +mrMeeseeks.Greet(); \ No newline at end of file diff --git a/MrMeeseeks.DIE.sln b/MrMeeseeks.DIE.sln index 1497f684..79a2bf46 100644 --- a/MrMeeseeks.DIE.sln +++ b/MrMeeseeks.DIE.sln @@ -23,6 +23,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestNotInternalsVisibleToCh EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestInternalsVisibleToChild", "TestInternalsVisibleToChild\TestInternalsVisibleToChild.csproj", "{AB74CB8A-5195-4CB0-9844-71AFB1F5C926}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GettingStarted", "GettingStarted\GettingStarted.csproj", "{D71C272C-8CD5-44D5-B1A2-BD9271823FC3}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -57,6 +59,10 @@ Global {AB74CB8A-5195-4CB0-9844-71AFB1F5C926}.Debug|Any CPU.Build.0 = Debug|Any CPU {AB74CB8A-5195-4CB0-9844-71AFB1F5C926}.Release|Any CPU.ActiveCfg = Release|Any CPU {AB74CB8A-5195-4CB0-9844-71AFB1F5C926}.Release|Any CPU.Build.0 = Release|Any CPU + {D71C272C-8CD5-44D5-B1A2-BD9271823FC3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D71C272C-8CD5-44D5-B1A2-BD9271823FC3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D71C272C-8CD5-44D5-B1A2-BD9271823FC3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D71C272C-8CD5-44D5-B1A2-BD9271823FC3}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From b3c6a3cf982933b69018dd4e319594a9ab03f4d2 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sat, 17 Sep 2022 15:54:53 +0200 Subject: [PATCH 136/162] File per scope generation --- Main/CodeBuilding/ContainerCodeBuilder.cs | 10 --- Main/CodeBuilding/ContainerGenerator.cs | 54 +++++++++----- Main/CodeBuilding/ScopeCodeBuilder.cs | 45 +++++++----- .../CodeBuilding/TransientScopeCodeBuilder.cs | 39 ++++++---- Main/SourceGenerator.cs | 8 +-- Sample/Container.cs | 72 ++++++++++++++++--- 6 files changed, 155 insertions(+), 73 deletions(-) diff --git a/Main/CodeBuilding/ContainerCodeBuilder.cs b/Main/CodeBuilding/ContainerCodeBuilder.cs index 4ead6f12..9c1c70df 100644 --- a/Main/CodeBuilding/ContainerCodeBuilder.cs +++ b/Main/CodeBuilding/ContainerCodeBuilder.cs @@ -12,8 +12,6 @@ internal class ContainerCodeBuilder : RangeCodeBaseBuilder, IContainerCodeBuilde { private readonly IContainerInfo _containerInfo; private readonly ContainerResolution _containerResolution; - private readonly IReadOnlyList _transientScopeCodeBuilders; - private readonly IReadOnlyList _scopeCodeBuilders; protected override StringBuilder GenerateDisposalFunction_TransientScopeDictionary(StringBuilder stringBuilder) { @@ -102,10 +100,6 @@ public override StringBuilder Build(StringBuilder stringBuilder) .AppendLine($"private {_containerResolution.TransientScopeInterface.ContainerAdapterName}? _{_containerResolution.TransientScopeAdapterReference};") .AppendLine($"private {_containerResolution.TransientScopeInterface.ContainerAdapterName} {_containerResolution.TransientScopeAdapterReference} => _{_containerResolution.TransientScopeAdapterReference} ??= new {_containerResolution.TransientScopeInterface.ContainerAdapterName}(this);"); - stringBuilder = _transientScopeCodeBuilders.Aggregate(stringBuilder, (sb, cb) => cb.Build(sb)); - - stringBuilder = _scopeCodeBuilders.Aggregate(stringBuilder, (sb, cb) => cb.Build(sb)); - var disposableTypeFullName = WellKnownTypes.Disposable.FullName(); var asyncDisposableTypeFullName = WellKnownTypes.AsyncDisposable.FullName(); var valueTaskFullName = WellKnownTypes.ValueTask.FullName(); @@ -152,8 +146,6 @@ public ContainerCodeBuilder( // parameter IContainerInfo containerInfo, ContainerResolution containerResolution, - IReadOnlyList transientScopeCodeBuilders, - IReadOnlyList scopeCodeBuilders, // dependencies WellKnownTypes wellKnownTypes) @@ -161,7 +153,5 @@ public ContainerCodeBuilder( { _containerInfo = containerInfo; _containerResolution = containerResolution; - _transientScopeCodeBuilders = transientScopeCodeBuilders; - _scopeCodeBuilders = scopeCodeBuilders; } } \ No newline at end of file diff --git a/Main/CodeBuilding/ContainerGenerator.cs b/Main/CodeBuilding/ContainerGenerator.cs index 05f3ac53..b86b1cb8 100644 --- a/Main/CodeBuilding/ContainerGenerator.cs +++ b/Main/CodeBuilding/ContainerGenerator.cs @@ -3,7 +3,7 @@ namespace MrMeeseeks.DIE.CodeBuilding; -internal interface IContainerGenerator +internal interface IContainerGenerator { void Generate(IContainerInfo containerInfo, ContainerResolution resolvable); } @@ -11,20 +11,17 @@ internal interface IContainerGenerator internal class ContainerGenerator : IContainerGenerator { private readonly GeneratorExecutionContext _context; - private readonly IDiagLogger _diagLogger; - private readonly Func, IReadOnlyList, IContainerCodeBuilder> _containerCodeBuilderFactory; + private readonly Func _containerCodeBuilderFactory; private readonly Func _transientScopeCodeBuilderFactory; private readonly Func _scopeCodeBuilderFactory; internal ContainerGenerator( GeneratorExecutionContext context, - IDiagLogger diagLogger, - Func, IReadOnlyList, IContainerCodeBuilder> containerCodeBuilderFactory, + Func containerCodeBuilderFactory, Func transientScopeCodeBuilderFactory, Func scopeCodeBuilderFactory) { _context = context; - _diagLogger = diagLogger; _containerCodeBuilderFactory = containerCodeBuilderFactory; _transientScopeCodeBuilderFactory = transientScopeCodeBuilderFactory; _scopeCodeBuilderFactory = scopeCodeBuilderFactory; @@ -32,21 +29,42 @@ internal ContainerGenerator( public void Generate(IContainerInfo containerInfo, ContainerResolution containerResolution) { - var containerCodeBuilder = _containerCodeBuilderFactory( - containerInfo, - containerResolution, - containerResolution.TransientScopes.Select(ts => _transientScopeCodeBuilderFactory(containerInfo, ts, containerResolution)).ToList(), - containerResolution.Scopes.Select(s => _scopeCodeBuilderFactory(containerInfo, s, containerResolution.TransientScopeInterface, containerResolution)).ToList()); + var containerCodeBuilder = _containerCodeBuilderFactory(containerInfo, containerResolution); var generatedContainer = containerCodeBuilder.Build(new StringBuilder()); + + RenderSourceFile($"{containerInfo.Namespace}.{containerInfo.Name}.g.cs", generatedContainer); + + generatedContainer.Clear(); + + foreach (var transientScopeCodeBuilder in containerResolution.TransientScopes.Select(ts => _transientScopeCodeBuilderFactory(containerInfo, ts, containerResolution)).ToList()) + { + var generatedTransientScope = transientScopeCodeBuilder.Build(new StringBuilder()); + + RenderSourceFile($"{containerInfo.Namespace}.{containerInfo.Name}.{transientScopeCodeBuilder.TransientScopeResolution.Name}.g.cs", generatedTransientScope); + + generatedTransientScope.Clear(); + } + + foreach (var scopeCodeBuilder in containerResolution.Scopes.Select(s => _scopeCodeBuilderFactory(containerInfo, s, containerResolution.TransientScopeInterface, containerResolution)).ToList()) + { + var generatedTransientScope = scopeCodeBuilder.Build(new StringBuilder()); + + RenderSourceFile($"{containerInfo.Namespace}.{containerInfo.Name}.{scopeCodeBuilder.ScopeResolution.Name}.g.cs", generatedTransientScope); + + generatedTransientScope.Clear(); + } - var containerSource = CSharpSyntaxTree - .ParseText(SourceText.From(generatedContainer.ToString(), Encoding.UTF8)) - .GetRoot() - .NormalizeWhitespace() - .SyntaxTree - .GetText(); + void RenderSourceFile(string fileName, StringBuilder compiledCode) + { + var containerSource = CSharpSyntaxTree + .ParseText(SourceText.From(compiledCode.ToString(), Encoding.UTF8)) + .GetRoot() + .NormalizeWhitespace() + .SyntaxTree + .GetText(); - _context.AddSource($"{containerInfo.Namespace}.{containerInfo.Name}.g.cs", containerSource); + _context.AddSource(fileName, containerSource); + } } } \ No newline at end of file diff --git a/Main/CodeBuilding/ScopeCodeBuilder.cs b/Main/CodeBuilding/ScopeCodeBuilder.cs index 3c277f57..af928cce 100644 --- a/Main/CodeBuilding/ScopeCodeBuilder.cs +++ b/Main/CodeBuilding/ScopeCodeBuilder.cs @@ -4,13 +4,12 @@ namespace MrMeeseeks.DIE.CodeBuilding; internal interface IScopeCodeBuilder : IRangeCodeBaseBuilder { - + ScopeResolution ScopeResolution { get; } } internal class ScopeCodeBuilder : RangeCodeBaseBuilder, IScopeCodeBuilder { private readonly IContainerInfo _containerInfo; - private readonly ScopeResolution _scopeResolution; private readonly TransientScopeInterfaceResolution _transientScopeInterfaceResolution; private readonly ContainerResolution _containerResolution; @@ -22,32 +21,42 @@ internal class ScopeCodeBuilder : RangeCodeBaseBuilder, IScopeCodeBuilder public override StringBuilder Build(StringBuilder stringBuilder) { - var disposableImplementation = _containerResolution.DisposalType.HasFlag(DisposalType.Async) - ? $" : {WellKnownTypes.AsyncDisposable.FullName()}" - : $" : {WellKnownTypes.AsyncDisposable.FullName()}, {WellKnownTypes.Disposable.FullName()}"; + var disposableImplementation = _containerResolution.DisposalType.HasFlag(DisposalType.Async) + ? $" : {WellKnownTypes.AsyncDisposable.FullName()}" + : $" : {WellKnownTypes.AsyncDisposable.FullName()}, {WellKnownTypes.Disposable.FullName()}"; + + stringBuilder = stringBuilder + .AppendLine($"#nullable enable") + .AppendLine($"namespace {_containerInfo.Namespace}") + .AppendLine($"{{") + .AppendLine($"partial class {_containerInfo.Name}") + .AppendLine($"{{"); stringBuilder = stringBuilder .AppendLine( - $"private partial class {_scopeResolution.Name}{disposableImplementation}") + $"private partial class {ScopeResolution.Name}{disposableImplementation}") .AppendLine($"{{") - .AppendLine($"private readonly {_containerInfo.FullName} {_scopeResolution.ContainerReference};") - .AppendLine($"private readonly {_transientScopeInterfaceResolution.Name} {_scopeResolution.TransientScopeReference};") - .AppendLine($"internal {_scopeResolution.Name}(") - .AppendLine($"{_containerInfo.FullName} {_scopeResolution.ContainerParameterReference},") - .AppendLine($"{_transientScopeInterfaceResolution.Name} {_scopeResolution.TransientScopeParameterReference})") + .AppendLine($"private readonly {_containerInfo.FullName} {ScopeResolution.ContainerReference};") + .AppendLine($"private readonly {_transientScopeInterfaceResolution.Name} {ScopeResolution.TransientScopeReference};") + .AppendLine($"internal {ScopeResolution.Name}(") + .AppendLine($"{_containerInfo.FullName} {ScopeResolution.ContainerParameterReference},") + .AppendLine($"{_transientScopeInterfaceResolution.Name} {ScopeResolution.TransientScopeParameterReference})") .AppendLine($"{{") - .AppendLine($"{_scopeResolution.ContainerReference} = {_scopeResolution.ContainerParameterReference};") - .AppendLine($"{_scopeResolution.TransientScopeReference} = {_scopeResolution.TransientScopeParameterReference};") + .AppendLine($"{ScopeResolution.ContainerReference} = {ScopeResolution.ContainerParameterReference};") + .AppendLine($"{ScopeResolution.TransientScopeReference} = {ScopeResolution.TransientScopeParameterReference};") .AppendLine($"}}"); stringBuilder = GenerateResolutionRange( stringBuilder, - _scopeResolution); + ScopeResolution); stringBuilder = stringBuilder .AppendLine($"}}"); - - return stringBuilder; + + return stringBuilder + .AppendLine($"}}") + .AppendLine($"}}") + .AppendLine($"#nullable disable"); } public ScopeCodeBuilder( @@ -62,8 +71,10 @@ public ScopeCodeBuilder( : base(scopeResolution, containerResolution, wellKnownTypes) { _containerInfo = containerInfo; - _scopeResolution = scopeResolution; + ScopeResolution = scopeResolution; _transientScopeInterfaceResolution = transientScopeInterfaceResolution; _containerResolution = containerResolution; } + + public ScopeResolution ScopeResolution { get; } } \ No newline at end of file diff --git a/Main/CodeBuilding/TransientScopeCodeBuilder.cs b/Main/CodeBuilding/TransientScopeCodeBuilder.cs index 16f55975..1c81631e 100644 --- a/Main/CodeBuilding/TransientScopeCodeBuilder.cs +++ b/Main/CodeBuilding/TransientScopeCodeBuilder.cs @@ -4,14 +4,15 @@ namespace MrMeeseeks.DIE.CodeBuilding; internal interface ITransientScopeCodeBuilder : IRangeCodeBaseBuilder { - + public TransientScopeResolution TransientScopeResolution { get; } } internal class TransientScopeCodeBuilder : RangeCodeBaseBuilder, ITransientScopeCodeBuilder { private readonly IContainerInfo _containerInfo; - private readonly TransientScopeResolution _transientScopeResolution; private readonly ContainerResolution _containerResolution; + + public TransientScopeResolution TransientScopeResolution { get; } protected override StringBuilder GenerateDisposalFunction_TransientScopeDictionary(StringBuilder stringBuilder) => stringBuilder; @@ -25,7 +26,7 @@ protected override StringBuilder GenerateDisposalFunction_TransientScopeDisposal : WellKnownTypes.Disposable.FullName(); stringBuilder - .AppendLine($"{_transientScopeResolution.ContainerReference}.{_containerResolution.TransientScopeDisposalReference}.TryRemove(({disposalType}) this, out _);"); + .AppendLine($"{TransientScopeResolution.ContainerReference}.{_containerResolution.TransientScopeDisposalReference}.TryRemove(({disposalType}) this, out _);"); return stringBuilder; } @@ -34,28 +35,38 @@ protected override StringBuilder GenerateDisposalFunction_TransientScopeDisposal public override StringBuilder Build(StringBuilder stringBuilder) { - var disposableImplementation = _containerResolution.DisposalType.HasFlag(DisposalType.Async) - ? $", {WellKnownTypes.AsyncDisposable.FullName()}" + var disposableImplementation = _containerResolution.DisposalType.HasFlag(DisposalType.Async) + ? $", {WellKnownTypes.AsyncDisposable.FullName()}" : $", {WellKnownTypes.AsyncDisposable.FullName()}, {WellKnownTypes.Disposable.FullName()}"; stringBuilder = stringBuilder - .AppendLine($"private partial class {_transientScopeResolution.Name} : {_containerResolution.TransientScopeInterface.Name}{disposableImplementation}") + .AppendLine($"#nullable enable") + .AppendLine($"namespace {_containerInfo.Namespace}") + .AppendLine($"{{") + .AppendLine($"partial class {_containerInfo.Name}") + .AppendLine($"{{"); + + stringBuilder = stringBuilder + .AppendLine($"private partial class {TransientScopeResolution.Name} : {_containerResolution.TransientScopeInterface.Name}{disposableImplementation}") .AppendLine($"{{") - .AppendLine($"private readonly {_containerInfo.FullName} {_transientScopeResolution.ContainerReference};") - .AppendLine($"internal {_transientScopeResolution.Name}(") - .AppendLine($"{_containerInfo.FullName} {_transientScopeResolution.ContainerParameterReference})") + .AppendLine($"private readonly {_containerInfo.FullName} {TransientScopeResolution.ContainerReference};") + .AppendLine($"internal {TransientScopeResolution.Name}(") + .AppendLine($"{_containerInfo.FullName} {TransientScopeResolution.ContainerParameterReference})") .AppendLine($"{{") - .AppendLine($"{_transientScopeResolution.ContainerReference} = {_transientScopeResolution.ContainerParameterReference};") + .AppendLine($"{TransientScopeResolution.ContainerReference} = {TransientScopeResolution.ContainerParameterReference};") .AppendLine($"}}"); stringBuilder = GenerateResolutionRange( stringBuilder, - _transientScopeResolution); + TransientScopeResolution); stringBuilder = stringBuilder .AppendLine($"}}"); - - return stringBuilder; + + return stringBuilder + .AppendLine($"}}") + .AppendLine($"}}") + .AppendLine($"#nullable disable"); } public TransientScopeCodeBuilder( @@ -69,7 +80,7 @@ public TransientScopeCodeBuilder( : base(transientScopeResolution, containerResolution, wellKnownTypes) { _containerInfo = containerInfo; - _transientScopeResolution = transientScopeResolution; + TransientScopeResolution = transientScopeResolution; _containerResolution = containerResolution; } } \ No newline at end of file diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index 75b2dbe7..68bbf0d7 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -87,7 +87,7 @@ public void Execute(GeneratorExecutionContext context) if (assemblyTypesFromAttributes.Errors.Any()) return; - var containerGenerator = new ContainerGenerator(context, diagLogger, ContainerCodeBuilderFactory, TransientScopeCodeBuilderFactory, ScopeCodeBuilderFactory); + var containerGenerator = new ContainerGenerator(context, ContainerCodeBuilderFactory, TransientScopeCodeBuilderFactory, ScopeCodeBuilderFactory); var referenceGeneratorFactory = new ReferenceGeneratorFactory(ReferenceGeneratorFactory); var containerDieExceptionGenerator = new ContainerDieExceptionGenerator(context, wellKnownTypesMiscellaneous); var implementationTypeSetCache = new ImplementationTypeSetCache(context, wellKnownTypes); @@ -286,13 +286,9 @@ IFunctionResolutionSynchronicityDecisionMaker FunctionResolutionSynchronicityDec IContainerCodeBuilder ContainerCodeBuilderFactory( IContainerInfo containerInfo, - ContainerResolution containerResolution, - IReadOnlyList transientScopeCodeBuilders, - IReadOnlyList scopeCodeBuilders) => new ContainerCodeBuilder( + ContainerResolution containerResolution) => new ContainerCodeBuilder( containerInfo, containerResolution, - transientScopeCodeBuilders, - scopeCodeBuilders, wellKnownTypes); ITransientScopeCodeBuilder TransientScopeCodeBuilderFactory( diff --git a/Sample/Container.cs b/Sample/Container.cs index 3e8d5176..eb8e52e2 100644 --- a/Sample/Container.cs +++ b/Sample/Container.cs @@ -1,14 +1,70 @@ -using MrMeeseeks.DIE.Configuration.Attributes; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using MrMeeseeks.DIE.Sample; -namespace MrMeeseeks.DIE.Test.Bugs.UngenericImplementationGenericInterface; +namespace MrMeeseeks.DIE.Test.Async.Awaited.TransientScopeInstanceFunction_DifferentSynchronicity; -internal interface IInterface {} +internal interface IInterface {} -internal class DependencyA : IInterface {} +internal class DependencyA : IInterface, ITaskInitializer +{ + public bool IsInitialized { get; private set; } + + async Task ITaskInitializer.InitializeAsync() + { + await Task.Delay(500).ConfigureAwait(false); + IsInitialized = true; + } +} -internal class DependencyB : IInterface {} +internal class DependencyB : IInterface +{ +} -internal class DependencyC : IInterface {} +internal class Instance : ITransientScopeInstance +{ + public IInterface Inner { get; } -[CreateFunction(typeof(IInterface), "Create")] -internal sealed partial class Container {} \ No newline at end of file + public Instance(IInterface inner) + { + Inner = inner; + } +} + +internal class TransientScopeRoot0 : ITransientScopeRoot +{ + public Instance Dependency { get; } + + internal TransientScopeRoot0(Instance dependency) + { + Dependency = dependency; + } +} + +internal class TransientScopeRoot1 : ITransientScopeRoot +{ + internal TransientScopeRoot1(Instance dependency) + { + + } +} + +[FilterImplementationAggregation(typeof(DependencyB))] +[CreateFunction(typeof(TransientScopeRoot0), "Create0")] +[CreateFunction(typeof(TransientScopeRoot1), "Create1")] +internal sealed partial class Container +{ + [CustomScopeForRootTypes(typeof(TransientScopeRoot0))] + private sealed partial class DIE_TransientScope0 + { + + } + + [FilterImplementationAggregation(typeof(DependencyA))] + [ImplementationAggregation(typeof(DependencyB))] + [CustomScopeForRootTypes(typeof(TransientScopeRoot1))] + private sealed partial class DIE_TransientScope1 + { + + } +} \ No newline at end of file From 5b1e9993fa23a302963448aecd422743895eaaf3 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sat, 17 Sep 2022 16:00:30 +0200 Subject: [PATCH 137/162] Update README.md --- README.md | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 728eeb57..4fc78c42 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,33 @@ -# MrMeeseeks.DIE +# Welcome to MrMeeseeks.DIE -DIE is a secret agency organized by a bunch of Mr. Meeseekses. Its goal is to gather the information necessary to resolve dependencies. Therefore, … +DIE is a secret agency organized by a bunch of Mr. Meeseekses. Its goal is to gather the information necessary to resolve your dependencies. Therefore, … > The acronym DIE stands for **D**ependency **I**njection DI**E** + +Let the secret agency DIE compose these info in order to build factory methods which create instances of types of your choice. + +## Introduction + +MrMeeseeks.DIE (in this documentation just referred to as DIE) is a compile-time dependency injection container for .Net. As such it generates factory methods which create instances that you need. Instead of relying on reflection the generated code uses the good old `new` operator to create instances like you would probably do yourself if you'd create a pure DI container. + +## Nuget + +The easiest way of using DIE is by getting it through nuget. Here is the package page: + +https://www.nuget.org/packages/MrMeeseeks.DIE/ + +Either search for `MrMeeseeks.DIE` in the nuget manager of the IDE of your choice. + +Or call following PowerShell-command: + +> Install-Package MrMeeseeks.DIE + +Or manually insert the package reference into the target `.csproj`: + +```xml + +``` + +## Documentation + +Please visit https://die.mrmeeseeks.dev/ for a documentation. From 4b7493321e39beaf9f51704a5f7f845323cd4a63 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sat, 17 Sep 2022 17:01:38 +0200 Subject: [PATCH 138/162] Own file for each generated function --- Main/CodeBuilding/ContainerCodeBuilder.cs | 26 ++++++- Main/CodeBuilding/ContainerGenerator.cs | 45 +++++++----- Main/CodeBuilding/RangeCodeBaseBuilder.cs | 19 ++--- Main/CodeBuilding/ScopeCodeBuilder.cs | 33 ++++++++- .../CodeBuilding/TransientScopeCodeBuilder.cs | 33 ++++++++- Main/ResolutionTreeItem.cs | 50 +++++++------ Sample/Container.cs | 71 ++++++------------- 7 files changed, 179 insertions(+), 98 deletions(-) diff --git a/Main/CodeBuilding/ContainerCodeBuilder.cs b/Main/CodeBuilding/ContainerCodeBuilder.cs index 9c1c70df..e2aa67a0 100644 --- a/Main/CodeBuilding/ContainerCodeBuilder.cs +++ b/Main/CodeBuilding/ContainerCodeBuilder.cs @@ -54,7 +54,24 @@ protected override StringBuilder GenerateDisposalFunction_TransientScopeDisposal protected override bool ExplicitTransientScopeInstanceImplementation => false; - public override StringBuilder Build(StringBuilder stringBuilder) + private StringBuilder BuildFunction(StringBuilder stringBuilder, Func functionResolution) + { + stringBuilder = stringBuilder + .AppendLine($"#nullable enable") + .AppendLine($"namespace {_containerInfo.Namespace}") + .AppendLine($"{{") + .AppendLine($"partial class {_containerInfo.Name}") + .AppendLine($"{{"); + + stringBuilder = functionResolution(stringBuilder); + + return stringBuilder + .AppendLine($"}}") + .AppendLine($"}}") + .AppendLine($"#nullable disable"); + } + + public override StringBuilder BuildGeneral(StringBuilder stringBuilder) { var disposableImplementation = _containerResolution.DisposalType.HasFlag(DisposalType.Async) ? $" : {WellKnownTypes.AsyncDisposable.FullName()}" @@ -142,6 +159,13 @@ string SelectFullName(InterfaceFunctionDeclarationResolution interfaceResolution }; } + public override StringBuilder BuildCreateFunction(StringBuilder stringBuilder, FunctionResolution functionResolution) => + BuildFunction(stringBuilder, sb => GenerateResolutionFunction(sb, functionResolution)); + + public override StringBuilder BuildRangedFunction(StringBuilder stringBuilder, + RangedInstanceFunctionGroupResolution rangedInstanceFunctionGroupResolution) => + BuildFunction(stringBuilder, sb => GenerateRangedInstanceFunction(sb, rangedInstanceFunctionGroupResolution)); + public ContainerCodeBuilder( // parameter IContainerInfo containerInfo, diff --git a/Main/CodeBuilding/ContainerGenerator.cs b/Main/CodeBuilding/ContainerGenerator.cs index b86b1cb8..99d68dba 100644 --- a/Main/CodeBuilding/ContainerGenerator.cs +++ b/Main/CodeBuilding/ContainerGenerator.cs @@ -30,31 +30,42 @@ internal ContainerGenerator( public void Generate(IContainerInfo containerInfo, ContainerResolution containerResolution) { var containerCodeBuilder = _containerCodeBuilderFactory(containerInfo, containerResolution); - - var generatedContainer = containerCodeBuilder.Build(new StringBuilder()); - RenderSourceFile($"{containerInfo.Namespace}.{containerInfo.Name}.g.cs", generatedContainer); - - generatedContainer.Clear(); + GenerateRange(containerCodeBuilder, containerResolution); - foreach (var transientScopeCodeBuilder in containerResolution.TransientScopes.Select(ts => _transientScopeCodeBuilderFactory(containerInfo, ts, containerResolution)).ToList()) + foreach (var transientScopeResolution in containerResolution.TransientScopes) { - var generatedTransientScope = transientScopeCodeBuilder.Build(new StringBuilder()); - - RenderSourceFile($"{containerInfo.Namespace}.{containerInfo.Name}.{transientScopeCodeBuilder.TransientScopeResolution.Name}.g.cs", generatedTransientScope); - - generatedTransientScope.Clear(); + var transientScopeCodeBuilder = _transientScopeCodeBuilderFactory(containerInfo, transientScopeResolution, containerResolution); + GenerateRange(transientScopeCodeBuilder, transientScopeResolution); } - foreach (var scopeCodeBuilder in containerResolution.Scopes.Select(s => _scopeCodeBuilderFactory(containerInfo, s, containerResolution.TransientScopeInterface, containerResolution)).ToList()) + foreach (var scopeResolution in containerResolution.Scopes) { - var generatedTransientScope = scopeCodeBuilder.Build(new StringBuilder()); - - RenderSourceFile($"{containerInfo.Namespace}.{containerInfo.Name}.{scopeCodeBuilder.ScopeResolution.Name}.g.cs", generatedTransientScope); - - generatedTransientScope.Clear(); + var scopeCodeBuilder = _scopeCodeBuilderFactory(containerInfo, scopeResolution, containerResolution.TransientScopeInterface, containerResolution); + GenerateRange(scopeCodeBuilder, scopeResolution); } + void GenerateRange(IRangeCodeBaseBuilder rangeCodeBaseBuilder, IRangeResolution rangeResolution) + { + var generatedGeneral = rangeCodeBaseBuilder.BuildGeneral(new StringBuilder()); + RenderSourceFile($"{containerInfo.Namespace}.{containerInfo.Name}.{rangeResolution.Name}.g.cs", generatedGeneral); + generatedGeneral.Clear(); + + foreach (var createFunction in rangeResolution.CreateFunctions) + { + var generatedCreateFunction = rangeCodeBaseBuilder.BuildCreateFunction(new StringBuilder(), createFunction); + RenderSourceFile($"{containerInfo.Namespace}.{containerInfo.Name}.{rangeResolution.Name}.{createFunction.Reference}.g.cs", generatedCreateFunction); + generatedCreateFunction.Clear(); + } + + foreach (var rangedInstanceFunctionGroup in rangeResolution.RangedInstanceFunctionGroups) + { + var generatedInstanceFunctionGroupFunction = rangeCodeBaseBuilder.BuildRangedFunction(new StringBuilder(), rangedInstanceFunctionGroup); + RenderSourceFile($"{containerInfo.Namespace}.{containerInfo.Name}.{rangeResolution.Name}.{rangedInstanceFunctionGroup.Overloads[0].Reference}.g.cs", generatedInstanceFunctionGroupFunction); + generatedInstanceFunctionGroupFunction.Clear(); + } + } + void RenderSourceFile(string fileName, StringBuilder compiledCode) { var containerSource = CSharpSyntaxTree diff --git a/Main/CodeBuilding/RangeCodeBaseBuilder.cs b/Main/CodeBuilding/RangeCodeBaseBuilder.cs index 18fc16a0..5db2aa51 100644 --- a/Main/CodeBuilding/RangeCodeBaseBuilder.cs +++ b/Main/CodeBuilding/RangeCodeBaseBuilder.cs @@ -5,7 +5,9 @@ namespace MrMeeseeks.DIE.CodeBuilding; internal interface IRangeCodeBaseBuilder { - StringBuilder Build(StringBuilder stringBuilder); + StringBuilder BuildGeneral(StringBuilder stringBuilder); + StringBuilder BuildCreateFunction(StringBuilder stringBuilder, FunctionResolution functionResolution); + StringBuilder BuildRangedFunction(StringBuilder stringBuilder, RangedInstanceFunctionGroupResolution rangedInstanceFunctionGroupResolution); } internal abstract class RangeCodeBaseBuilder : IRangeCodeBaseBuilder @@ -28,10 +30,6 @@ protected StringBuilder GenerateResolutionRange( StringBuilder stringBuilder, RangeResolution rangeResolution) { - stringBuilder = rangeResolution.RangedInstanceFunctionGroups.Aggregate(stringBuilder, GenerateRangedInstanceFunction); - - stringBuilder = rangeResolution.CreateFunctions.Aggregate(stringBuilder, GenerateResolutionFunction); - if (_rangeResolution.AddForDisposal is { } addForDisposalMethod) { stringBuilder = stringBuilder @@ -170,7 +168,7 @@ private StringBuilder GenerateDisposalFunction( return stringBuilder; } - private StringBuilder GenerateResolutionFunction( + protected StringBuilder GenerateResolutionFunction( StringBuilder stringBuilder, FunctionResolution resolution) { @@ -476,7 +474,7 @@ private StringBuilder GenerateResolutions( private StringBuilder ObjectDisposedCheck(StringBuilder stringBuilder, string returnTypeFullName) => stringBuilder .AppendLine($"if (this.{_rangeResolution.DisposalHandling.DisposedPropertyReference}) throw new {WellKnownTypes.ObjectDisposedException}(\"{_rangeResolution.DisposalHandling.RangeName}\", $\"[DIE] This scope \\\"{_rangeResolution.DisposalHandling.RangeName}\\\" is already disposed, so it can't create a \\\"{returnTypeFullName}\\\" instance anymore.\");"); - private StringBuilder GenerateRangedInstanceFunction(StringBuilder stringBuilder, RangedInstanceFunctionGroupResolution rangedInstanceFunctionGroupResolution) + protected StringBuilder GenerateRangedInstanceFunction(StringBuilder stringBuilder, RangedInstanceFunctionGroupResolution rangedInstanceFunctionGroupResolution) { var isRefType = rangedInstanceFunctionGroupResolution.IsCreatedForStructs is null; stringBuilder = stringBuilder @@ -543,5 +541,10 @@ private StringBuilder GenerateRangedInstanceFunction(StringBuilder stringBuilder return stringBuilder; } - public abstract StringBuilder Build(StringBuilder stringBuilder); + public abstract StringBuilder BuildGeneral(StringBuilder stringBuilder); + public abstract StringBuilder BuildCreateFunction(StringBuilder stringBuilder, FunctionResolution functionResolution); + + public abstract StringBuilder BuildRangedFunction( + StringBuilder stringBuilder, + RangedInstanceFunctionGroupResolution rangedInstanceFunctionGroupResolution); } \ No newline at end of file diff --git a/Main/CodeBuilding/ScopeCodeBuilder.cs b/Main/CodeBuilding/ScopeCodeBuilder.cs index af928cce..f016c4dd 100644 --- a/Main/CodeBuilding/ScopeCodeBuilder.cs +++ b/Main/CodeBuilding/ScopeCodeBuilder.cs @@ -19,7 +19,31 @@ internal class ScopeCodeBuilder : RangeCodeBaseBuilder, IScopeCodeBuilder protected override bool ExplicitTransientScopeInstanceImplementation => false; - public override StringBuilder Build(StringBuilder stringBuilder) + public StringBuilder BuildFunction(StringBuilder stringBuilder, Func functionResolution) + { + stringBuilder = stringBuilder + .AppendLine($"#nullable enable") + .AppendLine($"namespace {_containerInfo.Namespace}") + .AppendLine($"{{") + .AppendLine($"partial class {_containerInfo.Name}") + .AppendLine($"{{"); + + stringBuilder = stringBuilder + .AppendLine($"private partial class {ScopeResolution.Name}") + .AppendLine($"{{"); + + stringBuilder = functionResolution(stringBuilder); + + stringBuilder = stringBuilder + .AppendLine($"}}"); + + return stringBuilder + .AppendLine($"}}") + .AppendLine($"}}") + .AppendLine($"#nullable disable"); + } + + public override StringBuilder BuildGeneral(StringBuilder stringBuilder) { var disposableImplementation = _containerResolution.DisposalType.HasFlag(DisposalType.Async) ? $" : {WellKnownTypes.AsyncDisposable.FullName()}" @@ -59,6 +83,13 @@ public override StringBuilder Build(StringBuilder stringBuilder) .AppendLine($"#nullable disable"); } + public override StringBuilder BuildCreateFunction(StringBuilder stringBuilder, FunctionResolution functionResolution) => + BuildFunction(stringBuilder, sb => GenerateResolutionFunction(sb, functionResolution)); + + public override StringBuilder BuildRangedFunction(StringBuilder stringBuilder, + RangedInstanceFunctionGroupResolution rangedInstanceFunctionGroupResolution) => + BuildFunction(stringBuilder, sb => GenerateRangedInstanceFunction(sb, rangedInstanceFunctionGroupResolution)); + public ScopeCodeBuilder( // parameter IContainerInfo containerInfo, diff --git a/Main/CodeBuilding/TransientScopeCodeBuilder.cs b/Main/CodeBuilding/TransientScopeCodeBuilder.cs index 1c81631e..a4e48de3 100644 --- a/Main/CodeBuilding/TransientScopeCodeBuilder.cs +++ b/Main/CodeBuilding/TransientScopeCodeBuilder.cs @@ -33,7 +33,31 @@ protected override StringBuilder GenerateDisposalFunction_TransientScopeDisposal protected override bool ExplicitTransientScopeInstanceImplementation => true; - public override StringBuilder Build(StringBuilder stringBuilder) + public StringBuilder BuildFunction(StringBuilder stringBuilder, Func functionResolution) + { + stringBuilder = stringBuilder + .AppendLine($"#nullable enable") + .AppendLine($"namespace {_containerInfo.Namespace}") + .AppendLine($"{{") + .AppendLine($"partial class {_containerInfo.Name}") + .AppendLine($"{{"); + + stringBuilder = stringBuilder + .AppendLine($"private partial class {TransientScopeResolution.Name}") + .AppendLine($"{{"); + + stringBuilder = functionResolution(stringBuilder); + + stringBuilder = stringBuilder + .AppendLine($"}}"); + + return stringBuilder + .AppendLine($"}}") + .AppendLine($"}}") + .AppendLine($"#nullable disable"); + } + + public override StringBuilder BuildGeneral(StringBuilder stringBuilder) { var disposableImplementation = _containerResolution.DisposalType.HasFlag(DisposalType.Async) ? $", {WellKnownTypes.AsyncDisposable.FullName()}" @@ -69,6 +93,13 @@ public override StringBuilder Build(StringBuilder stringBuilder) .AppendLine($"#nullable disable"); } + public override StringBuilder BuildCreateFunction(StringBuilder stringBuilder, FunctionResolution functionResolution) => + BuildFunction(stringBuilder, sb => GenerateResolutionFunction(sb, functionResolution)); + + public override StringBuilder BuildRangedFunction(StringBuilder stringBuilder, + RangedInstanceFunctionGroupResolution rangedInstanceFunctionGroupResolution) => + BuildFunction(stringBuilder, sb => GenerateRangedInstanceFunction(sb, rangedInstanceFunctionGroupResolution)); + public TransientScopeCodeBuilder( // parameter IContainerInfo containerInfo, diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index 893f5fe6..72a624b6 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -245,6 +245,13 @@ internal record TransientScopeInterfaceResolution( string Name, string ContainerAdapterName); +internal interface IRangeResolution +{ + string Name { get; } + IReadOnlyList CreateFunctions { get; } + IReadOnlyList RangedInstanceFunctionGroups { get; } +} + internal record ScopeResolution( IReadOnlyList CreateFunctions, DisposalHandling DisposalHandling, @@ -262,7 +269,7 @@ internal record ScopeResolution( RangedInstanceFunctionGroups, ContainerReference, AddForDisposal, - AddForDisposalAsync); + AddForDisposalAsync), IRangeResolution; internal record TransientScopeResolution( IReadOnlyList CreateFunctions, @@ -279,31 +286,34 @@ internal record TransientScopeResolution( RangedInstanceFunctionGroups, ContainerReference, AddForDisposal, - AddForDisposalAsync); + AddForDisposalAsync), IRangeResolution; internal record ContainerResolution( - IReadOnlyList CreateFunctions, - DisposalHandling DisposalHandling, - IReadOnlyList RangedInstanceFunctionGroups, - TransientScopeInterfaceResolution TransientScopeInterface, - string TransientScopeAdapterReference, - IReadOnlyList TransientScopes, - IReadOnlyList Scopes, - DisposalType DisposalType, - string TransientScopeDisposalReference, - string TransientScopeDisposalElement, - NopDisposable NopDisposable, - NopAsyncDisposable NopAsyncDisposable, - SyncToAsyncDisposable SyncToAsyncDisposable, - IMethodSymbol? AddForDisposal, - IMethodSymbol? AddForDisposalAsync) + IReadOnlyList CreateFunctions, + DisposalHandling DisposalHandling, + IReadOnlyList RangedInstanceFunctionGroups, + TransientScopeInterfaceResolution TransientScopeInterface, + string TransientScopeAdapterReference, + IReadOnlyList TransientScopes, + IReadOnlyList Scopes, + DisposalType DisposalType, + string TransientScopeDisposalReference, + string TransientScopeDisposalElement, + NopDisposable NopDisposable, + NopAsyncDisposable NopAsyncDisposable, + SyncToAsyncDisposable SyncToAsyncDisposable, + IMethodSymbol? AddForDisposal, + IMethodSymbol? AddForDisposalAsync) : RangeResolution( CreateFunctions, - DisposalHandling, - RangedInstanceFunctionGroups, + DisposalHandling, + RangedInstanceFunctionGroups, Constants.ThisKeyword, AddForDisposal, - AddForDisposalAsync); + AddForDisposalAsync), IRangeResolution +{ + public string Name => "Container"; +}; internal record NopDisposable( string ClassName, diff --git a/Sample/Container.cs b/Sample/Container.cs index eb8e52e2..b7325611 100644 --- a/Sample/Container.cs +++ b/Sample/Container.cs @@ -1,70 +1,41 @@ -using System.Threading.Tasks; +using System; using MrMeeseeks.DIE.Configuration.Attributes; using MrMeeseeks.DIE.Sample; -namespace MrMeeseeks.DIE.Test.Async.Awaited.TransientScopeInstanceFunction_DifferentSynchronicity; +namespace MrMeeseeks.DIE.Test.Disposal.ScopeUserDefinedAddForDisposal; -internal interface IInterface {} - -internal class DependencyA : IInterface, ITaskInitializer -{ - public bool IsInitialized { get; private set; } - - async Task ITaskInitializer.InitializeAsync() - { - await Task.Delay(500).ConfigureAwait(false); - IsInitialized = true; - } -} - -internal class DependencyB : IInterface -{ -} - -internal class Instance : ITransientScopeInstance +internal class Dependency : IDisposable { - public IInterface Inner { get; } + internal bool IsDisposed { get; private set; } - public Instance(IInterface inner) - { - Inner = inner; - } + public void Dispose() => IsDisposed = true; } -internal class TransientScopeRoot0 : ITransientScopeRoot +internal class ScopeRoot : IScopeRoot { - public Instance Dependency { get; } + public Dependency Dependency { get; } - internal TransientScopeRoot0(Instance dependency) + internal ScopeRoot(Dependency dependency) { Dependency = dependency; } } -internal class TransientScopeRoot1 : ITransientScopeRoot -{ - internal TransientScopeRoot1(Instance dependency) - { - - } -} - -[FilterImplementationAggregation(typeof(DependencyB))] -[CreateFunction(typeof(TransientScopeRoot0), "Create0")] -[CreateFunction(typeof(TransientScopeRoot1), "Create1")] +[CreateFunction(typeof(ScopeRoot), "Create")] internal sealed partial class Container { - [CustomScopeForRootTypes(typeof(TransientScopeRoot0))] - private sealed partial class DIE_TransientScope0 - { - - } - - [FilterImplementationAggregation(typeof(DependencyA))] - [ImplementationAggregation(typeof(DependencyB))] - [CustomScopeForRootTypes(typeof(TransientScopeRoot1))] - private sealed partial class DIE_TransientScope1 + private sealed partial class DIE_DefaultScope { - + private Dependency DIE_Factory_Dependency + { + get + { + var dependency = new Dependency(); + DIE_AddForDisposal(dependency); + return dependency; + } + } + + private partial void DIE_AddForDisposal(IDisposable disposable); } } \ No newline at end of file From 02bfe5792b917bb146eecfa3faf31b00fc201705 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sat, 17 Sep 2022 21:24:31 +0200 Subject: [PATCH 139/162] Revert "Own file for each generated function" This reverts commit 086d5674830657fa944291df2f6faca173436d0c. Revert "File per scope generation" This reverts commit 44f06b60d5d932f6b36570113819022e933601cd. --- Main/CodeBuilding/ContainerCodeBuilder.cs | 36 +++------ Main/CodeBuilding/ContainerGenerator.cs | 69 +++++----------- Main/CodeBuilding/RangeCodeBaseBuilder.cs | 19 ++--- Main/CodeBuilding/ScopeCodeBuilder.cs | 78 +++++-------------- .../CodeBuilding/TransientScopeCodeBuilder.cs | 72 ++++------------- Main/ResolutionTreeItem.cs | 50 +++++------- Main/SourceGenerator.cs | 8 +- Sample/Container.cs | 43 ++-------- 8 files changed, 106 insertions(+), 269 deletions(-) diff --git a/Main/CodeBuilding/ContainerCodeBuilder.cs b/Main/CodeBuilding/ContainerCodeBuilder.cs index e2aa67a0..4ead6f12 100644 --- a/Main/CodeBuilding/ContainerCodeBuilder.cs +++ b/Main/CodeBuilding/ContainerCodeBuilder.cs @@ -12,6 +12,8 @@ internal class ContainerCodeBuilder : RangeCodeBaseBuilder, IContainerCodeBuilde { private readonly IContainerInfo _containerInfo; private readonly ContainerResolution _containerResolution; + private readonly IReadOnlyList _transientScopeCodeBuilders; + private readonly IReadOnlyList _scopeCodeBuilders; protected override StringBuilder GenerateDisposalFunction_TransientScopeDictionary(StringBuilder stringBuilder) { @@ -54,24 +56,7 @@ protected override StringBuilder GenerateDisposalFunction_TransientScopeDisposal protected override bool ExplicitTransientScopeInstanceImplementation => false; - private StringBuilder BuildFunction(StringBuilder stringBuilder, Func functionResolution) - { - stringBuilder = stringBuilder - .AppendLine($"#nullable enable") - .AppendLine($"namespace {_containerInfo.Namespace}") - .AppendLine($"{{") - .AppendLine($"partial class {_containerInfo.Name}") - .AppendLine($"{{"); - - stringBuilder = functionResolution(stringBuilder); - - return stringBuilder - .AppendLine($"}}") - .AppendLine($"}}") - .AppendLine($"#nullable disable"); - } - - public override StringBuilder BuildGeneral(StringBuilder stringBuilder) + public override StringBuilder Build(StringBuilder stringBuilder) { var disposableImplementation = _containerResolution.DisposalType.HasFlag(DisposalType.Async) ? $" : {WellKnownTypes.AsyncDisposable.FullName()}" @@ -117,6 +102,10 @@ public override StringBuilder BuildGeneral(StringBuilder stringBuilder) .AppendLine($"private {_containerResolution.TransientScopeInterface.ContainerAdapterName}? _{_containerResolution.TransientScopeAdapterReference};") .AppendLine($"private {_containerResolution.TransientScopeInterface.ContainerAdapterName} {_containerResolution.TransientScopeAdapterReference} => _{_containerResolution.TransientScopeAdapterReference} ??= new {_containerResolution.TransientScopeInterface.ContainerAdapterName}(this);"); + stringBuilder = _transientScopeCodeBuilders.Aggregate(stringBuilder, (sb, cb) => cb.Build(sb)); + + stringBuilder = _scopeCodeBuilders.Aggregate(stringBuilder, (sb, cb) => cb.Build(sb)); + var disposableTypeFullName = WellKnownTypes.Disposable.FullName(); var asyncDisposableTypeFullName = WellKnownTypes.AsyncDisposable.FullName(); var valueTaskFullName = WellKnownTypes.ValueTask.FullName(); @@ -159,17 +148,12 @@ string SelectFullName(InterfaceFunctionDeclarationResolution interfaceResolution }; } - public override StringBuilder BuildCreateFunction(StringBuilder stringBuilder, FunctionResolution functionResolution) => - BuildFunction(stringBuilder, sb => GenerateResolutionFunction(sb, functionResolution)); - - public override StringBuilder BuildRangedFunction(StringBuilder stringBuilder, - RangedInstanceFunctionGroupResolution rangedInstanceFunctionGroupResolution) => - BuildFunction(stringBuilder, sb => GenerateRangedInstanceFunction(sb, rangedInstanceFunctionGroupResolution)); - public ContainerCodeBuilder( // parameter IContainerInfo containerInfo, ContainerResolution containerResolution, + IReadOnlyList transientScopeCodeBuilders, + IReadOnlyList scopeCodeBuilders, // dependencies WellKnownTypes wellKnownTypes) @@ -177,5 +161,7 @@ public ContainerCodeBuilder( { _containerInfo = containerInfo; _containerResolution = containerResolution; + _transientScopeCodeBuilders = transientScopeCodeBuilders; + _scopeCodeBuilders = scopeCodeBuilders; } } \ No newline at end of file diff --git a/Main/CodeBuilding/ContainerGenerator.cs b/Main/CodeBuilding/ContainerGenerator.cs index 99d68dba..05f3ac53 100644 --- a/Main/CodeBuilding/ContainerGenerator.cs +++ b/Main/CodeBuilding/ContainerGenerator.cs @@ -3,7 +3,7 @@ namespace MrMeeseeks.DIE.CodeBuilding; -internal interface IContainerGenerator +internal interface IContainerGenerator { void Generate(IContainerInfo containerInfo, ContainerResolution resolvable); } @@ -11,17 +11,20 @@ internal interface IContainerGenerator internal class ContainerGenerator : IContainerGenerator { private readonly GeneratorExecutionContext _context; - private readonly Func _containerCodeBuilderFactory; + private readonly IDiagLogger _diagLogger; + private readonly Func, IReadOnlyList, IContainerCodeBuilder> _containerCodeBuilderFactory; private readonly Func _transientScopeCodeBuilderFactory; private readonly Func _scopeCodeBuilderFactory; internal ContainerGenerator( GeneratorExecutionContext context, - Func containerCodeBuilderFactory, + IDiagLogger diagLogger, + Func, IReadOnlyList, IContainerCodeBuilder> containerCodeBuilderFactory, Func transientScopeCodeBuilderFactory, Func scopeCodeBuilderFactory) { _context = context; + _diagLogger = diagLogger; _containerCodeBuilderFactory = containerCodeBuilderFactory; _transientScopeCodeBuilderFactory = transientScopeCodeBuilderFactory; _scopeCodeBuilderFactory = scopeCodeBuilderFactory; @@ -29,53 +32,21 @@ internal ContainerGenerator( public void Generate(IContainerInfo containerInfo, ContainerResolution containerResolution) { - var containerCodeBuilder = _containerCodeBuilderFactory(containerInfo, containerResolution); - - GenerateRange(containerCodeBuilder, containerResolution); - - foreach (var transientScopeResolution in containerResolution.TransientScopes) - { - var transientScopeCodeBuilder = _transientScopeCodeBuilderFactory(containerInfo, transientScopeResolution, containerResolution); - GenerateRange(transientScopeCodeBuilder, transientScopeResolution); - } - - foreach (var scopeResolution in containerResolution.Scopes) - { - var scopeCodeBuilder = _scopeCodeBuilderFactory(containerInfo, scopeResolution, containerResolution.TransientScopeInterface, containerResolution); - GenerateRange(scopeCodeBuilder, scopeResolution); - } + var containerCodeBuilder = _containerCodeBuilderFactory( + containerInfo, + containerResolution, + containerResolution.TransientScopes.Select(ts => _transientScopeCodeBuilderFactory(containerInfo, ts, containerResolution)).ToList(), + containerResolution.Scopes.Select(s => _scopeCodeBuilderFactory(containerInfo, s, containerResolution.TransientScopeInterface, containerResolution)).ToList()); - void GenerateRange(IRangeCodeBaseBuilder rangeCodeBaseBuilder, IRangeResolution rangeResolution) - { - var generatedGeneral = rangeCodeBaseBuilder.BuildGeneral(new StringBuilder()); - RenderSourceFile($"{containerInfo.Namespace}.{containerInfo.Name}.{rangeResolution.Name}.g.cs", generatedGeneral); - generatedGeneral.Clear(); - - foreach (var createFunction in rangeResolution.CreateFunctions) - { - var generatedCreateFunction = rangeCodeBaseBuilder.BuildCreateFunction(new StringBuilder(), createFunction); - RenderSourceFile($"{containerInfo.Namespace}.{containerInfo.Name}.{rangeResolution.Name}.{createFunction.Reference}.g.cs", generatedCreateFunction); - generatedCreateFunction.Clear(); - } - - foreach (var rangedInstanceFunctionGroup in rangeResolution.RangedInstanceFunctionGroups) - { - var generatedInstanceFunctionGroupFunction = rangeCodeBaseBuilder.BuildRangedFunction(new StringBuilder(), rangedInstanceFunctionGroup); - RenderSourceFile($"{containerInfo.Namespace}.{containerInfo.Name}.{rangeResolution.Name}.{rangedInstanceFunctionGroup.Overloads[0].Reference}.g.cs", generatedInstanceFunctionGroupFunction); - generatedInstanceFunctionGroupFunction.Clear(); - } - } - - void RenderSourceFile(string fileName, StringBuilder compiledCode) - { - var containerSource = CSharpSyntaxTree - .ParseText(SourceText.From(compiledCode.ToString(), Encoding.UTF8)) - .GetRoot() - .NormalizeWhitespace() - .SyntaxTree - .GetText(); + var generatedContainer = containerCodeBuilder.Build(new StringBuilder()); + + var containerSource = CSharpSyntaxTree + .ParseText(SourceText.From(generatedContainer.ToString(), Encoding.UTF8)) + .GetRoot() + .NormalizeWhitespace() + .SyntaxTree + .GetText(); - _context.AddSource(fileName, containerSource); - } + _context.AddSource($"{containerInfo.Namespace}.{containerInfo.Name}.g.cs", containerSource); } } \ No newline at end of file diff --git a/Main/CodeBuilding/RangeCodeBaseBuilder.cs b/Main/CodeBuilding/RangeCodeBaseBuilder.cs index 5db2aa51..18fc16a0 100644 --- a/Main/CodeBuilding/RangeCodeBaseBuilder.cs +++ b/Main/CodeBuilding/RangeCodeBaseBuilder.cs @@ -5,9 +5,7 @@ namespace MrMeeseeks.DIE.CodeBuilding; internal interface IRangeCodeBaseBuilder { - StringBuilder BuildGeneral(StringBuilder stringBuilder); - StringBuilder BuildCreateFunction(StringBuilder stringBuilder, FunctionResolution functionResolution); - StringBuilder BuildRangedFunction(StringBuilder stringBuilder, RangedInstanceFunctionGroupResolution rangedInstanceFunctionGroupResolution); + StringBuilder Build(StringBuilder stringBuilder); } internal abstract class RangeCodeBaseBuilder : IRangeCodeBaseBuilder @@ -30,6 +28,10 @@ protected StringBuilder GenerateResolutionRange( StringBuilder stringBuilder, RangeResolution rangeResolution) { + stringBuilder = rangeResolution.RangedInstanceFunctionGroups.Aggregate(stringBuilder, GenerateRangedInstanceFunction); + + stringBuilder = rangeResolution.CreateFunctions.Aggregate(stringBuilder, GenerateResolutionFunction); + if (_rangeResolution.AddForDisposal is { } addForDisposalMethod) { stringBuilder = stringBuilder @@ -168,7 +170,7 @@ private StringBuilder GenerateDisposalFunction( return stringBuilder; } - protected StringBuilder GenerateResolutionFunction( + private StringBuilder GenerateResolutionFunction( StringBuilder stringBuilder, FunctionResolution resolution) { @@ -474,7 +476,7 @@ private StringBuilder GenerateResolutions( private StringBuilder ObjectDisposedCheck(StringBuilder stringBuilder, string returnTypeFullName) => stringBuilder .AppendLine($"if (this.{_rangeResolution.DisposalHandling.DisposedPropertyReference}) throw new {WellKnownTypes.ObjectDisposedException}(\"{_rangeResolution.DisposalHandling.RangeName}\", $\"[DIE] This scope \\\"{_rangeResolution.DisposalHandling.RangeName}\\\" is already disposed, so it can't create a \\\"{returnTypeFullName}\\\" instance anymore.\");"); - protected StringBuilder GenerateRangedInstanceFunction(StringBuilder stringBuilder, RangedInstanceFunctionGroupResolution rangedInstanceFunctionGroupResolution) + private StringBuilder GenerateRangedInstanceFunction(StringBuilder stringBuilder, RangedInstanceFunctionGroupResolution rangedInstanceFunctionGroupResolution) { var isRefType = rangedInstanceFunctionGroupResolution.IsCreatedForStructs is null; stringBuilder = stringBuilder @@ -541,10 +543,5 @@ protected StringBuilder GenerateRangedInstanceFunction(StringBuilder stringBuild return stringBuilder; } - public abstract StringBuilder BuildGeneral(StringBuilder stringBuilder); - public abstract StringBuilder BuildCreateFunction(StringBuilder stringBuilder, FunctionResolution functionResolution); - - public abstract StringBuilder BuildRangedFunction( - StringBuilder stringBuilder, - RangedInstanceFunctionGroupResolution rangedInstanceFunctionGroupResolution); + public abstract StringBuilder Build(StringBuilder stringBuilder); } \ No newline at end of file diff --git a/Main/CodeBuilding/ScopeCodeBuilder.cs b/Main/CodeBuilding/ScopeCodeBuilder.cs index f016c4dd..3c277f57 100644 --- a/Main/CodeBuilding/ScopeCodeBuilder.cs +++ b/Main/CodeBuilding/ScopeCodeBuilder.cs @@ -4,12 +4,13 @@ namespace MrMeeseeks.DIE.CodeBuilding; internal interface IScopeCodeBuilder : IRangeCodeBaseBuilder { - ScopeResolution ScopeResolution { get; } + } internal class ScopeCodeBuilder : RangeCodeBaseBuilder, IScopeCodeBuilder { private readonly IContainerInfo _containerInfo; + private readonly ScopeResolution _scopeResolution; private readonly TransientScopeInterfaceResolution _transientScopeInterfaceResolution; private readonly ContainerResolution _containerResolution; @@ -19,76 +20,35 @@ internal class ScopeCodeBuilder : RangeCodeBaseBuilder, IScopeCodeBuilder protected override bool ExplicitTransientScopeInstanceImplementation => false; - public StringBuilder BuildFunction(StringBuilder stringBuilder, Func functionResolution) + public override StringBuilder Build(StringBuilder stringBuilder) { - stringBuilder = stringBuilder - .AppendLine($"#nullable enable") - .AppendLine($"namespace {_containerInfo.Namespace}") - .AppendLine($"{{") - .AppendLine($"partial class {_containerInfo.Name}") - .AppendLine($"{{"); - - stringBuilder = stringBuilder - .AppendLine($"private partial class {ScopeResolution.Name}") - .AppendLine($"{{"); - - stringBuilder = functionResolution(stringBuilder); - - stringBuilder = stringBuilder - .AppendLine($"}}"); - - return stringBuilder - .AppendLine($"}}") - .AppendLine($"}}") - .AppendLine($"#nullable disable"); - } - - public override StringBuilder BuildGeneral(StringBuilder stringBuilder) - { - var disposableImplementation = _containerResolution.DisposalType.HasFlag(DisposalType.Async) - ? $" : {WellKnownTypes.AsyncDisposable.FullName()}" - : $" : {WellKnownTypes.AsyncDisposable.FullName()}, {WellKnownTypes.Disposable.FullName()}"; - - stringBuilder = stringBuilder - .AppendLine($"#nullable enable") - .AppendLine($"namespace {_containerInfo.Namespace}") - .AppendLine($"{{") - .AppendLine($"partial class {_containerInfo.Name}") - .AppendLine($"{{"); + var disposableImplementation = _containerResolution.DisposalType.HasFlag(DisposalType.Async) + ? $" : {WellKnownTypes.AsyncDisposable.FullName()}" + : $" : {WellKnownTypes.AsyncDisposable.FullName()}, {WellKnownTypes.Disposable.FullName()}"; stringBuilder = stringBuilder .AppendLine( - $"private partial class {ScopeResolution.Name}{disposableImplementation}") + $"private partial class {_scopeResolution.Name}{disposableImplementation}") .AppendLine($"{{") - .AppendLine($"private readonly {_containerInfo.FullName} {ScopeResolution.ContainerReference};") - .AppendLine($"private readonly {_transientScopeInterfaceResolution.Name} {ScopeResolution.TransientScopeReference};") - .AppendLine($"internal {ScopeResolution.Name}(") - .AppendLine($"{_containerInfo.FullName} {ScopeResolution.ContainerParameterReference},") - .AppendLine($"{_transientScopeInterfaceResolution.Name} {ScopeResolution.TransientScopeParameterReference})") + .AppendLine($"private readonly {_containerInfo.FullName} {_scopeResolution.ContainerReference};") + .AppendLine($"private readonly {_transientScopeInterfaceResolution.Name} {_scopeResolution.TransientScopeReference};") + .AppendLine($"internal {_scopeResolution.Name}(") + .AppendLine($"{_containerInfo.FullName} {_scopeResolution.ContainerParameterReference},") + .AppendLine($"{_transientScopeInterfaceResolution.Name} {_scopeResolution.TransientScopeParameterReference})") .AppendLine($"{{") - .AppendLine($"{ScopeResolution.ContainerReference} = {ScopeResolution.ContainerParameterReference};") - .AppendLine($"{ScopeResolution.TransientScopeReference} = {ScopeResolution.TransientScopeParameterReference};") + .AppendLine($"{_scopeResolution.ContainerReference} = {_scopeResolution.ContainerParameterReference};") + .AppendLine($"{_scopeResolution.TransientScopeReference} = {_scopeResolution.TransientScopeParameterReference};") .AppendLine($"}}"); stringBuilder = GenerateResolutionRange( stringBuilder, - ScopeResolution); + _scopeResolution); stringBuilder = stringBuilder .AppendLine($"}}"); - - return stringBuilder - .AppendLine($"}}") - .AppendLine($"}}") - .AppendLine($"#nullable disable"); - } - - public override StringBuilder BuildCreateFunction(StringBuilder stringBuilder, FunctionResolution functionResolution) => - BuildFunction(stringBuilder, sb => GenerateResolutionFunction(sb, functionResolution)); - public override StringBuilder BuildRangedFunction(StringBuilder stringBuilder, - RangedInstanceFunctionGroupResolution rangedInstanceFunctionGroupResolution) => - BuildFunction(stringBuilder, sb => GenerateRangedInstanceFunction(sb, rangedInstanceFunctionGroupResolution)); + return stringBuilder; + } public ScopeCodeBuilder( // parameter @@ -102,10 +62,8 @@ public ScopeCodeBuilder( : base(scopeResolution, containerResolution, wellKnownTypes) { _containerInfo = containerInfo; - ScopeResolution = scopeResolution; + _scopeResolution = scopeResolution; _transientScopeInterfaceResolution = transientScopeInterfaceResolution; _containerResolution = containerResolution; } - - public ScopeResolution ScopeResolution { get; } } \ No newline at end of file diff --git a/Main/CodeBuilding/TransientScopeCodeBuilder.cs b/Main/CodeBuilding/TransientScopeCodeBuilder.cs index a4e48de3..16f55975 100644 --- a/Main/CodeBuilding/TransientScopeCodeBuilder.cs +++ b/Main/CodeBuilding/TransientScopeCodeBuilder.cs @@ -4,15 +4,14 @@ namespace MrMeeseeks.DIE.CodeBuilding; internal interface ITransientScopeCodeBuilder : IRangeCodeBaseBuilder { - public TransientScopeResolution TransientScopeResolution { get; } + } internal class TransientScopeCodeBuilder : RangeCodeBaseBuilder, ITransientScopeCodeBuilder { private readonly IContainerInfo _containerInfo; + private readonly TransientScopeResolution _transientScopeResolution; private readonly ContainerResolution _containerResolution; - - public TransientScopeResolution TransientScopeResolution { get; } protected override StringBuilder GenerateDisposalFunction_TransientScopeDictionary(StringBuilder stringBuilder) => stringBuilder; @@ -26,79 +25,38 @@ protected override StringBuilder GenerateDisposalFunction_TransientScopeDisposal : WellKnownTypes.Disposable.FullName(); stringBuilder - .AppendLine($"{TransientScopeResolution.ContainerReference}.{_containerResolution.TransientScopeDisposalReference}.TryRemove(({disposalType}) this, out _);"); + .AppendLine($"{_transientScopeResolution.ContainerReference}.{_containerResolution.TransientScopeDisposalReference}.TryRemove(({disposalType}) this, out _);"); return stringBuilder; } protected override bool ExplicitTransientScopeInstanceImplementation => true; - public StringBuilder BuildFunction(StringBuilder stringBuilder, Func functionResolution) - { - stringBuilder = stringBuilder - .AppendLine($"#nullable enable") - .AppendLine($"namespace {_containerInfo.Namespace}") - .AppendLine($"{{") - .AppendLine($"partial class {_containerInfo.Name}") - .AppendLine($"{{"); - - stringBuilder = stringBuilder - .AppendLine($"private partial class {TransientScopeResolution.Name}") - .AppendLine($"{{"); - - stringBuilder = functionResolution(stringBuilder); - - stringBuilder = stringBuilder - .AppendLine($"}}"); - - return stringBuilder - .AppendLine($"}}") - .AppendLine($"}}") - .AppendLine($"#nullable disable"); - } - - public override StringBuilder BuildGeneral(StringBuilder stringBuilder) + public override StringBuilder Build(StringBuilder stringBuilder) { - var disposableImplementation = _containerResolution.DisposalType.HasFlag(DisposalType.Async) - ? $", {WellKnownTypes.AsyncDisposable.FullName()}" + var disposableImplementation = _containerResolution.DisposalType.HasFlag(DisposalType.Async) + ? $", {WellKnownTypes.AsyncDisposable.FullName()}" : $", {WellKnownTypes.AsyncDisposable.FullName()}, {WellKnownTypes.Disposable.FullName()}"; stringBuilder = stringBuilder - .AppendLine($"#nullable enable") - .AppendLine($"namespace {_containerInfo.Namespace}") - .AppendLine($"{{") - .AppendLine($"partial class {_containerInfo.Name}") - .AppendLine($"{{"); - - stringBuilder = stringBuilder - .AppendLine($"private partial class {TransientScopeResolution.Name} : {_containerResolution.TransientScopeInterface.Name}{disposableImplementation}") + .AppendLine($"private partial class {_transientScopeResolution.Name} : {_containerResolution.TransientScopeInterface.Name}{disposableImplementation}") .AppendLine($"{{") - .AppendLine($"private readonly {_containerInfo.FullName} {TransientScopeResolution.ContainerReference};") - .AppendLine($"internal {TransientScopeResolution.Name}(") - .AppendLine($"{_containerInfo.FullName} {TransientScopeResolution.ContainerParameterReference})") + .AppendLine($"private readonly {_containerInfo.FullName} {_transientScopeResolution.ContainerReference};") + .AppendLine($"internal {_transientScopeResolution.Name}(") + .AppendLine($"{_containerInfo.FullName} {_transientScopeResolution.ContainerParameterReference})") .AppendLine($"{{") - .AppendLine($"{TransientScopeResolution.ContainerReference} = {TransientScopeResolution.ContainerParameterReference};") + .AppendLine($"{_transientScopeResolution.ContainerReference} = {_transientScopeResolution.ContainerParameterReference};") .AppendLine($"}}"); stringBuilder = GenerateResolutionRange( stringBuilder, - TransientScopeResolution); + _transientScopeResolution); stringBuilder = stringBuilder .AppendLine($"}}"); - - return stringBuilder - .AppendLine($"}}") - .AppendLine($"}}") - .AppendLine($"#nullable disable"); - } - - public override StringBuilder BuildCreateFunction(StringBuilder stringBuilder, FunctionResolution functionResolution) => - BuildFunction(stringBuilder, sb => GenerateResolutionFunction(sb, functionResolution)); - public override StringBuilder BuildRangedFunction(StringBuilder stringBuilder, - RangedInstanceFunctionGroupResolution rangedInstanceFunctionGroupResolution) => - BuildFunction(stringBuilder, sb => GenerateRangedInstanceFunction(sb, rangedInstanceFunctionGroupResolution)); + return stringBuilder; + } public TransientScopeCodeBuilder( // parameter @@ -111,7 +69,7 @@ public TransientScopeCodeBuilder( : base(transientScopeResolution, containerResolution, wellKnownTypes) { _containerInfo = containerInfo; - TransientScopeResolution = transientScopeResolution; + _transientScopeResolution = transientScopeResolution; _containerResolution = containerResolution; } } \ No newline at end of file diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index 72a624b6..893f5fe6 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -245,13 +245,6 @@ internal record TransientScopeInterfaceResolution( string Name, string ContainerAdapterName); -internal interface IRangeResolution -{ - string Name { get; } - IReadOnlyList CreateFunctions { get; } - IReadOnlyList RangedInstanceFunctionGroups { get; } -} - internal record ScopeResolution( IReadOnlyList CreateFunctions, DisposalHandling DisposalHandling, @@ -269,7 +262,7 @@ internal record ScopeResolution( RangedInstanceFunctionGroups, ContainerReference, AddForDisposal, - AddForDisposalAsync), IRangeResolution; + AddForDisposalAsync); internal record TransientScopeResolution( IReadOnlyList CreateFunctions, @@ -286,34 +279,31 @@ internal record TransientScopeResolution( RangedInstanceFunctionGroups, ContainerReference, AddForDisposal, - AddForDisposalAsync), IRangeResolution; + AddForDisposalAsync); internal record ContainerResolution( - IReadOnlyList CreateFunctions, - DisposalHandling DisposalHandling, - IReadOnlyList RangedInstanceFunctionGroups, - TransientScopeInterfaceResolution TransientScopeInterface, - string TransientScopeAdapterReference, - IReadOnlyList TransientScopes, - IReadOnlyList Scopes, - DisposalType DisposalType, - string TransientScopeDisposalReference, - string TransientScopeDisposalElement, - NopDisposable NopDisposable, - NopAsyncDisposable NopAsyncDisposable, - SyncToAsyncDisposable SyncToAsyncDisposable, - IMethodSymbol? AddForDisposal, - IMethodSymbol? AddForDisposalAsync) + IReadOnlyList CreateFunctions, + DisposalHandling DisposalHandling, + IReadOnlyList RangedInstanceFunctionGroups, + TransientScopeInterfaceResolution TransientScopeInterface, + string TransientScopeAdapterReference, + IReadOnlyList TransientScopes, + IReadOnlyList Scopes, + DisposalType DisposalType, + string TransientScopeDisposalReference, + string TransientScopeDisposalElement, + NopDisposable NopDisposable, + NopAsyncDisposable NopAsyncDisposable, + SyncToAsyncDisposable SyncToAsyncDisposable, + IMethodSymbol? AddForDisposal, + IMethodSymbol? AddForDisposalAsync) : RangeResolution( CreateFunctions, - DisposalHandling, - RangedInstanceFunctionGroups, + DisposalHandling, + RangedInstanceFunctionGroups, Constants.ThisKeyword, AddForDisposal, - AddForDisposalAsync), IRangeResolution -{ - public string Name => "Container"; -}; + AddForDisposalAsync); internal record NopDisposable( string ClassName, diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index 68bbf0d7..75b2dbe7 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -87,7 +87,7 @@ public void Execute(GeneratorExecutionContext context) if (assemblyTypesFromAttributes.Errors.Any()) return; - var containerGenerator = new ContainerGenerator(context, ContainerCodeBuilderFactory, TransientScopeCodeBuilderFactory, ScopeCodeBuilderFactory); + var containerGenerator = new ContainerGenerator(context, diagLogger, ContainerCodeBuilderFactory, TransientScopeCodeBuilderFactory, ScopeCodeBuilderFactory); var referenceGeneratorFactory = new ReferenceGeneratorFactory(ReferenceGeneratorFactory); var containerDieExceptionGenerator = new ContainerDieExceptionGenerator(context, wellKnownTypesMiscellaneous); var implementationTypeSetCache = new ImplementationTypeSetCache(context, wellKnownTypes); @@ -286,9 +286,13 @@ IFunctionResolutionSynchronicityDecisionMaker FunctionResolutionSynchronicityDec IContainerCodeBuilder ContainerCodeBuilderFactory( IContainerInfo containerInfo, - ContainerResolution containerResolution) => new ContainerCodeBuilder( + ContainerResolution containerResolution, + IReadOnlyList transientScopeCodeBuilders, + IReadOnlyList scopeCodeBuilders) => new ContainerCodeBuilder( containerInfo, containerResolution, + transientScopeCodeBuilders, + scopeCodeBuilders, wellKnownTypes); ITransientScopeCodeBuilder TransientScopeCodeBuilderFactory( diff --git a/Sample/Container.cs b/Sample/Container.cs index b7325611..3e8d5176 100644 --- a/Sample/Container.cs +++ b/Sample/Container.cs @@ -1,41 +1,14 @@ -using System; -using MrMeeseeks.DIE.Configuration.Attributes; -using MrMeeseeks.DIE.Sample; +using MrMeeseeks.DIE.Configuration.Attributes; -namespace MrMeeseeks.DIE.Test.Disposal.ScopeUserDefinedAddForDisposal; +namespace MrMeeseeks.DIE.Test.Bugs.UngenericImplementationGenericInterface; -internal class Dependency : IDisposable -{ - internal bool IsDisposed { get; private set; } +internal interface IInterface {} - public void Dispose() => IsDisposed = true; -} +internal class DependencyA : IInterface {} -internal class ScopeRoot : IScopeRoot -{ - public Dependency Dependency { get; } +internal class DependencyB : IInterface {} - internal ScopeRoot(Dependency dependency) - { - Dependency = dependency; - } -} +internal class DependencyC : IInterface {} -[CreateFunction(typeof(ScopeRoot), "Create")] -internal sealed partial class Container -{ - private sealed partial class DIE_DefaultScope - { - private Dependency DIE_Factory_Dependency - { - get - { - var dependency = new Dependency(); - DIE_AddForDisposal(dependency); - return dependency; - } - } - - private partial void DIE_AddForDisposal(IDisposable disposable); - } -} \ No newline at end of file +[CreateFunction(typeof(IInterface), "Create")] +internal sealed partial class Container {} \ No newline at end of file From 16098a0d4f6885b19328c94e80333dff63b589c5 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sun, 18 Sep 2022 12:46:05 +0200 Subject: [PATCH 140/162] Performance attempt: No parsing of generated code --- Main/CodeBuilding/ContainerGenerator.cs | 6 +++--- Main/Main.csproj | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Main/CodeBuilding/ContainerGenerator.cs b/Main/CodeBuilding/ContainerGenerator.cs index 05f3ac53..71514a43 100644 --- a/Main/CodeBuilding/ContainerGenerator.cs +++ b/Main/CodeBuilding/ContainerGenerator.cs @@ -40,13 +40,13 @@ public void Generate(IContainerInfo containerInfo, ContainerResolution container var generatedContainer = containerCodeBuilder.Build(new StringBuilder()); - var containerSource = CSharpSyntaxTree + /*var containerSource = CSharpSyntaxTree .ParseText(SourceText.From(generatedContainer.ToString(), Encoding.UTF8)) .GetRoot() .NormalizeWhitespace() .SyntaxTree - .GetText(); + .GetText();*/ - _context.AddSource($"{containerInfo.Namespace}.{containerInfo.Name}.g.cs", containerSource); + _context.AddSource($"{containerInfo.Namespace}.{containerInfo.Name}.g.cs", generatedContainer.ToString()); } } \ No newline at end of file diff --git a/Main/Main.csproj b/Main/Main.csproj index 2563c09d..15916b56 100644 --- a/Main/Main.csproj +++ b/Main/Main.csproj @@ -35,7 +35,6 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - From 40de16b2dbddf02dea961f63d63ce60f0c63a7e3 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sun, 18 Sep 2022 14:07:20 +0200 Subject: [PATCH 141/162] Logging --- Main/Diagnostics.cs | 44 +++++++++++++++++++++++++++++++++----------- Main/ExecuteImpl.cs | 17 ++++++++++++++++- 2 files changed, 49 insertions(+), 12 deletions(-) diff --git a/Main/Diagnostics.cs b/Main/Diagnostics.cs index 2984ca6c..1989c9e2 100644 --- a/Main/Diagnostics.cs +++ b/Main/Diagnostics.cs @@ -11,7 +11,8 @@ public static Diagnostic CircularReferenceInsideFactory(ImplementationCycleDieEx return Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_68_00", "Circular Reference Exception (inside factory)", $"This container and/or its configuration lead to a circular reference inside one of its factory functions, which need to be generated. The implementations involved in the cycle are: {cycleText}", - "Error", DiagnosticSeverity.Error, + "Error", + DiagnosticSeverity.Error, true), Location.None); } @@ -21,7 +22,8 @@ public static Diagnostic CircularReferenceInsideFactory(ImplementationCycleDieEx Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_68_01", "Circular Reference Exception (among factories)", "This container and/or its configuration lead to a circular reference among factory functions, which need to be generated.", - "Error", DiagnosticSeverity.Error, + "Error", + DiagnosticSeverity.Error, true), Location.None); @@ -29,7 +31,8 @@ public static Diagnostic ValidationContainer(INamedTypeSymbol container, string Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_67_00", "Validation (Container)", $"The Container \"{container.Name}\" isn't validly defined: {specification}", - "Error", DiagnosticSeverity.Error, + "Error", + DiagnosticSeverity.Error, true), container.Locations.FirstOrDefault() ?? Location.None); @@ -37,7 +40,8 @@ public static Diagnostic ValidationContainer(INamedTypeSymbol container, string Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_67_00", "Validation (Container)", $"The Container \"{container.Name}\" isn't validly defined: {specification}", - "Error", DiagnosticSeverity.Error, + "Error", + DiagnosticSeverity.Error, true), location); @@ -45,7 +49,8 @@ public static Diagnostic ValidationTransientScope(INamedTypeSymbol transientScop Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_67_01", "Validation (TransientScope)", $"The TransientScope \"{transientScope.Name}\" (of parent-Container \"{parentContainer.Name}\") isn't validly defined: {specification}", - "Error", DiagnosticSeverity.Error, + "Error", + DiagnosticSeverity.Error, true), transientScope.Locations.FirstOrDefault() ?? Location.None); @@ -53,7 +58,8 @@ public static Diagnostic ValidationScope(INamedTypeSymbol scope, INamedTypeSymbo Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_67_02", "Validation (Scope)", $"The Scope \"{scope.Name}\" (of parent-Container \"{parentContainer.Name}\") isn't validly defined: {specification}", - "Error", DiagnosticSeverity.Error, + "Error", + DiagnosticSeverity.Error, true), scope.Locations.FirstOrDefault() ?? Location.None); @@ -65,7 +71,8 @@ public static Diagnostic ValidationUserDefinedElement(ISymbol userDefinedElement return Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_67_03", "Validation (User-Defined Element)", $"The user-defined \"{userDefinedElement.Name}\" (of {rangeDescription}) isn't validly defined: {specification}", - "Error", DiagnosticSeverity.Error, + "Error", + DiagnosticSeverity.Error, true), userDefinedElement.Locations.FirstOrDefault() ?? Location.None); } @@ -82,7 +89,8 @@ public static Diagnostic ValidationConfigurationAttribute(AttributeData attribut return Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_67_03", "Validation (Configuration Attribute)", $"The configuration attribute \"{attributeData.AttributeClass?.Name}\" (of {rangeDescription}) isn't validly defined: {specification}", - "Error", DiagnosticSeverity.Error, + "Error", + DiagnosticSeverity.Error, true), attributeData.GetLocation()); } @@ -92,7 +100,8 @@ public static Diagnostic UnexpectedDieException(DieException exception) return Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_66_00", "Unexpected Exception (DIE)", exception.ToString(), - "Error", DiagnosticSeverity.Error, + "Error", + DiagnosticSeverity.Error, true), Location.None); } @@ -102,7 +111,8 @@ public static Diagnostic UnexpectedException(Exception exception) return Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_66_01", "Unexpected Exception (General)", exception.ToString(), - "Error", DiagnosticSeverity.Error, + "Error", + DiagnosticSeverity.Error, true), Location.None); } @@ -112,8 +122,20 @@ public static Diagnostic CompilationError(string message, Location location) return Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_65_00", "Error During Compilation", message, - "Error", DiagnosticSeverity.Error, + "Error", + DiagnosticSeverity.Error, true), location); } + + public static Diagnostic Logging(string message) + { + return Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_00_00", + "Logging", + message, + "Log", + DiagnosticSeverity.Warning, + true), + Location.None); + } } \ No newline at end of file diff --git a/Main/ExecuteImpl.cs b/Main/ExecuteImpl.cs index 63be8c83..6f1cc2ee 100644 --- a/Main/ExecuteImpl.cs +++ b/Main/ExecuteImpl.cs @@ -1,4 +1,5 @@ -using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.CodeDom.Compiler; +using Microsoft.CodeAnalysis.CSharp.Syntax; using MrMeeseeks.DIE.CodeBuilding; using MrMeeseeks.DIE.ResolutionBuilding; using MrMeeseeks.DIE.Validation.Range; @@ -62,23 +63,37 @@ public void Execute() { try { + DateTime start = DateTime.Now; + _context.ReportDiagnostic(Diagnostics.Logging($"Start {start}")); var containerInfo = _containerInfoFactory(containerSymbol); var validationDiagnostics = _validateContainer.Validate(containerInfo.ContainerType, containerInfo.ContainerType) .ToImmutableArray(); if (!validationDiagnostics.Any()) { + _context.ReportDiagnostic(Diagnostics.Logging($"Validation {DateTime.Now - start}")); + start = DateTime.Now; var containerResolutionBuilder = _containerResolutionBuilderFactory(containerInfo); + _context.ReportDiagnostic(Diagnostics.Logging($"Building Container Builder {DateTime.Now - start}")); + start = DateTime.Now; containerResolutionBuilder.AddCreateResolveFunctions(containerInfo.CreateFunctionData); + _context.ReportDiagnostic(Diagnostics.Logging($"Create Resolve Functions {DateTime.Now - start}")); + start = DateTime.Now; while (containerResolutionBuilder.HasWorkToDo) { containerResolutionBuilder.DoWork(); } + _context.ReportDiagnostic(Diagnostics.Logging($"Do work {DateTime.Now - start}")); + start = DateTime.Now; containerResolutionBuilder.FunctionCycleTracker.DetectCycle(); + _context.ReportDiagnostic(Diagnostics.Logging($"Detect cycles {DateTime.Now - start}")); + start = DateTime.Now; var containerResolution = containerResolutionBuilder.Build(); _containerGenerator.Generate(containerInfo, containerResolution); + _context.ReportDiagnostic(Diagnostics.Logging($"Generate Code {DateTime.Now - start}")); + start = DateTime.Now; } else { From c6bbab41bd2495e5679af55c838de8ee9132718f Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sun, 18 Sep 2022 15:52:41 +0200 Subject: [PATCH 142/162] Optimizing cycle detection --- .../Function/FunctionCycleTracker.cs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Main/ResolutionBuilding/Function/FunctionCycleTracker.cs b/Main/ResolutionBuilding/Function/FunctionCycleTracker.cs index 4ff10520..6d1a856f 100644 --- a/Main/ResolutionBuilding/Function/FunctionCycleTracker.cs +++ b/Main/ResolutionBuilding/Function/FunctionCycleTracker.cs @@ -22,17 +22,20 @@ public void TrackFunctionCall(FunctionResolutionBuilderHandle from, FunctionReso public void DetectCycle() { foreach (var function in _adjacencyMap.Keys) - DetectCycleInner(function, ImmutableStack.Empty); + DetectCycleInner(function, new Stack(), new HashSet()); - void DetectCycleInner(FunctionResolutionBuilderHandle current, IImmutableStack stack) + void DetectCycleInner(FunctionResolutionBuilderHandle current, Stack stack, HashSet visited) { - if (stack.Any(h => h.Identity == current.Identity)) + if (visited.Contains(current.Identity)) throw new FunctionCycleDieException(); if (_adjacencyMap.TryGetValue(current, out var neighbors)) { - stack = stack.Push(current); + stack.Push(current); + visited.Add(current.Identity); foreach (var neighbor in neighbors) - DetectCycleInner(neighbor, stack); + DetectCycleInner(neighbor, stack, visited); + visited.Remove(current.Identity); + stack.Pop(); } } } From a7630adbaa1b3de203e8de4add9717112cea5b73 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sun, 18 Sep 2022 16:02:42 +0200 Subject: [PATCH 143/162] Optimizing cycle detection v2 --- Main/ResolutionBuilding/Function/FunctionCycleTracker.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Main/ResolutionBuilding/Function/FunctionCycleTracker.cs b/Main/ResolutionBuilding/Function/FunctionCycleTracker.cs index 6d1a856f..130ae606 100644 --- a/Main/ResolutionBuilding/Function/FunctionCycleTracker.cs +++ b/Main/ResolutionBuilding/Function/FunctionCycleTracker.cs @@ -22,20 +22,18 @@ public void TrackFunctionCall(FunctionResolutionBuilderHandle from, FunctionReso public void DetectCycle() { foreach (var function in _adjacencyMap.Keys) - DetectCycleInner(function, new Stack(), new HashSet()); + DetectCycleInner(function, new HashSet()); - void DetectCycleInner(FunctionResolutionBuilderHandle current, Stack stack, HashSet visited) + void DetectCycleInner(FunctionResolutionBuilderHandle current, HashSet visited) { if (visited.Contains(current.Identity)) throw new FunctionCycleDieException(); if (_adjacencyMap.TryGetValue(current, out var neighbors)) { - stack.Push(current); visited.Add(current.Identity); foreach (var neighbor in neighbors) - DetectCycleInner(neighbor, stack, visited); + DetectCycleInner(neighbor, visited); visited.Remove(current.Identity); - stack.Pop(); } } } From 868598c4f2bba9dd26dd092cdc680dfb94e52779 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sun, 18 Sep 2022 17:06:48 +0200 Subject: [PATCH 144/162] Optimizing cycle detection v3 --- Main/CodeBuilding/ContainerGenerator.cs | 6 +++--- .../ContainerResolutionBuilder.cs | 13 ++++++++++--- .../Function/FunctionCycleTracker.cs | 7 ++++++- .../Function/FunctionResolutionBuilder.cs | 11 ++++++----- 4 files changed, 25 insertions(+), 12 deletions(-) diff --git a/Main/CodeBuilding/ContainerGenerator.cs b/Main/CodeBuilding/ContainerGenerator.cs index 71514a43..05f3ac53 100644 --- a/Main/CodeBuilding/ContainerGenerator.cs +++ b/Main/CodeBuilding/ContainerGenerator.cs @@ -40,13 +40,13 @@ public void Generate(IContainerInfo containerInfo, ContainerResolution container var generatedContainer = containerCodeBuilder.Build(new StringBuilder()); - /*var containerSource = CSharpSyntaxTree + var containerSource = CSharpSyntaxTree .ParseText(SourceText.From(generatedContainer.ToString(), Encoding.UTF8)) .GetRoot() .NormalizeWhitespace() .SyntaxTree - .GetText();*/ + .GetText(); - _context.AddSource($"{containerInfo.Namespace}.{containerInfo.Name}.g.cs", generatedContainer.ToString()); + _context.AddSource($"{containerInfo.Namespace}.{containerInfo.Name}.g.cs", containerSource); } } \ No newline at end of file diff --git a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs index 7c06e142..7dc44a58 100644 --- a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs @@ -73,11 +73,18 @@ internal ContainerResolutionBuilder( public void AddCreateResolveFunctions(IReadOnlyList<(ITypeSymbol, string)> createFunctionData) { foreach (var (typeSymbol, methodNamePrefix) in createFunctionData) - _rootResolutions.Add((CreateCreateFunctionResolution( - typeSymbol, + { + var functionResolution = CreateCreateFunctionResolution( + typeSymbol, ImmutableSortedDictionary.Empty, - Constants.PrivateKeyword), + Constants.PrivateKeyword); + + _rootResolutions.Add((CreateCreateFunctionResolution( + typeSymbol, + ImmutableSortedDictionary.Empty, + Constants.PrivateKeyword), methodNamePrefix)); + } } public MultiSynchronicityFunctionCallResolution CreateContainerInstanceReferenceResolution(ForConstructorParameter parameter, string containerReference) => diff --git a/Main/ResolutionBuilding/Function/FunctionCycleTracker.cs b/Main/ResolutionBuilding/Function/FunctionCycleTracker.cs index 130ae606..7cbc8deb 100644 --- a/Main/ResolutionBuilding/Function/FunctionCycleTracker.cs +++ b/Main/ResolutionBuilding/Function/FunctionCycleTracker.cs @@ -2,6 +2,8 @@ namespace MrMeeseeks.DIE.ResolutionBuilding.Function; internal interface IFunctionCycleTracker { + void RegisterRootHandle(FunctionResolutionBuilderHandle root); + void TrackFunctionCall(FunctionResolutionBuilderHandle from, FunctionResolutionBuilderHandle to); void DetectCycle(); @@ -10,6 +12,9 @@ internal interface IFunctionCycleTracker internal class FunctionCycleTracker : IFunctionCycleTracker { private readonly Dictionary> _adjacencyMap = new (); + private readonly List _roots = new(); + + public void RegisterRootHandle(FunctionResolutionBuilderHandle root) => _roots.Add(root); public void TrackFunctionCall(FunctionResolutionBuilderHandle from, FunctionResolutionBuilderHandle to) { @@ -21,7 +26,7 @@ public void TrackFunctionCall(FunctionResolutionBuilderHandle from, FunctionReso public void DetectCycle() { - foreach (var function in _adjacencyMap.Keys) + foreach (var function in _roots) DetectCycleInner(function, new HashSet()); void DetectCycleInner(FunctionResolutionBuilderHandle current, HashSet visited) diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs index b12a63a0..c54730c5 100644 --- a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs @@ -45,6 +45,7 @@ public void Register(IAwaitableResolution awaitableResolution) internal interface IFunctionResolutionBuilder : IResolutionBuilder { + FunctionResolutionBuilderHandle Handle { get; } ITypeSymbol OriginalReturnType { get; } ITypeSymbol? ActualReturnType { get; } IReadOnlyList Parameters { get; } @@ -69,7 +70,7 @@ internal abstract partial class FunctionResolutionBuilder : IFunctionResolutionB private readonly IUserDefinedElements _userDefinedElements; - private readonly FunctionResolutionBuilderHandle _handle; + public FunctionResolutionBuilderHandle Handle { get; } protected abstract string Name { get; } protected string TypeFullName => ActualReturnType?.FullName() ?? OriginalReturnType.FullName(); @@ -104,7 +105,7 @@ internal FunctionResolutionBuilder( _functionCycleTracker = functionCycleTracker; _checkTypeProperties = rangeResolutionBaseBuilder.CheckTypeProperties; _userDefinedElements = rangeResolutionBaseBuilder.UserDefinedElements; - _handle = new FunctionResolutionBuilderHandle( + Handle = new FunctionResolutionBuilderHandle( handleIdentity, $"{OriginalReturnType.FullName()}({string.Join(", ", currentParameters.Select(p => p.Value.Item2.TypeFullName))})"); @@ -798,7 +799,7 @@ INamedTypeSymbol UnwrapAsynchronicity(INamedTypeSymbol currentWrappedType, Stack }; if (ret.Item1 is MultiSynchronicityFunctionCallResolution multi) - _functionCycleTracker.TrackFunctionCall(_handle, multi.FunctionResolutionBuilderHandle); + _functionCycleTracker.TrackFunctionCall(Handle, multi.FunctionResolutionBuilderHandle); if (ret.Item1 is ScopeRootResolution { ScopeRootFunction: IAwaitableResolution awaitableResolution }) _synchronicityDecisionMaker.Register(awaitableResolution); @@ -858,7 +859,7 @@ INamedTypeSymbol UnwrapAsynchronicity(INamedTypeSymbol currentWrappedType, Stack _scopedInstancesReferenceCache[implementationType] = new ProxyResolvable(ret.Item1.Reference, ret.Item1.TypeFullName); if (ret.Item1 is MultiSynchronicityFunctionCallResolution multi) - _functionCycleTracker.TrackFunctionCall(_handle, multi.FunctionResolutionBuilderHandle); + _functionCycleTracker.TrackFunctionCall(Handle, multi.FunctionResolutionBuilderHandle); if (ret.Item1 is IAwaitableResolution awaitableResolution) _synchronicityDecisionMaker.Register(awaitableResolution); @@ -1212,7 +1213,7 @@ public MultiSynchronicityFunctionCallResolution BuildFunctionCall( ownerReference, CreateParameter()), SynchronicityDecision, - _handle); + Handle); IReadOnlyList<(string Name, string Reference)> CreateParameter() => Parameters.Join( From 3bdc25e4b25fa0609176042a0ae11ade6ba57a77 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sun, 18 Sep 2022 17:27:07 +0200 Subject: [PATCH 145/162] Removed debugging code --- Main/ExecuteImpl.cs | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/Main/ExecuteImpl.cs b/Main/ExecuteImpl.cs index 6f1cc2ee..a79b3e78 100644 --- a/Main/ExecuteImpl.cs +++ b/Main/ExecuteImpl.cs @@ -63,37 +63,23 @@ public void Execute() { try { - DateTime start = DateTime.Now; - _context.ReportDiagnostic(Diagnostics.Logging($"Start {start}")); var containerInfo = _containerInfoFactory(containerSymbol); var validationDiagnostics = _validateContainer.Validate(containerInfo.ContainerType, containerInfo.ContainerType) .ToImmutableArray(); if (!validationDiagnostics.Any()) { - _context.ReportDiagnostic(Diagnostics.Logging($"Validation {DateTime.Now - start}")); - start = DateTime.Now; var containerResolutionBuilder = _containerResolutionBuilderFactory(containerInfo); - _context.ReportDiagnostic(Diagnostics.Logging($"Building Container Builder {DateTime.Now - start}")); - start = DateTime.Now; containerResolutionBuilder.AddCreateResolveFunctions(containerInfo.CreateFunctionData); - _context.ReportDiagnostic(Diagnostics.Logging($"Create Resolve Functions {DateTime.Now - start}")); - start = DateTime.Now; while (containerResolutionBuilder.HasWorkToDo) { containerResolutionBuilder.DoWork(); } - _context.ReportDiagnostic(Diagnostics.Logging($"Do work {DateTime.Now - start}")); - start = DateTime.Now; containerResolutionBuilder.FunctionCycleTracker.DetectCycle(); - _context.ReportDiagnostic(Diagnostics.Logging($"Detect cycles {DateTime.Now - start}")); - start = DateTime.Now; var containerResolution = containerResolutionBuilder.Build(); _containerGenerator.Generate(containerInfo, containerResolution); - _context.ReportDiagnostic(Diagnostics.Logging($"Generate Code {DateTime.Now - start}")); - start = DateTime.Now; } else { From 9bfb47cda182f14ac655702719e7f83acf76ac5c Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Tue, 20 Sep 2022 12:03:13 +0200 Subject: [PATCH 146/162] Fix recent optimization --- GettingStarted/GettingStarted.csproj | 2 +- Main/ResolutionBuilding/ContainerResolutionBuilder.cs | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/GettingStarted/GettingStarted.csproj b/GettingStarted/GettingStarted.csproj index b912f3b0..2e0e970e 100644 --- a/GettingStarted/GettingStarted.csproj +++ b/GettingStarted/GettingStarted.csproj @@ -10,7 +10,7 @@ - + diff --git a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs index 7dc44a58..0263d77c 100644 --- a/Main/ResolutionBuilding/ContainerResolutionBuilder.cs +++ b/Main/ResolutionBuilding/ContainerResolutionBuilder.cs @@ -79,11 +79,9 @@ public void AddCreateResolveFunctions(IReadOnlyList<(ITypeSymbol, string)> creat ImmutableSortedDictionary.Empty, Constants.PrivateKeyword); - _rootResolutions.Add((CreateCreateFunctionResolution( - typeSymbol, - ImmutableSortedDictionary.Empty, - Constants.PrivateKeyword), - methodNamePrefix)); + FunctionCycleTracker.RegisterRootHandle(functionResolution.Handle); + + _rootResolutions.Add((functionResolution, methodNamePrefix)); } } From 97afc61891f9e21326ef00b3f1fe2420b88d3706 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Tue, 20 Sep 2022 12:51:52 +0200 Subject: [PATCH 147/162] Printing function cycle --- GettingStarted/GettingStarted.csproj | 2 +- Main/DiagLogger.cs | 4 +-- Main/Diagnostics.cs | 16 ++++++---- Main/DieException.cs | 5 ++++ .../Function/FunctionCycleTracker.cs | 19 +++++++++--- .../Function/FunctionResolutionBuilder.cs | 2 +- ...ransientScopeInterfaceResolutionBuilder.cs | 3 +- Sample/Container.cs | 24 +++++++++------ .../Cycle/IndirectRecursionContainer.cs | 30 +++++++++++++++++++ .../Function/Cycle/IndirectRecursionScope.cs | 30 +++++++++++++++++++ .../Cycle/IndirectRecursionTransientScope.cs | 30 +++++++++++++++++++ 11 files changed, 141 insertions(+), 24 deletions(-) create mode 100644 Test/CycleDetection/Function/Cycle/IndirectRecursionContainer.cs create mode 100644 Test/CycleDetection/Function/Cycle/IndirectRecursionScope.cs create mode 100644 Test/CycleDetection/Function/Cycle/IndirectRecursionTransientScope.cs diff --git a/GettingStarted/GettingStarted.csproj b/GettingStarted/GettingStarted.csproj index 2e0e970e..9b0a6cd1 100644 --- a/GettingStarted/GettingStarted.csproj +++ b/GettingStarted/GettingStarted.csproj @@ -10,7 +10,7 @@ - + diff --git a/Main/DiagLogger.cs b/Main/DiagLogger.cs index 66e393fe..500513d5 100644 --- a/Main/DiagLogger.cs +++ b/Main/DiagLogger.cs @@ -27,8 +27,8 @@ public void Error(DieException exception) case ImplementationCycleDieException implementationCycle: Log(Diagnostics.CircularReferenceInsideFactory(implementationCycle)); break; - case FunctionCycleDieException: - Log(Diagnostics.CircularReferenceAmongFactories); + case FunctionCycleDieException functionCycleDieException: + Log(Diagnostics.CircularReferenceAmongFactories(functionCycleDieException)); break; case ValidationDieException validationDieException: foreach (var error in validationDieException.Diagnostics) diff --git a/Main/Diagnostics.cs b/Main/Diagnostics.cs index 1989c9e2..e315474c 100644 --- a/Main/Diagnostics.cs +++ b/Main/Diagnostics.cs @@ -18,15 +18,19 @@ public static Diagnostic CircularReferenceInsideFactory(ImplementationCycleDieEx } - public static Diagnostic CircularReferenceAmongFactories => - Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_68_01", + public static Diagnostic CircularReferenceAmongFactories(FunctionCycleDieException exception) + { + var cycleText = string.Join(" --> ", exception.Cycle.Select(f => f.Description)); + + return Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_68_01", "Circular Reference Exception (among factories)", - "This container and/or its configuration lead to a circular reference among factory functions, which need to be generated.", - "Error", - DiagnosticSeverity.Error, + $"This container and/or its configuration lead to a circular reference among factory functions, which need to be generated. The involved factory functions are: {cycleText}", + "Error", + DiagnosticSeverity.Error, true), Location.None); - + } + public static Diagnostic ValidationContainer(INamedTypeSymbol container, string specification) => Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_67_00", "Validation (Container)", diff --git a/Main/DieException.cs b/Main/DieException.cs index 4ed3281b..a5db28ae 100644 --- a/Main/DieException.cs +++ b/Main/DieException.cs @@ -1,3 +1,5 @@ +using MrMeeseeks.DIE.ResolutionBuilding.Function; + namespace MrMeeseeks.DIE; public enum DieExceptionKind @@ -24,7 +26,10 @@ public class ImplementationCycleDieException : DieException public class FunctionCycleDieException : DieException { + public FunctionCycleDieException(IImmutableStack cycle) => Cycle = cycle; + public override DieExceptionKind Kind => DieExceptionKind.FunctionCycle; + public IImmutableStack Cycle { get; } } public class ValidationDieException : DieException diff --git a/Main/ResolutionBuilding/Function/FunctionCycleTracker.cs b/Main/ResolutionBuilding/Function/FunctionCycleTracker.cs index 7cbc8deb..4905621f 100644 --- a/Main/ResolutionBuilding/Function/FunctionCycleTracker.cs +++ b/Main/ResolutionBuilding/Function/FunctionCycleTracker.cs @@ -27,17 +27,28 @@ public void TrackFunctionCall(FunctionResolutionBuilderHandle from, FunctionReso public void DetectCycle() { foreach (var function in _roots) - DetectCycleInner(function, new HashSet()); + DetectCycleInner(function, new HashSet(), new Stack()); - void DetectCycleInner(FunctionResolutionBuilderHandle current, HashSet visited) + void DetectCycleInner(FunctionResolutionBuilderHandle current, HashSet visited, Stack stack) { if (visited.Contains(current.Identity)) - throw new FunctionCycleDieException(); + { + var cycleStack = ImmutableStack.Create(current); + var i = current; + do + { + i = stack.Pop(); + cycleStack = cycleStack.Push(i); + } while (i.Identity != current.Identity && stack.Any()); + throw new FunctionCycleDieException(cycleStack); + } if (_adjacencyMap.TryGetValue(current, out var neighbors)) { visited.Add(current.Identity); + stack.Push(current); foreach (var neighbor in neighbors) - DetectCycleInner(neighbor, visited); + DetectCycleInner(neighbor, visited, stack); + stack.Pop(); visited.Remove(current.Identity); } } diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs index c54730c5..3b532663 100644 --- a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs @@ -107,7 +107,7 @@ internal FunctionResolutionBuilder( _userDefinedElements = rangeResolutionBaseBuilder.UserDefinedElements; Handle = new FunctionResolutionBuilderHandle( handleIdentity, - $"{OriginalReturnType.FullName()}({string.Join(", ", currentParameters.Select(p => p.Value.Item2.TypeFullName))})"); + $"(implementation) {OriginalReturnType.FullName()}({string.Join(", ", currentParameters.Select(p => p.Value.Item2.TypeFullName))})"); RootReferenceGenerator = referenceGeneratorFactory.Create(); CurrentParameters = currentParameters diff --git a/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs b/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs index 43f64c30..e574e006 100644 --- a/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs +++ b/Main/ResolutionBuilding/TransientScopeInterfaceResolutionBuilder.cs @@ -100,7 +100,8 @@ private MultiSynchronicityFunctionCallResolution CreateRangedInstanceReferenceRe var decorationSuffix = interfaceExtension?.RangedNameSuffix() ?? ""; tuple = ( _rootReferenceGenerator.Generate($"Get{label}Instance", implementationType, decorationSuffix), - new FunctionResolutionBuilderHandle(new object(), "asdf")); + new FunctionResolutionBuilderHandle(new object(), + $"(interface) {implementationType.FullName()}({string.Join(", ", currentParameters.Select(p => p.Value.Item2.TypeFullName))})")); _rangedInstanceReferences[referenceKey] = tuple; } diff --git a/Sample/Container.cs b/Sample/Container.cs index 3e8d5176..de47eaa0 100644 --- a/Sample/Container.cs +++ b/Sample/Container.cs @@ -1,14 +1,20 @@ using MrMeeseeks.DIE.Configuration.Attributes; +using MrMeeseeks.DIE.Sample; -namespace MrMeeseeks.DIE.Test.Bugs.UngenericImplementationGenericInterface; +namespace MrMeeseeks.DIE.Test.CycleDetection.Function.Cycle.IndirectRecursionContainer; -internal interface IInterface {} +internal class Dependency : IContainerInstance +{ + internal Dependency(InnerDependency inner) {} +} -internal class DependencyA : IInterface {} +internal class InnerDependency : IContainerInstance +{ + internal InnerDependency(Dependency inner) {} +} -internal class DependencyB : IInterface {} - -internal class DependencyC : IInterface {} - -[CreateFunction(typeof(IInterface), "Create")] -internal sealed partial class Container {} \ No newline at end of file +[CreateFunction(typeof(Dependency), "Create")] +internal sealed partial class Container +{ + +} \ No newline at end of file diff --git a/Test/CycleDetection/Function/Cycle/IndirectRecursionContainer.cs b/Test/CycleDetection/Function/Cycle/IndirectRecursionContainer.cs new file mode 100644 index 00000000..28f3c766 --- /dev/null +++ b/Test/CycleDetection/Function/Cycle/IndirectRecursionContainer.cs @@ -0,0 +1,30 @@ +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CycleDetection.Function.Cycle.IndirectRecursionContainer; + +internal class Dependency : IContainerInstance +{ + internal Dependency(InnerDependency inner) {} +} + +internal class InnerDependency : IContainerInstance +{ + internal InnerDependency(Dependency inner) {} +} + +[CreateFunction(typeof(Dependency), "Create")] +internal sealed partial class Container +{ + +} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + Assert.Equal(DieExceptionKind.FunctionCycle , container.ExceptionKind_0_0); + } +} \ No newline at end of file diff --git a/Test/CycleDetection/Function/Cycle/IndirectRecursionScope.cs b/Test/CycleDetection/Function/Cycle/IndirectRecursionScope.cs new file mode 100644 index 00000000..ed8b39a1 --- /dev/null +++ b/Test/CycleDetection/Function/Cycle/IndirectRecursionScope.cs @@ -0,0 +1,30 @@ +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CycleDetection.Function.Cycle.IndirectRecursionScope; + +/* todo internal class Dependency : IScopeRoot +{ + internal Dependency(InnerDependency inner) {} +} + +internal class InnerDependency : IScopeInstance +{ + internal InnerDependency(Dependency inner) {} +} + +[CreateFunction(typeof(Dependency), "Create")] +internal sealed partial class Container +{ + +} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + Assert.Equal(DieExceptionKind.FunctionCycle , container.ExceptionKind_0_0); + } +}*/ \ No newline at end of file diff --git a/Test/CycleDetection/Function/Cycle/IndirectRecursionTransientScope.cs b/Test/CycleDetection/Function/Cycle/IndirectRecursionTransientScope.cs new file mode 100644 index 00000000..995eda39 --- /dev/null +++ b/Test/CycleDetection/Function/Cycle/IndirectRecursionTransientScope.cs @@ -0,0 +1,30 @@ +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.CycleDetection.Function.Cycle.IndirectRecursionTransientScope; + +/* todo internal class Dependency : ITransientScopeRoot +{ + internal Dependency(InnerDependency inner) {} +} + +internal class InnerDependency : ITransientScopeInstance +{ + internal InnerDependency(Dependency inner) {} +} + +[CreateFunction(typeof(Dependency), "Create")] +internal sealed partial class Container +{ + +} + +public class Tests +{ + [Fact] + public void Test() + { + var container = new Container(); + Assert.Equal(DieExceptionKind.FunctionCycle , container.ExceptionKind_0_0); + } +}*/ \ No newline at end of file From 47c0558c63ce28f4043e0dc3216244eb7b71ac1a Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Thu, 22 Sep 2022 16:06:48 +0200 Subject: [PATCH 148/162] Fixed function cycle detection with scopes and generated factories --- .../Function/FunctionCycleTracker.cs | 19 +++++++++++++++---- .../Function/FunctionResolutionBuilder.cs | 11 +++++++++-- Sample/Container.cs | 6 +++--- .../Function/Cycle/IndirectRecursionScope.cs | 4 ++-- .../Cycle/IndirectRecursionTransientScope.cs | 4 ++-- 5 files changed, 31 insertions(+), 13 deletions(-) diff --git a/Main/ResolutionBuilding/Function/FunctionCycleTracker.cs b/Main/ResolutionBuilding/Function/FunctionCycleTracker.cs index 4905621f..d5e86d01 100644 --- a/Main/ResolutionBuilding/Function/FunctionCycleTracker.cs +++ b/Main/ResolutionBuilding/Function/FunctionCycleTracker.cs @@ -27,14 +27,24 @@ public void TrackFunctionCall(FunctionResolutionBuilderHandle from, FunctionReso public void DetectCycle() { foreach (var function in _roots) - DetectCycleInner(function, new HashSet(), new Stack()); + DetectCycleInner( + function, + new HashSet(), + new Stack(), + new HashSet()); - void DetectCycleInner(FunctionResolutionBuilderHandle current, HashSet visited, Stack stack) + void DetectCycleInner( + FunctionResolutionBuilderHandle current, + HashSet visited, + Stack stack, + HashSet cycleFree) { + if (cycleFree.Contains(current.Identity)) + return; // one of the previous roots checked this node already if (visited.Contains(current.Identity)) { var cycleStack = ImmutableStack.Create(current); - var i = current; + FunctionResolutionBuilderHandle i; do { i = stack.Pop(); @@ -47,7 +57,8 @@ void DetectCycleInner(FunctionResolutionBuilderHandle current, HashSet v visited.Add(current.Identity); stack.Push(current); foreach (var neighbor in neighbors) - DetectCycleInner(neighbor, visited, stack); + DetectCycleInner(neighbor, visited, stack, cycleFree); + cycleFree.Add(current.Identity); stack.Pop(); visited.Remove(current.Identity); } diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs index 3b532663..ea0a085b 100644 --- a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs @@ -510,6 +510,7 @@ IFactoryResolution CreateFactoryResolution( var functionCall = newCreateFunction.BuildFunctionCall( currentParameters, Constants.ThisKeyword); + _functionCycleTracker.RegisterRootHandle(functionCall.FunctionResolutionBuilderHandle); var currentResolution = (IFactoryResolution)functionCall; var currentType = mostInnerType; @@ -801,11 +802,17 @@ INamedTypeSymbol UnwrapAsynchronicity(INamedTypeSymbol currentWrappedType, Stack if (ret.Item1 is MultiSynchronicityFunctionCallResolution multi) _functionCycleTracker.TrackFunctionCall(Handle, multi.FunctionResolutionBuilderHandle); - if (ret.Item1 is ScopeRootResolution { ScopeRootFunction: IAwaitableResolution awaitableResolution }) + if (ret.Item1 is ScopeRootResolution { ScopeRootFunction: { } awaitableResolution }) + { + _functionCycleTracker.TrackFunctionCall(Handle, awaitableResolution.FunctionResolutionBuilderHandle); _synchronicityDecisionMaker.Register(awaitableResolution); + } - if (ret.Item1 is TransientScopeRootResolution { ScopeRootFunction: IAwaitableResolution awaitableResolution0 }) + if (ret.Item1 is TransientScopeRootResolution { ScopeRootFunction: { } awaitableResolution0 }) + { + _functionCycleTracker.TrackFunctionCall(Handle, awaitableResolution0.FunctionResolutionBuilderHandle); _synchronicityDecisionMaker.Register(awaitableResolution0); + } if (ret.Item1 is ScopeRootResolution { ScopeRootFunction: ITaskConsumableResolution taskConsumableResolution }) ret.Item2 = taskConsumableResolution; diff --git a/Sample/Container.cs b/Sample/Container.cs index de47eaa0..e3d46e46 100644 --- a/Sample/Container.cs +++ b/Sample/Container.cs @@ -1,14 +1,14 @@ using MrMeeseeks.DIE.Configuration.Attributes; using MrMeeseeks.DIE.Sample; -namespace MrMeeseeks.DIE.Test.CycleDetection.Function.Cycle.IndirectRecursionContainer; +namespace Asdf; -internal class Dependency : IContainerInstance +internal class Dependency : IScopeRoot { internal Dependency(InnerDependency inner) {} } -internal class InnerDependency : IContainerInstance +internal class InnerDependency : IScopeInstance { internal InnerDependency(Dependency inner) {} } diff --git a/Test/CycleDetection/Function/Cycle/IndirectRecursionScope.cs b/Test/CycleDetection/Function/Cycle/IndirectRecursionScope.cs index ed8b39a1..a395629e 100644 --- a/Test/CycleDetection/Function/Cycle/IndirectRecursionScope.cs +++ b/Test/CycleDetection/Function/Cycle/IndirectRecursionScope.cs @@ -3,7 +3,7 @@ namespace MrMeeseeks.DIE.Test.CycleDetection.Function.Cycle.IndirectRecursionScope; -/* todo internal class Dependency : IScopeRoot +internal class Dependency : IScopeRoot { internal Dependency(InnerDependency inner) {} } @@ -27,4 +27,4 @@ public void Test() var container = new Container(); Assert.Equal(DieExceptionKind.FunctionCycle , container.ExceptionKind_0_0); } -}*/ \ No newline at end of file +} \ No newline at end of file diff --git a/Test/CycleDetection/Function/Cycle/IndirectRecursionTransientScope.cs b/Test/CycleDetection/Function/Cycle/IndirectRecursionTransientScope.cs index 995eda39..86f13176 100644 --- a/Test/CycleDetection/Function/Cycle/IndirectRecursionTransientScope.cs +++ b/Test/CycleDetection/Function/Cycle/IndirectRecursionTransientScope.cs @@ -3,7 +3,7 @@ namespace MrMeeseeks.DIE.Test.CycleDetection.Function.Cycle.IndirectRecursionTransientScope; -/* todo internal class Dependency : ITransientScopeRoot +internal class Dependency : ITransientScopeRoot { internal Dependency(InnerDependency inner) {} } @@ -27,4 +27,4 @@ public void Test() var container = new Container(); Assert.Equal(DieExceptionKind.FunctionCycle , container.ExceptionKind_0_0); } -}*/ \ No newline at end of file +} \ No newline at end of file From d7b9f3d8f608fc2e66d01f9aa53b9507ac9996ba Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Fri, 23 Sep 2022 20:35:56 +0200 Subject: [PATCH 149/162] Collection Tests --- Test/Collection/Array.cs | 27 ++++++++++++++++++++++++ Test/Collection/IEnumerable.cs | 29 ++++++++++++++++++++++++++ Test/Collection/IReadOnlyCollection.cs | 28 +++++++++++++++++++++++++ Test/Collection/IReadOnlyList.cs | 28 +++++++++++++++++++++++++ 4 files changed, 112 insertions(+) create mode 100644 Test/Collection/Array.cs create mode 100644 Test/Collection/IEnumerable.cs create mode 100644 Test/Collection/IReadOnlyCollection.cs create mode 100644 Test/Collection/IReadOnlyList.cs diff --git a/Test/Collection/Array.cs b/Test/Collection/Array.cs new file mode 100644 index 00000000..df40628d --- /dev/null +++ b/Test/Collection/Array.cs @@ -0,0 +1,27 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Collection.Array; + +internal interface IInterface {} + +internal class ClassA : IInterface {} + +internal class ClassB : IInterface {} + +internal class ClassC : IInterface {} + +[CreateFunction(typeof(IInterface[]), "Create")] +internal sealed partial class Container {} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var collection = container.Create(); + Assert.Equal(3, collection.Length); + } +} \ No newline at end of file diff --git a/Test/Collection/IEnumerable.cs b/Test/Collection/IEnumerable.cs new file mode 100644 index 00000000..7a92c1e6 --- /dev/null +++ b/Test/Collection/IEnumerable.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Collection.IEnumerable; + +internal interface IInterface {} + +internal class ClassA : IInterface {} + +internal class ClassB : IInterface {} + +internal class ClassC : IInterface {} + +[CreateFunction(typeof(IEnumerable), "Create")] +internal sealed partial class Container {} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var collection = container.Create(); + Assert.Equal(3, collection.Count()); + } +} \ No newline at end of file diff --git a/Test/Collection/IReadOnlyCollection.cs b/Test/Collection/IReadOnlyCollection.cs new file mode 100644 index 00000000..ace45e3b --- /dev/null +++ b/Test/Collection/IReadOnlyCollection.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Collection.IReadOnlyCollection; + +internal interface IInterface {} + +internal class ClassA : IInterface {} + +internal class ClassB : IInterface {} + +internal class ClassC : IInterface {} + +[CreateFunction(typeof(IReadOnlyCollection), "Create")] +internal sealed partial class Container {} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var collection = container.Create(); + Assert.Equal(3, collection.Count); + } +} \ No newline at end of file diff --git a/Test/Collection/IReadOnlyList.cs b/Test/Collection/IReadOnlyList.cs new file mode 100644 index 00000000..96e42af5 --- /dev/null +++ b/Test/Collection/IReadOnlyList.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Collection.IReadOnlyList; + +internal interface IInterface {} + +internal class ClassA : IInterface {} + +internal class ClassB : IInterface {} + +internal class ClassC : IInterface {} + +[CreateFunction(typeof(IReadOnlyList), "Create")] +internal sealed partial class Container {} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var collection = container.Create(); + Assert.Equal(3, collection.Count); + } +} \ No newline at end of file From 71adb7de92324215dad50158cd227ad900c342b5 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sat, 24 Sep 2022 11:20:58 +0200 Subject: [PATCH 150/162] Support arrays in composite parameter --- Main/CodeBuilding/RangeCodeBaseBuilder.cs | 2 +- .../Function/FunctionResolutionBuilder.cs | 37 ++++++++++--------- Main/ResolutionTreeItem.cs | 2 +- Test/Collection/Composite/Array.cs | 31 ++++++++++++++++ Test/Collection/Composite/IEnumerable.cs | 32 ++++++++++++++++ .../Composite/IReadOnlyCollection.cs | 32 ++++++++++++++++ Test/Collection/Composite/IReadOnlyList.cs | 32 ++++++++++++++++ Test/Collection/{ => Injection}/Array.cs | 2 +- .../Collection/{ => Injection}/IEnumerable.cs | 6 +-- .../{ => Injection}/IReadOnlyCollection.cs | 2 +- .../{ => Injection}/IReadOnlyList.cs | 2 +- 11 files changed, 154 insertions(+), 26 deletions(-) create mode 100644 Test/Collection/Composite/Array.cs create mode 100644 Test/Collection/Composite/IEnumerable.cs create mode 100644 Test/Collection/Composite/IReadOnlyCollection.cs create mode 100644 Test/Collection/Composite/IReadOnlyList.cs rename Test/Collection/{ => Injection}/Array.cs (90%) rename Test/Collection/{ => Injection}/IEnumerable.cs (75%) rename Test/Collection/{ => Injection}/IReadOnlyCollection.cs (89%) rename Test/Collection/{ => Injection}/IReadOnlyList.cs (90%) diff --git a/Main/CodeBuilding/RangeCodeBaseBuilder.cs b/Main/CodeBuilding/RangeCodeBaseBuilder.cs index 18fc16a0..e8c937db 100644 --- a/Main/CodeBuilding/RangeCodeBaseBuilder.cs +++ b/Main/CodeBuilding/RangeCodeBaseBuilder.cs @@ -457,7 +457,7 @@ private StringBuilder GenerateResolutions( (builder, tuple) => GenerateResolutions(builder, tuple.Dependency ?? throw new Exception())); stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference} = {(isAwait ? "await " : "")}this.{functionName}({string.Join(", ", parameters.Select(t => $"{t.Name}: {t.Dependency.Reference}"))});"); break; - case CollectionResolution(var reference, var typeFullName, var itemFullName, var items): + case ArrayResolution(var reference, var typeFullName, var itemFullName, var items): stringBuilder = items.OfType().Aggregate(stringBuilder, GenerateResolutions); stringBuilder = stringBuilder.AppendLine( $"{typeFullName} {reference} = new {itemFullName}[]{{{string.Join(", ", items.Select(d => $"({itemFullName}) {(d as Resolvable)?.Reference}"))}}};"); diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs index ea0a085b..8f4c65ae 100644 --- a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs @@ -388,10 +388,7 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup null); } - if (type.OriginalDefinition.Equals(_wellKnownTypes.Enumerable1, SymbolEqualityComparer.Default) - || type.OriginalDefinition.Equals(_wellKnownTypes.ReadOnlyCollection1, SymbolEqualityComparer.Default) - || type.OriginalDefinition.Equals(_wellKnownTypes.ReadOnlyList1, SymbolEqualityComparer.Default) - || type is IArrayTypeSymbol) + if (IsCollectionType(type)) { if (type is not INamedTypeSymbol && type is not IArrayTypeSymbol) { @@ -473,7 +470,7 @@ when collectionType.TypeArguments.SingleOrDefault() is INamedTypeSymbol innerTyp .ToList(); return ( - new CollectionResolution( + new ArrayResolution( RootReferenceGenerator.Generate(type), type.FullName(), wrappedItemType.FullName(), @@ -1070,19 +1067,15 @@ false when initializationMethod.ReturnType.Equals(_wellKnownTypes.ValueTask, Sym if (checkForComposition && composition is {}) { - if (typeSymbol.Equals(_wellKnownTypes.Enumerable1.Construct(composition.InterfaceType), SymbolEqualityComparer.Default) - || typeSymbol.Equals(_wellKnownTypes.ReadOnlyCollection1.Construct(composition.InterfaceType), SymbolEqualityComparer.Default) - || typeSymbol.Equals(_wellKnownTypes.ReadOnlyList1.Construct(composition.InterfaceType), SymbolEqualityComparer.Default)) - return (parameterName, new CollectionResolution( + if (IsConstructedCollectionType(typeSymbol, composition.InterfaceType)) + return (parameterName, new ArrayResolution( RootReferenceGenerator.Generate(typeSymbol), typeSymbol.FullName(), composition.InterfaceType.FullName(), composition.InterfaceResolutionComposition)); - if (typeSymbol.Equals(_wellKnownTypes.Enumerable1.Construct(_wellKnownTypes.Task1.Construct(composition.InterfaceType)), SymbolEqualityComparer.Default) - || typeSymbol.Equals(_wellKnownTypes.ReadOnlyCollection1.Construct(_wellKnownTypes.Task1.Construct(composition.InterfaceType)), SymbolEqualityComparer.Default) - || typeSymbol.Equals(_wellKnownTypes.ReadOnlyList1.Construct(_wellKnownTypes.Task1.Construct(composition.InterfaceType)), SymbolEqualityComparer.Default)) - return (parameterName, new CollectionResolution( + if (IsConstructedCollectionType(typeSymbol, _wellKnownTypes.Task1.Construct(composition.InterfaceType))) + return (parameterName, new ArrayResolution( RootReferenceGenerator.Generate(typeSymbol), typeSymbol.FullName(), _wellKnownTypes.Task1.Construct(composition.InterfaceType).FullName(), @@ -1096,10 +1089,8 @@ false when initializationMethod.ReturnType.Equals(_wellKnownTypes.ValueTask, Sym .OfType() .ToList())); - if (typeSymbol.Equals(_wellKnownTypes.Enumerable1.Construct(_wellKnownTypes.ValueTask1.Construct(composition.InterfaceType)), SymbolEqualityComparer.Default) - || typeSymbol.Equals(_wellKnownTypes.ReadOnlyCollection1.Construct(_wellKnownTypes.ValueTask1.Construct(composition.InterfaceType)), SymbolEqualityComparer.Default) - || typeSymbol.Equals(_wellKnownTypes.ReadOnlyList1.Construct(_wellKnownTypes.ValueTask1.Construct(composition.InterfaceType)), SymbolEqualityComparer.Default)) - return (parameterName, new CollectionResolution( + if (IsConstructedCollectionType(typeSymbol, _wellKnownTypes.ValueTask1.Construct(composition.InterfaceType))) + return (parameterName, new ArrayResolution( RootReferenceGenerator.Generate(typeSymbol), typeSymbol.FullName(), _wellKnownTypes.ValueTask1.Construct(composition.InterfaceType).FullName(), @@ -1230,6 +1221,18 @@ public MultiSynchronicityFunctionCallResolution BuildFunctionCall( (p, cp) => (p.Reference, cp.Value.Item2.Reference)).ToList(); } + private bool IsCollectionType(ITypeSymbol type) => + type.OriginalDefinition.Equals(_wellKnownTypes.Enumerable1, SymbolEqualityComparer.Default) + || type.OriginalDefinition.Equals(_wellKnownTypes.ReadOnlyCollection1, SymbolEqualityComparer.Default) + || type.OriginalDefinition.Equals(_wellKnownTypes.ReadOnlyList1, SymbolEqualityComparer.Default) + || type is IArrayTypeSymbol; + + private bool IsConstructedCollectionType(ITypeSymbol type, INamedTypeSymbol interfaceType) => + type.Equals(_wellKnownTypes.Enumerable1.Construct(interfaceType), SymbolEqualityComparer.Default) + || type.Equals(_wellKnownTypes.ReadOnlyCollection1.Construct(interfaceType), SymbolEqualityComparer.Default) + || type.Equals(_wellKnownTypes.ReadOnlyList1.Construct(interfaceType), SymbolEqualityComparer.Default) + || type is IArrayTypeSymbol { ElementType: {} elementType } && elementType.Equals(interfaceType, SymbolEqualityComparer.Default); + public bool HasWorkToDo => !Resolvable.IsValueCreated; protected abstract Resolvable CreateResolvable(); diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index 893f5fe6..ee7270fd 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -200,7 +200,7 @@ internal record UserDefinedInitializerParametersInjectionResolution( string FunctionName, IReadOnlyList<(string Name, Resolvable Dependency, bool isOut)> Parameter) : UserDefinedInjectionResolution(FunctionName, Parameter); -internal record CollectionResolution( +internal record ArrayResolution( string Reference, string TypeFullName, string ItemFullName, diff --git a/Test/Collection/Composite/Array.cs b/Test/Collection/Composite/Array.cs new file mode 100644 index 00000000..c8468f63 --- /dev/null +++ b/Test/Collection/Composite/Array.cs @@ -0,0 +1,31 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Collection.Composite.Array; + +internal interface IInterface {} + +internal class ClassA : IInterface {} + +internal class ClassB : IInterface {} + +internal class ClassC : IInterface {} + +internal class Composite : IInterface, IComposite +{ + internal Composite(IInterface[] _) {} +} + +[CreateFunction(typeof(IInterface), "Create")] +internal sealed partial class Container {} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var _ = container.Create(); + } +} \ No newline at end of file diff --git a/Test/Collection/Composite/IEnumerable.cs b/Test/Collection/Composite/IEnumerable.cs new file mode 100644 index 00000000..935443f4 --- /dev/null +++ b/Test/Collection/Composite/IEnumerable.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Collection.Composite.IEnumerable; + +internal interface IInterface {} + +internal class ClassA : IInterface {} + +internal class ClassB : IInterface {} + +internal class ClassC : IInterface {} + +internal class Composite : IInterface, IComposite +{ + internal Composite(IEnumerable _) {} +} + +[CreateFunction(typeof(IInterface), "Create")] +internal sealed partial class Container {} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var _ = container.Create(); + } +} \ No newline at end of file diff --git a/Test/Collection/Composite/IReadOnlyCollection.cs b/Test/Collection/Composite/IReadOnlyCollection.cs new file mode 100644 index 00000000..aca083bf --- /dev/null +++ b/Test/Collection/Composite/IReadOnlyCollection.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Collection.Composite.IReadOnlyCollection; + +internal interface IInterface {} + +internal class ClassA : IInterface {} + +internal class ClassB : IInterface {} + +internal class ClassC : IInterface {} + +internal class Composite : IInterface, IComposite +{ + internal Composite(IReadOnlyCollection _) {} +} + +[CreateFunction(typeof(IInterface), "Create")] +internal sealed partial class Container {} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var _ = container.Create(); + } +} \ No newline at end of file diff --git a/Test/Collection/Composite/IReadOnlyList.cs b/Test/Collection/Composite/IReadOnlyList.cs new file mode 100644 index 00000000..9336e3e4 --- /dev/null +++ b/Test/Collection/Composite/IReadOnlyList.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Collection.Composite.IReadOnlyList; + +internal interface IInterface {} + +internal class ClassA : IInterface {} + +internal class ClassB : IInterface {} + +internal class ClassC : IInterface {} + +internal class Composite : IInterface, IComposite +{ + internal Composite(IReadOnlyList _) {} +} + +[CreateFunction(typeof(IInterface), "Create")] +internal sealed partial class Container {} + +public class Tests +{ + [Fact] + public async ValueTask Test() + { + await using var container = new Container(); + var _ = container.Create(); + } +} \ No newline at end of file diff --git a/Test/Collection/Array.cs b/Test/Collection/Injection/Array.cs similarity index 90% rename from Test/Collection/Array.cs rename to Test/Collection/Injection/Array.cs index df40628d..4c628374 100644 --- a/Test/Collection/Array.cs +++ b/Test/Collection/Injection/Array.cs @@ -2,7 +2,7 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.Collection.Array; +namespace MrMeeseeks.DIE.Test.Collection.Injection.Array; internal interface IInterface {} diff --git a/Test/Collection/IEnumerable.cs b/Test/Collection/Injection/IEnumerable.cs similarity index 75% rename from Test/Collection/IEnumerable.cs rename to Test/Collection/Injection/IEnumerable.cs index 7a92c1e6..eac53ed6 100644 --- a/Test/Collection/IEnumerable.cs +++ b/Test/Collection/Injection/IEnumerable.cs @@ -1,10 +1,9 @@ using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.Collection.IEnumerable; +namespace MrMeeseeks.DIE.Test.Collection.Injection.IEnumerable; internal interface IInterface {} @@ -23,7 +22,6 @@ public class Tests public async ValueTask Test() { await using var container = new Container(); - var collection = container.Create(); - Assert.Equal(3, collection.Count()); + var _ = container.Create(); } } \ No newline at end of file diff --git a/Test/Collection/IReadOnlyCollection.cs b/Test/Collection/Injection/IReadOnlyCollection.cs similarity index 89% rename from Test/Collection/IReadOnlyCollection.cs rename to Test/Collection/Injection/IReadOnlyCollection.cs index ace45e3b..8af9e70e 100644 --- a/Test/Collection/IReadOnlyCollection.cs +++ b/Test/Collection/Injection/IReadOnlyCollection.cs @@ -3,7 +3,7 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.Collection.IReadOnlyCollection; +namespace MrMeeseeks.DIE.Test.Collection.Injection.IReadOnlyCollection; internal interface IInterface {} diff --git a/Test/Collection/IReadOnlyList.cs b/Test/Collection/Injection/IReadOnlyList.cs similarity index 90% rename from Test/Collection/IReadOnlyList.cs rename to Test/Collection/Injection/IReadOnlyList.cs index 96e42af5..006e0238 100644 --- a/Test/Collection/IReadOnlyList.cs +++ b/Test/Collection/Injection/IReadOnlyList.cs @@ -3,7 +3,7 @@ using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; -namespace MrMeeseeks.DIE.Test.Collection.IReadOnlyList; +namespace MrMeeseeks.DIE.Test.Collection.Injection.IReadOnlyList; internal interface IInterface {} From 9acfeebbdb80f794c45902e98e7fc670ae6ead6e Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sat, 24 Sep 2022 13:13:52 +0200 Subject: [PATCH 151/162] Phase info for error handling --- Main/Configuration/TypesFromAttributes.cs | 54 ++++++++++----- Main/DiagLogger.cs | 10 +-- Main/Diagnostics.cs | 53 ++++++++------- Main/DieException.cs | 9 +++ Main/ExecuteImpl.cs | 12 ++-- .../Function/FunctionResolutionBuilder.cs | 65 +++++++++++++++---- Main/UserDefinedElements.cs | 6 +- .../ValidateUserDefinedFactoryField.cs | 2 +- .../UserDefined/ValidateUserDefinedMethod.cs | 2 +- Main/Validation/Range/ValidateContainer.cs | 4 +- Main/Validation/Range/ValidateScope.cs | 2 +- .../Range/ValidateTransientScope.cs | 2 +- 12 files changed, 150 insertions(+), 71 deletions(-) diff --git a/Main/Configuration/TypesFromAttributes.cs b/Main/Configuration/TypesFromAttributes.cs index 1ea1ae0a..147f5630 100644 --- a/Main/Configuration/TypesFromAttributes.cs +++ b/Main/Configuration/TypesFromAttributes.cs @@ -181,7 +181,8 @@ void NotParsableAttribute(AttributeData attributeData) => attributeData, _rangeType, _containerType, - "Not parsable attribute.")); + "Not parsable attribute.", + ExecutionPhase.Validation)); DecoratorSequenceChoices = ImmutableHashSet.CreateRange( (AttributeDictionary.TryGetValue(wellKnownTypesChoice.DecoratorSequenceChoiceAttribute, out var decoratorSequenceChoiceAttributes) @@ -209,7 +210,8 @@ void NotParsableAttribute(AttributeData attributeData) => ad, _rangeType, _containerType, - $"Decorated type \"{decoratedType.FullName()}\" has to implement decorator interface \"{interfaceType.FullName()}\".")); + $"Decorated type \"{decoratedType.FullName()}\" has to implement decorator interface \"{interfaceType.FullName()}\".", + ExecutionPhase.Validation)); return null; } @@ -234,7 +236,8 @@ void NotParsableAttribute(AttributeData attributeData) => ad, _rangeType, _containerType, - $"Decorator type \"{decoratorType.FullName()}\" has to implement decorator interface \"{interfaceType.FullName()}\".")); + $"Decorator type \"{decoratorType.FullName()}\" has to implement decorator interface \"{interfaceType.FullName()}\".", + ExecutionPhase.Validation)); return null; } @@ -273,7 +276,8 @@ void NotParsableAttribute(AttributeData attributeData) => ad, _rangeType, _containerType, - $"Decorated type \"{decoratedType.FullName()}\" has to implement decorator interface \"{interfaceType.FullName()}\".")); + $"Decorated type \"{decoratedType.FullName()}\" has to implement decorator interface \"{interfaceType.FullName()}\".", + ExecutionPhase.Validation)); return null; } @@ -322,7 +326,8 @@ void NotParsableAttribute(AttributeData attributeData) => ad, _rangeType, _containerType, - $"Couldn't find constructor \"{implementationType.FullName()}({string.Join(", ", parameterTypes.Select(p => p.FullName()))})\".")); + $"Couldn't find constructor \"{implementationType.FullName()}({string.Join(", ", parameterTypes.Select(p => p.FullName()))})\".", + ExecutionPhase.Validation)); return null; } @@ -387,7 +392,8 @@ void NotParsableAttribute(AttributeData attributeData) => ad, _rangeType, _containerType, - $"Couldn't find property \"{nonExistent}\" on \"{implementationType.FullName()}\".")); + $"Couldn't find property \"{nonExistent}\" on \"{implementationType.FullName()}\".", + ExecutionPhase.Validation)); var pickedProperties = propertyNames.Intersect(parameterTypes); @@ -440,7 +446,8 @@ void NotParsableAttribute(AttributeData attributeData) => ad, _rangeType, _containerType, - $"If method \"{methodName}\" on \"{type.FullName()}\" is to be used as initialize method, then it should return either nothing (void), \"{wellKnownTypes.ValueTask.FullName()}\", or \"{wellKnownTypes.Task.FullName()}\".")); + $"If method \"{methodName}\" on \"{type.FullName()}\" is to be used as initialize method, then it should return either nothing (void), \"{wellKnownTypes.ValueTask.FullName()}\", or \"{wellKnownTypes.Task.FullName()}\".", + ExecutionPhase.Validation)); return null; } @@ -451,7 +458,8 @@ void NotParsableAttribute(AttributeData attributeData) => ad, _rangeType, _containerType, - $"Couldn't find a method with the name \"{methodName}\" on \"{type.FullName()}\".")); + $"Couldn't find a method with the name \"{methodName}\" on \"{type.FullName()}\".", + ExecutionPhase.Validation)); return null; }) .OfType<(INamedTypeSymbol, IMethodSymbol)>()); @@ -496,7 +504,8 @@ void NotParsableAttribute(AttributeData attributeData) => ad, _rangeType, _containerType, - $"Couldn't find the generic type parameter with the name \"{nameOfGenericParameter}\" on \"{genericType.FullName()}\".")); + $"Couldn't find the generic type parameter with the name \"{nameOfGenericParameter}\" on \"{genericType.FullName()}\".", + ExecutionPhase.Validation)); return null; } @@ -551,7 +560,8 @@ void NotParsableAttribute(AttributeData attributeData) => ad, _rangeType, _containerType, - $"Couldn't find the generic type parameter with the name \"{nameOfGenericParameter}\" on \"{genericType.FullName()}\".")); + $"Couldn't find the generic type parameter with the name \"{nameOfGenericParameter}\" on \"{genericType.FullName()}\".", + ExecutionPhase.Validation)); return null; } @@ -591,7 +601,8 @@ void NotParsableAttribute(AttributeData attributeData) => ad, _rangeType, _containerType, - $"Couldn't find the generic type parameter with the name \"{nameOfGenericParameter}\" on \"{genericType.FullName()}\".")); + $"Couldn't find the generic type parameter with the name \"{nameOfGenericParameter}\" on \"{genericType.FullName()}\".", + ExecutionPhase.Validation)); return null; } @@ -631,7 +642,8 @@ void NotParsableAttribute(AttributeData attributeData) => ad, _rangeType, _containerType, - $"Couldn't find the generic type parameter with the name \"{nameOfGenericParameter}\" on \"{genericType.FullName()}\".")); + $"Couldn't find the generic type parameter with the name \"{nameOfGenericParameter}\" on \"{genericType.FullName()}\".", + ExecutionPhase.Validation)); return null; } @@ -677,7 +689,8 @@ IImmutableSet GetAssemblies(INamedTypeSymbol attributeType) => ad, _rangeType, _containerType, - $"Type \"{t.FullName()}\" doesn't lead to a single known assembly.")); + $"Type \"{t.FullName()}\" doesn't lead to a single known assembly.", + ExecutionPhase.Validation)); } return t.ContainingAssembly; }) @@ -709,7 +722,8 @@ IImmutableSet GetAssemblies(INamedTypeSymbol attributeType) => ad, _rangeType, _containerType, - $"Type \"{implementation.FullName()}\" has to be an implementation.")); + $"Type \"{implementation.FullName()}\" has to be an implementation.", + ExecutionPhase.Validation)); return null; } @@ -724,7 +738,8 @@ IImmutableSet GetAssemblies(INamedTypeSymbol attributeType) => ad, _rangeType, _containerType, - $"Type \"{implementation.FullName()}\" has to implement \"{type.FullName()}\".")); + $"Type \"{implementation.FullName()}\" has to implement \"{type.FullName()}\".", + ExecutionPhase.Validation)); return null; } @@ -767,7 +782,8 @@ IImmutableSet GetAssemblies(INamedTypeSymbol attributeType) => ad, _rangeType, _containerType, - $"Type \"{implementation.FullName()}\" has to implement \"{type.FullName()}\".")); + $"Type \"{implementation.FullName()}\" has to implement \"{type.FullName()}\".", + ExecutionPhase.Validation)); return null; } @@ -802,7 +818,8 @@ protected IImmutableSet GetAbstractionTypesFromAttribute( t.Item1, _rangeType, _containerType, - $"Given type \"{t.Item2.FullName()}\" isn't a valid abstraction type. It'll be ignored.")); + $"Given type \"{t.Item2.FullName()}\" isn't a valid abstraction type. It'll be ignored.", + ExecutionPhase.Validation)); return ret; }) @@ -824,7 +841,8 @@ protected IImmutableSet GetImplementationTypesFromAttribute( t.Item1, _rangeType, _containerType, - $"Given type \"{t.Item2.FullName()}\" isn't a valid implementation type. It'll be ignored.")); + $"Given type \"{t.Item2.FullName()}\" isn't a valid implementation type. It'll be ignored.", + ExecutionPhase.Validation)); return ret; }) diff --git a/Main/DiagLogger.cs b/Main/DiagLogger.cs index 500513d5..36d92861 100644 --- a/Main/DiagLogger.cs +++ b/Main/DiagLogger.cs @@ -2,7 +2,7 @@ internal interface IDiagLogger { - void Error(DieException exception); + void Error(DieException exception, ExecutionPhase phase); void Log(Diagnostic diagnostic); } @@ -20,15 +20,15 @@ internal DiagLogger( _context = context; } - public void Error(DieException exception) + public void Error(DieException exception, ExecutionPhase phase) { switch (exception) { case ImplementationCycleDieException implementationCycle: - Log(Diagnostics.CircularReferenceInsideFactory(implementationCycle)); + Log(Diagnostics.CircularReferenceInsideFactory(implementationCycle, phase)); break; case FunctionCycleDieException functionCycleDieException: - Log(Diagnostics.CircularReferenceAmongFactories(functionCycleDieException)); + Log(Diagnostics.CircularReferenceAmongFactories(functionCycleDieException, phase)); break; case ValidationDieException validationDieException: foreach (var error in validationDieException.Diagnostics) @@ -38,7 +38,7 @@ public void Error(DieException exception) Log(slippedResolution.Diagnostic); break; default: - Log(Diagnostics.UnexpectedDieException(exception)); + Log(Diagnostics.UnexpectedDieException(exception, phase)); break; } } diff --git a/Main/Diagnostics.cs b/Main/Diagnostics.cs index e315474c..0a7f2289 100644 --- a/Main/Diagnostics.cs +++ b/Main/Diagnostics.cs @@ -2,15 +2,18 @@ namespace MrMeeseeks.DIE; -public static class Diagnostics +internal static class Diagnostics { - public static Diagnostic CircularReferenceInsideFactory(ImplementationCycleDieException exception) + private static string PhaseToString(ExecutionPhase phase) => + $"[{phase switch { ExecutionPhase.Validation => "Validation", ExecutionPhase.Resolution => "Resolution", ExecutionPhase.CycleDetection => "Cycle Detection", ExecutionPhase.CodeGeneration => "Code Generation", ExecutionPhase.ResolutionBuilding => "Resolution Building", _ => throw new ArgumentOutOfRangeException(nameof(phase), phase, null) }}]"; + + internal static Diagnostic CircularReferenceInsideFactory(ImplementationCycleDieException exception, ExecutionPhase phase) { var cycleText = string.Join(" --> ", exception.Cycle.Select(nts => nts.FullName())); return Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_68_00", "Circular Reference Exception (inside factory)", - $"This container and/or its configuration lead to a circular reference inside one of its factory functions, which need to be generated. The implementations involved in the cycle are: {cycleText}", + $"{PhaseToString(phase)} This container and/or its configuration lead to a circular reference inside one of its factory functions, which need to be generated. The implementations involved in the cycle are: {cycleText}", "Error", DiagnosticSeverity.Error, true), @@ -18,70 +21,70 @@ public static Diagnostic CircularReferenceInsideFactory(ImplementationCycleDieEx } - public static Diagnostic CircularReferenceAmongFactories(FunctionCycleDieException exception) + internal static Diagnostic CircularReferenceAmongFactories(FunctionCycleDieException exception, ExecutionPhase phase) { var cycleText = string.Join(" --> ", exception.Cycle.Select(f => f.Description)); return Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_68_01", "Circular Reference Exception (among factories)", - $"This container and/or its configuration lead to a circular reference among factory functions, which need to be generated. The involved factory functions are: {cycleText}", + $"{PhaseToString(phase)} This container and/or its configuration lead to a circular reference among factory functions, which need to be generated. The involved factory functions are: {cycleText}", "Error", DiagnosticSeverity.Error, true), Location.None); } - public static Diagnostic ValidationContainer(INamedTypeSymbol container, string specification) => + internal static Diagnostic ValidationContainer(INamedTypeSymbol container, string specification, ExecutionPhase phase) => Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_67_00", "Validation (Container)", - $"The Container \"{container.Name}\" isn't validly defined: {specification}", + $"{PhaseToString(phase)} The Container \"{container.Name}\" isn't validly defined: {specification}", "Error", DiagnosticSeverity.Error, true), container.Locations.FirstOrDefault() ?? Location.None); - public static Diagnostic ValidationContainer(INamedTypeSymbol container, string specification, Location location) => + internal static Diagnostic ValidationContainer(INamedTypeSymbol container, string specification, Location location, ExecutionPhase phase) => Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_67_00", "Validation (Container)", - $"The Container \"{container.Name}\" isn't validly defined: {specification}", + $"{PhaseToString(phase)} The Container \"{container.Name}\" isn't validly defined: {specification}", "Error", DiagnosticSeverity.Error, true), location); - public static Diagnostic ValidationTransientScope(INamedTypeSymbol transientScope, INamedTypeSymbol parentContainer, string specification) => + internal static Diagnostic ValidationTransientScope(INamedTypeSymbol transientScope, INamedTypeSymbol parentContainer, string specification, ExecutionPhase phase) => Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_67_01", "Validation (TransientScope)", - $"The TransientScope \"{transientScope.Name}\" (of parent-Container \"{parentContainer.Name}\") isn't validly defined: {specification}", + $"{PhaseToString(phase)} The TransientScope \"{transientScope.Name}\" (of parent-Container \"{parentContainer.Name}\") isn't validly defined: {specification}", "Error", DiagnosticSeverity.Error, true), transientScope.Locations.FirstOrDefault() ?? Location.None); - public static Diagnostic ValidationScope(INamedTypeSymbol scope, INamedTypeSymbol parentContainer, string specification) => + internal static Diagnostic ValidationScope(INamedTypeSymbol scope, INamedTypeSymbol parentContainer, string specification, ExecutionPhase phase) => Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_67_02", "Validation (Scope)", - $"The Scope \"{scope.Name}\" (of parent-Container \"{parentContainer.Name}\") isn't validly defined: {specification}", + $"{PhaseToString(phase)} The Scope \"{scope.Name}\" (of parent-Container \"{parentContainer.Name}\") isn't validly defined: {specification}", "Error", DiagnosticSeverity.Error, true), scope.Locations.FirstOrDefault() ?? Location.None); - public static Diagnostic ValidationUserDefinedElement(ISymbol userDefinedElement, INamedTypeSymbol parentRange, INamedTypeSymbol parentContainer, string specification) + internal static Diagnostic ValidationUserDefinedElement(ISymbol userDefinedElement, INamedTypeSymbol parentRange, INamedTypeSymbol parentContainer, string specification, ExecutionPhase phase) { var rangeDescription = SymbolEqualityComparer.Default.Equals(parentRange, parentContainer) ? $"parent-Container \"{parentContainer.Name}\"" : $"Range \"{parentRange.Name}\" in parent-Container \"{parentContainer.Name}\""; return Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_67_03", "Validation (User-Defined Element)", - $"The user-defined \"{userDefinedElement.Name}\" (of {rangeDescription}) isn't validly defined: {specification}", + $"{PhaseToString(phase)} The user-defined \"{userDefinedElement.Name}\" (of {rangeDescription}) isn't validly defined: {specification}", "Error", DiagnosticSeverity.Error, true), userDefinedElement.Locations.FirstOrDefault() ?? Location.None); } - public static Diagnostic ValidationConfigurationAttribute(AttributeData attributeData, INamedTypeSymbol? parentRange, INamedTypeSymbol? parentContainer, string specification) + internal static Diagnostic ValidationConfigurationAttribute(AttributeData attributeData, INamedTypeSymbol? parentRange, INamedTypeSymbol? parentContainer, string specification, ExecutionPhase phase) { var rangeDescription = parentRange is null && parentContainer is null ? "assembly level" @@ -92,51 +95,51 @@ public static Diagnostic ValidationConfigurationAttribute(AttributeData attribut : $"Range \"{parentRange.Name}\" in parent-Container \"{parentContainer.Name}\""; return Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_67_03", "Validation (Configuration Attribute)", - $"The configuration attribute \"{attributeData.AttributeClass?.Name}\" (of {rangeDescription}) isn't validly defined: {specification}", + $"{PhaseToString(phase)} The configuration attribute \"{attributeData.AttributeClass?.Name}\" (of {rangeDescription}) isn't validly defined: {specification}", "Error", DiagnosticSeverity.Error, true), attributeData.GetLocation()); } - public static Diagnostic UnexpectedDieException(DieException exception) + internal static Diagnostic UnexpectedDieException(DieException exception, ExecutionPhase phase) { return Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_66_00", "Unexpected Exception (DIE)", - exception.ToString(), + $"{PhaseToString(phase)} {exception}", "Error", DiagnosticSeverity.Error, true), Location.None); } - public static Diagnostic UnexpectedException(Exception exception) + internal static Diagnostic UnexpectedException(Exception exception, ExecutionPhase phase) { return Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_66_01", "Unexpected Exception (General)", - exception.ToString(), + $"{PhaseToString(phase)} {exception}", "Error", DiagnosticSeverity.Error, true), Location.None); } - public static Diagnostic CompilationError(string message, Location location) + internal static Diagnostic CompilationError(string message, Location location, ExecutionPhase phase) { return Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_65_00", "Error During Compilation", - message, + $"{PhaseToString(phase)} {message}", "Error", DiagnosticSeverity.Error, true), location); } - public static Diagnostic Logging(string message) + internal static Diagnostic Logging(string message, ExecutionPhase phase) { return Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_00_00", "Logging", - message, + $"{PhaseToString(phase)} {message}", "Log", DiagnosticSeverity.Warning, true), diff --git a/Main/DieException.cs b/Main/DieException.cs index a5db28ae..73631c7f 100644 --- a/Main/DieException.cs +++ b/Main/DieException.cs @@ -11,6 +11,15 @@ public enum DieExceptionKind Compilation } +internal enum ExecutionPhase +{ + Validation, + Resolution, + CycleDetection, + ResolutionBuilding, + CodeGeneration +} + public abstract class DieException : Exception { public abstract DieExceptionKind Kind { get; } diff --git a/Main/ExecuteImpl.cs b/Main/ExecuteImpl.cs index a79b3e78..10152660 100644 --- a/Main/ExecuteImpl.cs +++ b/Main/ExecuteImpl.cs @@ -1,5 +1,4 @@ -using System.CodeDom.Compiler; -using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.CSharp.Syntax; using MrMeeseeks.DIE.CodeBuilding; using MrMeeseeks.DIE.ResolutionBuilding; using MrMeeseeks.DIE.Validation.Range; @@ -61,6 +60,7 @@ public void Execute() .ToList(); foreach (var containerSymbol in containerClasses) { + var currentPhase = ExecutionPhase.Validation; try { var containerInfo = _containerInfoFactory(containerSymbol); @@ -68,6 +68,7 @@ public void Execute() .ToImmutableArray(); if (!validationDiagnostics.Any()) { + currentPhase = ExecutionPhase.Resolution; var containerResolutionBuilder = _containerResolutionBuilderFactory(containerInfo); containerResolutionBuilder.AddCreateResolveFunctions(containerInfo.CreateFunctionData); @@ -75,10 +76,13 @@ public void Execute() { containerResolutionBuilder.DoWork(); } + currentPhase = ExecutionPhase.CycleDetection; containerResolutionBuilder.FunctionCycleTracker.DetectCycle(); + currentPhase = ExecutionPhase.ResolutionBuilding; var containerResolution = containerResolutionBuilder.Build(); + currentPhase = ExecutionPhase.CodeGeneration; _containerGenerator.Generate(containerInfo, containerResolution); } else @@ -94,7 +98,7 @@ public void Execute() containerSymbol.Name, dieException); else - _diagLogger.Error(dieException); + _diagLogger.Error(dieException, currentPhase); } catch (Exception exception) { @@ -104,7 +108,7 @@ public void Execute() containerSymbol.Name, exception); else - _diagLogger.Log(Diagnostics.UnexpectedException(exception)); + _diagLogger.Log(Diagnostics.UnexpectedException(exception, currentPhase)); } } } diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs index 8f4c65ae..1273e2b1 100644 --- a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs @@ -327,7 +327,8 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup 0 => ErrorMessage(implementationStack, namedTypeSymbol, "Lazy: No type argument"), > 1 => ErrorMessage(implementationStack, namedTypeSymbol, "Lazy: more than one type argument"), _ => ErrorMessage(implementationStack, namedTypeSymbol, "Lazy: {namedTypeSymbol.TypeArguments[0].FullName()} is not a named type symbol"), - }, _rangeResolutionBaseBuilder.ErrorContext.Location)), + }, _rangeResolutionBaseBuilder.ErrorContext.Location, + ExecutionPhase.Resolution)), null); } @@ -354,7 +355,12 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup { return ( new ErrorTreeItem(Diagnostics.CompilationError( - ErrorMessage(implementationStack, type, "Func: Return type not named"), _rangeResolutionBaseBuilder.ErrorContext.Location)), + ErrorMessage( + implementationStack, + type, + "Func: Return type not named"), + _rangeResolutionBaseBuilder.ErrorContext.Location, + ExecutionPhase.Resolution)), null); } @@ -394,7 +400,12 @@ IEnumerable GetTypeArguments(INamedTypeSymbol currentSyntaxValueTup { return ( new ErrorTreeItem(Diagnostics.CompilationError( - ErrorMessage(implementationStack, type, "Collection: Collection is not a named type symbol"), _rangeResolutionBaseBuilder.ErrorContext.Location)), + ErrorMessage( + implementationStack, + type, + "Collection: Collection is not a named type symbol"), + _rangeResolutionBaseBuilder.ErrorContext.Location, + ExecutionPhase.Resolution)), null); } @@ -411,7 +422,8 @@ when collectionType.TypeArguments.SingleOrDefault() is INamedTypeSymbol innerTyp default: return (new ErrorTreeItem(Diagnostics.CompilationError( "Collection: Item type couldn't be determined", - _rangeResolutionBaseBuilder.ErrorContext.Location)), + _rangeResolutionBaseBuilder.ErrorContext.Location, + ExecutionPhase.Resolution)), null); } @@ -437,7 +449,12 @@ when collectionType.TypeArguments.SingleOrDefault() is INamedTypeSymbol innerTyp { return ( new ErrorTreeItem(Diagnostics.CompilationError( - ErrorMessage(implementationStack, type, "Collection: Collection's inner type is not a named type symbol"), _rangeResolutionBaseBuilder.ErrorContext.Location)), + ErrorMessage( + implementationStack, + type, + "Collection: Collection's inner type is not a named type symbol"), + _rangeResolutionBaseBuilder.ErrorContext.Location, + ExecutionPhase.Resolution)), null); } @@ -448,7 +465,12 @@ when collectionType.TypeArguments.SingleOrDefault() is INamedTypeSymbol innerTyp { return ( new ErrorTreeItem(Diagnostics.CompilationError( - ErrorMessage(implementationStack, type, "Collection: Collection's inner type is not a named type symbol"), _rangeResolutionBaseBuilder.ErrorContext.Location)), + ErrorMessage( + implementationStack, + type, + "Collection: Collection's inner type is not a named type symbol"), + _rangeResolutionBaseBuilder.ErrorContext.Location, + ExecutionPhase.Resolution)), null); } @@ -488,7 +510,12 @@ when collectionType.TypeArguments.SingleOrDefault() is INamedTypeSymbol innerTyp return ( new ErrorTreeItem(Diagnostics.CompilationError( - ErrorMessage(implementationStack, type, "Couldn't process in resolution tree creation."), _rangeResolutionBaseBuilder.ErrorContext.Location)), + ErrorMessage( + implementationStack, + type, + "Couldn't process in resolution tree creation."), + _rangeResolutionBaseBuilder.ErrorContext.Location, + ExecutionPhase.Resolution)), null); IFactoryResolution CreateFactoryResolution( @@ -705,7 +732,12 @@ INamedTypeSymbol UnwrapAsynchronicity(INamedTypeSymbol currentWrappedType, Stack return interfaceType.NullableAnnotation == NullableAnnotation.Annotated ? (new NullResolution(RootReferenceGenerator.Generate(interfaceType), interfaceType.FullName()), null) // todo warning : (new ErrorTreeItem(Diagnostics.CompilationError( - ErrorMessage(implementationStack, interfaceType, "Interface: Multiple or no implementations where a single is required"), _rangeResolutionBaseBuilder.ErrorContext.Location)), + ErrorMessage( + implementationStack, + interfaceType, + "Interface: Multiple or no implementations where a single is required"), + _rangeResolutionBaseBuilder.ErrorContext.Location, + ExecutionPhase.Resolution)), null); } @@ -774,7 +806,12 @@ INamedTypeSymbol UnwrapAsynchronicity(INamedTypeSymbol currentWrappedType, Stack return implementationType.NullableAnnotation == NullableAnnotation.Annotated ? (new NullResolution(RootReferenceGenerator.Generate(implementationType), implementationType.FullName()), null) // todo warning : (new ErrorTreeItem(Diagnostics.CompilationError( - ErrorMessage(implementationStack, implementationType, "Interface: Multiple or no implementations where a single is required"), _rangeResolutionBaseBuilder.ErrorContext.Location)), + ErrorMessage( + implementationStack, + implementationType, + "Interface: Multiple or no implementations where a single is required"), + _rangeResolutionBaseBuilder.ErrorContext.Location, + ExecutionPhase.Resolution)), null); } @@ -888,7 +925,8 @@ INamedTypeSymbol UnwrapAsynchronicity(INamedTypeSymbol currentWrappedType, Stack 0 => ErrorMessage(implementationStack, implementationType, $"Class.Constructor: No constructor found for implementation {implementationType.FullName()}"), > 1 => ErrorMessage(implementationStack, implementationType, $"Class.Constructor: More than one constructor found for implementation {implementationType.FullName()}"), _ => ErrorMessage(implementationStack, implementationType, $"Class.Constructor: {implementationType.InstanceConstructors[0].Name} is not a method symbol") - }, _rangeResolutionBaseBuilder.ErrorContext.Location)), + }, _rangeResolutionBaseBuilder.ErrorContext.Location, + ExecutionPhase.Resolution)), null); } @@ -1120,7 +1158,12 @@ false when initializationMethod.ReturnType.Equals(_wellKnownTypes.ValueTask, Sym if (typeSymbol is not INamedTypeSymbol && typeSymbol is not IArrayTypeSymbol) return ("", new ErrorTreeItem(Diagnostics.CompilationError( - ErrorMessage(implementationStack, typeSymbol, $"Class.Constructor.Parameter: Parameter type {typeSymbol.FullName()} is not a named type symbol"), _rangeResolutionBaseBuilder.ErrorContext.Location))); + ErrorMessage( + implementationStack, + typeSymbol, + $"Class.Constructor.Parameter: Parameter type {typeSymbol.FullName()} is not a named type symbol"), + _rangeResolutionBaseBuilder.ErrorContext.Location, + ExecutionPhase.Resolution))); return ( parameterName, diff --git a/Main/UserDefinedElements.cs b/Main/UserDefinedElements.cs index 2feeb675..d225cd6c 100644 --- a/Main/UserDefinedElements.cs +++ b/Main/UserDefinedElements.cs @@ -69,7 +69,8 @@ public UserDefinedElements( symbol, scopeType, containerType, - "Multiple user-defined factories aren't allowed to have the same type.")); + "Multiple user-defined factories aren't allowed to have the same type.", + ExecutionPhase.Validation)); _typeToField = new Dictionary(SymbolEqualityComparer.Default); @@ -171,7 +172,8 @@ public UserDefinedElements( t.Item2, scopeType, containerType, - "Multiple user-defined custom constructor parameter methods aren't allowed to have the same type that they are based on.")); + "Multiple user-defined custom constructor parameter methods aren't allowed to have the same type that they are based on.", + ExecutionPhase.Validation)); return new Dictionary(SymbolEqualityComparer.Default); } diff --git a/Main/Validation/Range/UserDefined/ValidateUserDefinedFactoryField.cs b/Main/Validation/Range/UserDefined/ValidateUserDefinedFactoryField.cs index 9e336dbb..8a1e40a4 100644 --- a/Main/Validation/Range/UserDefined/ValidateUserDefinedFactoryField.cs +++ b/Main/Validation/Range/UserDefined/ValidateUserDefinedFactoryField.cs @@ -29,5 +29,5 @@ public IEnumerable Validate(IFieldSymbol field, INamedTypeSymbol ran } protected static Diagnostic ValidationErrorDiagnostic(IFieldSymbol field, INamedTypeSymbol rangeType, INamedTypeSymbol container, string specification) => - Diagnostics.ValidationUserDefinedElement(field, rangeType, container, specification); + Diagnostics.ValidationUserDefinedElement(field, rangeType, container, specification, ExecutionPhase.Validation); } \ No newline at end of file diff --git a/Main/Validation/Range/UserDefined/ValidateUserDefinedMethod.cs b/Main/Validation/Range/UserDefined/ValidateUserDefinedMethod.cs index 1d3695ae..a848304c 100644 --- a/Main/Validation/Range/UserDefined/ValidateUserDefinedMethod.cs +++ b/Main/Validation/Range/UserDefined/ValidateUserDefinedMethod.cs @@ -60,5 +60,5 @@ public virtual IEnumerable Validate(IMethodSymbol method, INamedType } protected static Diagnostic ValidationErrorDiagnostic(IMethodSymbol method, INamedTypeSymbol rangeType, INamedTypeSymbol container, string specification) => - Diagnostics.ValidationUserDefinedElement(method, rangeType, container, specification); + Diagnostics.ValidationUserDefinedElement(method, rangeType, container, specification, ExecutionPhase.Validation); } \ No newline at end of file diff --git a/Main/Validation/Range/ValidateContainer.cs b/Main/Validation/Range/ValidateContainer.cs index 2319bd93..7de10eae 100644 --- a/Main/Validation/Range/ValidateContainer.cs +++ b/Main/Validation/Range/ValidateContainer.cs @@ -144,8 +144,8 @@ IEnumerable ValidateCustomScope(INamedTypeSymbol customScope, ISet - Diagnostics.ValidationContainer(rangeType, specification); + Diagnostics.ValidationContainer(rangeType, specification, ExecutionPhase.Validation); private Diagnostic ValidationErrorDiagnostic(INamedTypeSymbol rangeType, string specification, Location location) => - Diagnostics.ValidationContainer(rangeType, specification, location); + Diagnostics.ValidationContainer(rangeType, specification, location, ExecutionPhase.Validation); } \ No newline at end of file diff --git a/Main/Validation/Range/ValidateScope.cs b/Main/Validation/Range/ValidateScope.cs index 53872f5b..212db4ba 100644 --- a/Main/Validation/Range/ValidateScope.cs +++ b/Main/Validation/Range/ValidateScope.cs @@ -39,5 +39,5 @@ internal ValidateScope( protected override string ScopeName => Constants.ScopeName; protected override Diagnostic ValidationErrorDiagnostic(INamedTypeSymbol rangeType, INamedTypeSymbol containerType, string specification) => - Diagnostics.ValidationScope(rangeType, containerType, specification); + Diagnostics.ValidationScope(rangeType, containerType, specification, ExecutionPhase.Validation); } \ No newline at end of file diff --git a/Main/Validation/Range/ValidateTransientScope.cs b/Main/Validation/Range/ValidateTransientScope.cs index 8b0668a6..f6171e49 100644 --- a/Main/Validation/Range/ValidateTransientScope.cs +++ b/Main/Validation/Range/ValidateTransientScope.cs @@ -39,5 +39,5 @@ internal ValidateTransientScope( protected override string ScopeName => Constants.TransientScopeName; protected override Diagnostic ValidationErrorDiagnostic(INamedTypeSymbol rangeType, INamedTypeSymbol containerType, string specification) => - Diagnostics.ValidationTransientScope(rangeType, containerType, specification); + Diagnostics.ValidationTransientScope(rangeType, containerType, specification, ExecutionPhase.Validation); } \ No newline at end of file From 29e7eaf133697cd7a1ce83ac2f71afbccd83bdd1 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sat, 24 Sep 2022 18:08:34 +0200 Subject: [PATCH 152/162] Resolved open Todos --- Main/CodeBuilding/RangeCodeBaseBuilder.cs | 47 ++++----- Main/Configuration/CheckTypeProperties.cs | 4 +- .../Configuration/CurrentlyConsideredTypes.cs | 4 +- Main/DiagLogger.cs | 3 + Main/Diagnostics.cs | 99 ++++++++++++++++--- Main/DieException.cs | 11 ++- Main/ReferenceGenerator.cs | 36 +++++-- .../Function/FunctionResolutionBuilder.cs | 85 ++++++++++------ .../LocalFunctionResolutionBuilder.cs | 6 +- .../RangedFunctionResolutionBuilder.cs | 6 +- ...copeRootCreateFunctionResolutionBuilder.cs | 6 +- Main/ResolutionTreeItem.cs | 2 +- Main/SourceGenerator.cs | 11 ++- Main/UserDefinedElements.cs | 2 +- 14 files changed, 229 insertions(+), 93 deletions(-) diff --git a/Main/CodeBuilding/RangeCodeBaseBuilder.cs b/Main/CodeBuilding/RangeCodeBaseBuilder.cs index e8c937db..0162db32 100644 --- a/Main/CodeBuilding/RangeCodeBaseBuilder.cs +++ b/Main/CodeBuilding/RangeCodeBaseBuilder.cs @@ -172,25 +172,20 @@ private StringBuilder GenerateDisposalFunction( private StringBuilder GenerateResolutionFunction( StringBuilder stringBuilder, - FunctionResolution resolution) + CreateFunctionResolution resolution) { - if (resolution is CreateFunctionResolution localFunctionResolution) - { - var parameter = string.Join(",", resolution.Parameter.Select(r => $"{r.TypeFullName} {r.Reference}")); - stringBuilder = stringBuilder - .AppendLine($"{resolution.AccessModifier} {(localFunctionResolution.SynchronicityDecision is SynchronicityDecision.AsyncTask or SynchronicityDecision.AsyncValueTask ? "async " : "")}{resolution.TypeFullName} {resolution.Reference}({parameter})") - .AppendLine($"{{"); - stringBuilder = ObjectDisposedCheck(stringBuilder, resolution.TypeFullName); - stringBuilder = GenerateResolutionFunctionContent(stringBuilder, resolution.Resolvable); - stringBuilder = ObjectDisposedCheck(stringBuilder, resolution.TypeFullName); - stringBuilder = stringBuilder - .AppendLine($"return {resolution.Resolvable.Reference};") - .AppendLine($"}}"); - - return stringBuilder; - } + var parameter = string.Join(",", resolution.Parameter.Select(r => $"{r.TypeFullName} {r.Reference}")); + stringBuilder = stringBuilder + .AppendLine($"{resolution.AccessModifier} {(resolution.SynchronicityDecision is SynchronicityDecision.AsyncTask or SynchronicityDecision.AsyncValueTask ? "async " : "")}{resolution.TypeFullName} {resolution.Reference}({parameter})") + .AppendLine($"{{"); + stringBuilder = ObjectDisposedCheck(stringBuilder, resolution.TypeFullName); + stringBuilder = GenerateResolutionFunctionContent(stringBuilder, resolution.Resolvable); + stringBuilder = ObjectDisposedCheck(stringBuilder, resolution.TypeFullName); + stringBuilder = stringBuilder + .AppendLine($"return {resolution.Resolvable.Reference};") + .AppendLine($"}}"); - throw new Exception(); // todo message + return stringBuilder; } private StringBuilder GenerateResolutionFunctionContent( @@ -228,7 +223,9 @@ private StringBuilder GenerateResolutions( break; case LazyResolution(var reference, var typeFullName, var inner): if (inner is MultiSynchronicityFunctionCallResolution { LazySynchronicityDecision.Value: not SynchronicityDecision.Sync }) - throw new Exception("Lazy resolution has to call sync function"); // todo + throw new CompilationDieException(Diagnostics.SyncToAsyncCallCompilationError( + "Return type of Lazy is sync, but the generated function is async.", + ExecutionPhase.CodeGeneration)); var innerResolvable = (Resolvable)inner; stringBuilder = stringBuilder .AppendLine($"{typeFullName} {reference} = new {typeFullName}(() =>") @@ -240,7 +237,9 @@ private StringBuilder GenerateResolutions( break; case FuncResolution(var reference, var typeFullName, var lambdaParameters, var inner): if (inner is MultiSynchronicityFunctionCallResolution { LazySynchronicityDecision.Value: not SynchronicityDecision.Sync }) - throw new Exception("Func resolution has to call sync function"); // todo + throw new CompilationDieException(Diagnostics.SyncToAsyncCallCompilationError( + "Return type of Func is sync, but the generated function is async.", + ExecutionPhase.CodeGeneration)); var innerResolvableFunc = (Resolvable)inner; stringBuilder = stringBuilder .AppendLine($"{typeFullName} {reference} = ({string.Join(", " ,lambdaParameters.Select(p => p.Reference))}) =>") @@ -365,7 +364,9 @@ private StringBuilder GenerateResolutions( break; case TransientScopeAsSyncDisposableResolution(var reference, var typeFullName): if (_containerResolution.DisposalType.HasFlag(DisposalType.Async)) - throw new Exception("If the container disposal has to be async, then sync disposal handles in transient scopes are not allowed."); + throw new CompilationDieException(Diagnostics.SyncDisposalInAsyncContainerCompilationError( + "If the container disposal has to be async, then sync disposal handles in transient scopes are not allowed.", + ExecutionPhase.CodeGeneration)); else if (_containerResolution.DisposalType.HasFlag(DisposalType.Sync)) stringBuilder.AppendLine($"{typeFullName} {reference} = ({typeFullName}) this;"); else @@ -454,7 +455,7 @@ private StringBuilder GenerateResolutions( break; case FactoryResolution(var reference, var typeFullName, var functionName, var parameters, var isAwait): stringBuilder = parameters.Aggregate(stringBuilder, - (builder, tuple) => GenerateResolutions(builder, tuple.Dependency ?? throw new Exception())); + (builder, tuple) => GenerateResolutions(builder, tuple.Dependency ?? throw new ImpossibleDieException(new Guid("2A43FF83-E6A1-47DC-A437-36464CC872F7")))); stringBuilder = stringBuilder.AppendLine($"{typeFullName} {reference} = {(isAwait ? "await " : "")}this.{functionName}({string.Join(", ", parameters.Select(t => $"{t.Name}: {t.Dependency.Reference}"))});"); break; case ArrayResolution(var reference, var typeFullName, var itemFullName, var items): @@ -465,7 +466,9 @@ private StringBuilder GenerateResolutions( case ErrorTreeItem(var diagnostic): throw new CompilationDieException(diagnostic); default: - throw new Exception("Unexpected case or not implemented."); + throw new CompilationDieException(Diagnostics.IncompleteCompilationProcessingError( + "Unfortunately, the compilation phase of DIE seems incomplete. Please open an issue at https://github.com/Yeah69/MrMeeseeks.DIE/issues/new.", + ExecutionPhase.CodeGeneration)); } return stringBuilder; diff --git a/Main/Configuration/CheckTypeProperties.cs b/Main/Configuration/CheckTypeProperties.cs index cbbaeb66..b2e6b594 100644 --- a/Main/Configuration/CheckTypeProperties.cs +++ b/Main/Configuration/CheckTypeProperties.cs @@ -266,8 +266,8 @@ private IReadOnlyList GetClosedImplementations( .ToImmutableArray(); var unboundTargetType = targetType.UnboundIfGeneric(); var isTargetGeneric = targetType.IsGenericType; - if (isTargetGeneric && targetType.TypeArguments.Any(tp => tp is not INamedTypeSymbol)) - throw new Exception("Target type at this point should only have closed generic parameters"); + if (isTargetGeneric && targetType.TypeArguments.Any(tp => tp is not INamedTypeSymbol)) + throw new ImpossibleDieException(new Guid("94B3BC00-9D37-4991-A66A-DDDF7C8402B6")); // Target type at this point should only have closed generic parameters var ret = new List(); foreach (var implementation in rawImplementations) diff --git a/Main/Configuration/CurrentlyConsideredTypes.cs b/Main/Configuration/CurrentlyConsideredTypes.cs index 75c8bb11..446bbb7a 100644 --- a/Main/Configuration/CurrentlyConsideredTypes.cs +++ b/Main/Configuration/CurrentlyConsideredTypes.cs @@ -242,7 +242,7 @@ public CurrentlyConsideredTypes( .Single(t => compositeInterfaces.Contains(t.UnboundIfGeneric(), SymbolEqualityComparer.Default)); return namedTypeSymbol.TypeArguments.FirstOrDefault() is INamedTypeSymbol interfaceTypeSymbol ? interfaceTypeSymbol.UnboundIfGeneric() - : throw new Exception("Composite should implement composite interface"); + : throw new ValidationDieException(ImmutableList.Create(Diagnostics.ValidationGeneral("Composite should implement composite interface"))); }, SymbolEqualityComparer.Default) .Where(g => g.Count() == 1) .ToDictionary(g => g.Key, g => g.Single(), SymbolEqualityComparer.Default); @@ -294,7 +294,7 @@ public CurrentlyConsideredTypes( .Single(t => decoratorInterfaces.Contains(t.UnboundIfGeneric(), SymbolEqualityComparer.Default)); return namedTypeSymbol.TypeArguments.FirstOrDefault() is INamedTypeSymbol interfaceTypeSymbol ? interfaceTypeSymbol.UnboundIfGeneric() - : throw new Exception("Decorator should implement decorator interface"); + : throw new ValidationDieException(ImmutableList.Create(Diagnostics.ValidationGeneral("Decorator should implement decorator interface"))); }, SymbolEqualityComparer.Default) .ToDictionary(g => g.Key, g => (IReadOnlyList) g.ToList(), SymbolEqualityComparer.Default); diff --git a/Main/DiagLogger.cs b/Main/DiagLogger.cs index 36d92861..11fc44bb 100644 --- a/Main/DiagLogger.cs +++ b/Main/DiagLogger.cs @@ -37,6 +37,9 @@ public void Error(DieException exception, ExecutionPhase phase) case CompilationDieException slippedResolution: Log(slippedResolution.Diagnostic); break; + case ImpossibleDieException impossibleDieException: + Log(Diagnostics.ImpossibleException(impossibleDieException, phase)); + break; default: Log(Diagnostics.UnexpectedDieException(exception, phase)); break; diff --git a/Main/Diagnostics.cs b/Main/Diagnostics.cs index 0a7f2289..c94e259a 100644 --- a/Main/Diagnostics.cs +++ b/Main/Diagnostics.cs @@ -13,7 +13,7 @@ internal static Diagnostic CircularReferenceInsideFactory(ImplementationCycleDie return Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_68_00", "Circular Reference Exception (inside factory)", - $"{PhaseToString(phase)} This container and/or its configuration lead to a circular reference inside one of its factory functions, which need to be generated. The implementations involved in the cycle are: {cycleText}", + $"[DIE] {PhaseToString(phase)} This container and/or its configuration lead to a circular reference inside one of its factory functions, which need to be generated. The implementations involved in the cycle are: {cycleText}", "Error", DiagnosticSeverity.Error, true), @@ -27,7 +27,7 @@ internal static Diagnostic CircularReferenceAmongFactories(FunctionCycleDieExcep return Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_68_01", "Circular Reference Exception (among factories)", - $"{PhaseToString(phase)} This container and/or its configuration lead to a circular reference among factory functions, which need to be generated. The involved factory functions are: {cycleText}", + $"[DIE] {PhaseToString(phase)} This container and/or its configuration lead to a circular reference among factory functions, which need to be generated. The involved factory functions are: {cycleText}", "Error", DiagnosticSeverity.Error, true), @@ -37,7 +37,7 @@ internal static Diagnostic CircularReferenceAmongFactories(FunctionCycleDieExcep internal static Diagnostic ValidationContainer(INamedTypeSymbol container, string specification, ExecutionPhase phase) => Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_67_00", "Validation (Container)", - $"{PhaseToString(phase)} The Container \"{container.Name}\" isn't validly defined: {specification}", + $"[DIE] {PhaseToString(phase)} The Container \"{container.Name}\" isn't validly defined: {specification}", "Error", DiagnosticSeverity.Error, true), @@ -46,7 +46,7 @@ internal static Diagnostic ValidationContainer(INamedTypeSymbol container, strin internal static Diagnostic ValidationContainer(INamedTypeSymbol container, string specification, Location location, ExecutionPhase phase) => Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_67_00", "Validation (Container)", - $"{PhaseToString(phase)} The Container \"{container.Name}\" isn't validly defined: {specification}", + $"[DIE] {PhaseToString(phase)} The Container \"{container.Name}\" isn't validly defined: {specification}", "Error", DiagnosticSeverity.Error, true), @@ -55,7 +55,7 @@ internal static Diagnostic ValidationContainer(INamedTypeSymbol container, strin internal static Diagnostic ValidationTransientScope(INamedTypeSymbol transientScope, INamedTypeSymbol parentContainer, string specification, ExecutionPhase phase) => Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_67_01", "Validation (TransientScope)", - $"{PhaseToString(phase)} The TransientScope \"{transientScope.Name}\" (of parent-Container \"{parentContainer.Name}\") isn't validly defined: {specification}", + $"[DIE] {PhaseToString(phase)} The TransientScope \"{transientScope.Name}\" (of parent-Container \"{parentContainer.Name}\") isn't validly defined: {specification}", "Error", DiagnosticSeverity.Error, true), @@ -64,7 +64,7 @@ internal static Diagnostic ValidationTransientScope(INamedTypeSymbol transientSc internal static Diagnostic ValidationScope(INamedTypeSymbol scope, INamedTypeSymbol parentContainer, string specification, ExecutionPhase phase) => Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_67_02", "Validation (Scope)", - $"{PhaseToString(phase)} The Scope \"{scope.Name}\" (of parent-Container \"{parentContainer.Name}\") isn't validly defined: {specification}", + $"[DIE] {PhaseToString(phase)} The Scope \"{scope.Name}\" (of parent-Container \"{parentContainer.Name}\") isn't validly defined: {specification}", "Error", DiagnosticSeverity.Error, true), @@ -77,7 +77,7 @@ internal static Diagnostic ValidationUserDefinedElement(ISymbol userDefinedEleme : $"Range \"{parentRange.Name}\" in parent-Container \"{parentContainer.Name}\""; return Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_67_03", "Validation (User-Defined Element)", - $"{PhaseToString(phase)} The user-defined \"{userDefinedElement.Name}\" (of {rangeDescription}) isn't validly defined: {specification}", + $"[DIE] {PhaseToString(phase)} The user-defined \"{userDefinedElement.Name}\" (of {rangeDescription}) isn't validly defined: {specification}", "Error", DiagnosticSeverity.Error, true), @@ -95,18 +95,27 @@ internal static Diagnostic ValidationConfigurationAttribute(AttributeData attrib : $"Range \"{parentRange.Name}\" in parent-Container \"{parentContainer.Name}\""; return Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_67_03", "Validation (Configuration Attribute)", - $"{PhaseToString(phase)} The configuration attribute \"{attributeData.AttributeClass?.Name}\" (of {rangeDescription}) isn't validly defined: {specification}", + $"[DIE] {PhaseToString(phase)} The configuration attribute \"{attributeData.AttributeClass?.Name}\" (of {rangeDescription}) isn't validly defined: {specification}", "Error", DiagnosticSeverity.Error, true), attributeData.GetLocation()); } + internal static Diagnostic ValidationGeneral(string message) => + Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_67_02", + "Validation (General)", + $"[DIE] {PhaseToString(ExecutionPhase.Validation)} {message}", + "Error", + DiagnosticSeverity.Error, + true), + Location.None); + internal static Diagnostic UnexpectedDieException(DieException exception, ExecutionPhase phase) { return Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_66_00", "Unexpected Exception (DIE)", - $"{PhaseToString(phase)} {exception}", + $"[DIE] {PhaseToString(phase)} {exception}", "Error", DiagnosticSeverity.Error, true), @@ -117,7 +126,18 @@ internal static Diagnostic UnexpectedException(Exception exception, ExecutionPha { return Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_66_01", "Unexpected Exception (General)", - $"{PhaseToString(phase)} {exception}", + $"[DIE] {PhaseToString(phase)} {exception}", + "Error", + DiagnosticSeverity.Error, + true), + Location.None); + } + + internal static Diagnostic ImpossibleException(ImpossibleDieException exception, ExecutionPhase phase) + { + return Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_66_02", + "Impossible Exception", + $"[DIE] {PhaseToString(phase)} You've run into an impossible exception. Please make a issue at https://github.com/Yeah69/MrMeeseeks.DIE/issues/new with code hint \"{exception.Code.ToString()}\".", "Error", DiagnosticSeverity.Error, true), @@ -128,21 +148,70 @@ internal static Diagnostic CompilationError(string message, Location location, E { return Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_65_00", "Error During Compilation", - $"{PhaseToString(phase)} {message}", + $"[DIE] {PhaseToString(phase)} {message}", "Error", DiagnosticSeverity.Error, true), location); } - internal static Diagnostic Logging(string message, ExecutionPhase phase) + internal static Diagnostic SyncToAsyncCallCompilationError(string message, ExecutionPhase phase) + { + return Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_65_01", + "Sync Call To Async Function Error", + $"[DIE] {PhaseToString(phase)} {message}", + "Error", + DiagnosticSeverity.Error, + true), + Location.None); + } + + internal static Diagnostic SyncDisposalInAsyncContainerCompilationError(string message, ExecutionPhase phase) + { + return Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_65_02", + "Sync Disposal In Async Container Error", + $"[DIE] {PhaseToString(phase)} {message}", + "Error", + DiagnosticSeverity.Error, + true), + Location.None); + } + + internal static Diagnostic IncompleteCompilationProcessingError(string message, ExecutionPhase phase) { - return Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_00_00", + return Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_65_02", + "Incomplete Compilation Processing Error", + $"[DIE] {PhaseToString(phase)} {message}", + "Error", + DiagnosticSeverity.Error, + true), + Location.None); + } + + internal static Diagnostic NullResolutionWarning(string message, ExecutionPhase phase) => + Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_70_00", + "Null Resolution Warning", + $"[DIE] {PhaseToString(phase)} {message}", + "Warning", + DiagnosticSeverity.Warning, + true), + Location.None); + + internal static Diagnostic EmptyReferenceNameWarning(string message, ExecutionPhase phase) => + Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_70_01", + "Empty Reference Name Warning", + $"[DIE] {PhaseToString(phase)} {message}", + "Warning", + DiagnosticSeverity.Warning, + true), + Location.None); + + internal static Diagnostic Logging(string message, ExecutionPhase phase) => + Diagnostic.Create(new DiagnosticDescriptor($"{Constants.DieAbbreviation}_00_00", "Logging", - $"{PhaseToString(phase)} {message}", + $"[DIE] {PhaseToString(phase)} {message}", "Log", DiagnosticSeverity.Warning, true), Location.None); - } } \ No newline at end of file diff --git a/Main/DieException.cs b/Main/DieException.cs index 73631c7f..e70f3c67 100644 --- a/Main/DieException.cs +++ b/Main/DieException.cs @@ -8,7 +8,8 @@ public enum DieExceptionKind ImplementationCycle, FunctionCycle, Validation, - Compilation + Compilation, + Impossible } internal enum ExecutionPhase @@ -56,4 +57,12 @@ public class CompilationDieException : DieException public CompilationDieException(Diagnostic diagnostic) => Diagnostic = diagnostic; public override DieExceptionKind Kind => DieExceptionKind.Compilation; +} + +public class ImpossibleDieException : DieException +{ + public Guid Code { get; } + + public ImpossibleDieException(Guid code) => Code = code; + public override DieExceptionKind Kind => DieExceptionKind.Impossible; } \ No newline at end of file diff --git a/Main/ReferenceGenerator.cs b/Main/ReferenceGenerator.cs index b50e799b..457d2d62 100644 --- a/Main/ReferenceGenerator.cs +++ b/Main/ReferenceGenerator.cs @@ -12,20 +12,38 @@ internal class ReferenceGenerator : IReferenceGenerator { private int _i = -1; private readonly int _j; + private readonly IDiagLogger _diagLogger; - internal ReferenceGenerator(int j) => _j = j; + internal ReferenceGenerator( + // parameters + int j, + + // dependencies + IDiagLogger diagLogger) + { + _j = j; + _diagLogger = diagLogger; + } public string Generate(ITypeSymbol type) { - var baseName = type switch + string baseName; + switch (type) { - INamedTypeSymbol namedTypeSymbol => - $"{char.ToLower(namedTypeSymbol.Name[0])}{namedTypeSymbol.Name.Substring(1)}", - IArrayTypeSymbol { ElementType: {} elementType } => - $"{char.ToLower(elementType.Name[0])}{elementType.Name.Substring(1)}Array", - _ => "empty" // todo warning type without name seems strange - }; - + case INamedTypeSymbol namedTypeSymbol: + baseName = $"{char.ToLower(namedTypeSymbol.Name[0])}{namedTypeSymbol.Name.Substring(1)}"; + break; + case IArrayTypeSymbol { ElementType: { } elementType }: + baseName = $"{char.ToLower(elementType.Name[0])}{elementType.Name.Substring(1)}Array"; + break; + default: + _diagLogger.Log(Diagnostics.EmptyReferenceNameWarning( + $"A reference name couldn't be generated for \"{type.FullName()}\"", + ExecutionPhase.Resolution)); + baseName = "empty"; + break; + } + return GenerateInner(string.Empty, baseName, string.Empty); } diff --git a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs index 1273e2b1..e05cddf3 100644 --- a/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/FunctionResolutionBuilder.cs @@ -62,6 +62,7 @@ internal abstract partial class FunctionResolutionBuilder : IFunctionResolutionB private readonly IFunctionResolutionSynchronicityDecisionMaker _synchronicityDecisionMaker; private readonly WellKnownTypes _wellKnownTypes; private readonly IFunctionCycleTracker _functionCycleTracker; + private readonly IDiagLogger _diagLogger; private readonly ICheckTypeProperties _checkTypeProperties; private readonly Dictionary _scopedInstancesReferenceCache = new(SymbolEqualityComparer.Default); @@ -96,13 +97,15 @@ internal FunctionResolutionBuilder( // dependencies WellKnownTypes wellKnownTypes, IReferenceGeneratorFactory referenceGeneratorFactory, - IFunctionCycleTracker functionCycleTracker) + IFunctionCycleTracker functionCycleTracker, + IDiagLogger diagLogger) { OriginalReturnType = returnType; _rangeResolutionBaseBuilder = rangeResolutionBaseBuilder; _synchronicityDecisionMaker = synchronicityDecisionMaker; _wellKnownTypes = wellKnownTypes; _functionCycleTracker = functionCycleTracker; + _diagLogger = diagLogger; _checkTypeProperties = rangeResolutionBaseBuilder.CheckTypeProperties; _userDefinedElements = rangeResolutionBaseBuilder.UserDefinedElements; Handle = new FunctionResolutionBuilderHandle( @@ -545,7 +548,7 @@ IFactoryResolution CreateFactoryResolution( { Function.SynchronicityDecision.AsyncValueTask => _wellKnownTypes.ValueTask1.Construct(currentType), Function.SynchronicityDecision.AsyncTask => _wellKnownTypes.Task1.Construct(currentType), - _ => throw new Exception("Shouldn't happen") // todo + _ => throw new ImpossibleDieException(new Guid("3946978C-4A1D-477B-8C4B-D610DE6BC6A7")) }; currentResolution = new AsyncFactoryCallResolution( RootReferenceGenerator.Generate(currentType), @@ -559,7 +562,7 @@ IFactoryResolution CreateFactoryResolution( { Function.SynchronicityDecision.AsyncValueTask => _wellKnownTypes.ValueTask1.Construct(currentType), Function.SynchronicityDecision.AsyncTask => _wellKnownTypes.Task1.Construct(currentType), - _ => throw new Exception("Shouldn't happen") // todo + _ => throw new ImpossibleDieException(new Guid("041B43CA-287F-42BC-AEBB-36B931EDB424")) }; currentResolution = nextAsynchronicity switch { @@ -571,7 +574,7 @@ IFactoryResolution CreateFactoryResolution( (Resolvable) currentResolution, RootReferenceGenerator.Generate(currentType), currentType.FullName()), - _ => throw new Exception("Shouldn't happen") // todo + _ => throw new ImpossibleDieException(new Guid("61F9F5A1-0E5B-418F-80D5-BAFC41DCB551")) }; } } @@ -709,7 +712,7 @@ INamedTypeSymbol UnwrapAsynchronicity(INamedTypeSymbol currentWrappedType, Stack { var implementations = _checkTypeProperties.MapToImplementations(interfaceType); var compositeImplementationType = _checkTypeProperties.GetCompositeFor(interfaceType) - ?? throw new Exception("No or multiple composite implementations"); + ?? throw new ImpossibleDieException(new Guid("2E4A28E8-573B-4087-95FE-BDED04DB3981")); var interfaceResolutions = implementations.Select(i => SwitchInterfaceWithoutComposition(new CreateInterfaceParameter( interfaceType, i, @@ -729,16 +732,22 @@ INamedTypeSymbol UnwrapAsynchronicity(INamedTypeSymbol currentWrappedType, Stack } if (_checkTypeProperties.MapToSingleFittingImplementation(interfaceType) is not { } implementationType) { - return interfaceType.NullableAnnotation == NullableAnnotation.Annotated - ? (new NullResolution(RootReferenceGenerator.Generate(interfaceType), interfaceType.FullName()), null) // todo warning - : (new ErrorTreeItem(Diagnostics.CompilationError( + if (interfaceType.NullableAnnotation == NullableAnnotation.Annotated) + { + _diagLogger.Log(Diagnostics.NullResolutionWarning( + $"Interface: Multiple or no implementations where a single is required for \"{interfaceType.FullName()}\", but injecting null instead.", + ExecutionPhase.Resolution)); + return (new NullResolution(RootReferenceGenerator.Generate(interfaceType), interfaceType.FullName()), + null); + } + return (new ErrorTreeItem(Diagnostics.CompilationError( ErrorMessage( - implementationStack, - interfaceType, - "Interface: Multiple or no implementations where a single is required"), + implementationStack, + interfaceType, + $"Interface: Multiple or no implementations where a single is required for \"{interfaceType.FullName()}\"."), _rangeResolutionBaseBuilder.ErrorContext.Location, - ExecutionPhase.Resolution)), - null); + ExecutionPhase.Resolution)), + null); } return SwitchInterfaceWithoutComposition(new CreateInterfaceParameter( @@ -803,16 +812,23 @@ INamedTypeSymbol UnwrapAsynchronicity(INamedTypeSymbol currentWrappedType, Stack if (_checkTypeProperties.MapToSingleFittingImplementation(implementationType) is not { } chosenImplementationType) { - return implementationType.NullableAnnotation == NullableAnnotation.Annotated - ? (new NullResolution(RootReferenceGenerator.Generate(implementationType), implementationType.FullName()), null) // todo warning - : (new ErrorTreeItem(Diagnostics.CompilationError( + if (implementationType.NullableAnnotation == NullableAnnotation.Annotated) + { + _diagLogger.Log(Diagnostics.NullResolutionWarning( + $"Interface: Multiple or no implementations where a single is required for \"{implementationType.FullName()}\", but injecting null instead.", + ExecutionPhase.Resolution)); + return ( + new NullResolution(RootReferenceGenerator.Generate(implementationType), + implementationType.FullName()), null); + } + return (new ErrorTreeItem(Diagnostics.CompilationError( ErrorMessage( - implementationStack, - implementationType, - "Interface: Multiple or no implementations where a single is required"), + implementationStack, + implementationType, + $"Interface: Multiple or no implementations where a single is required for \"{implementationType.FullName()}\","), _rangeResolutionBaseBuilder.ErrorContext.Location, - ExecutionPhase.Resolution)), - null); + ExecutionPhase.Resolution)), + null); } var nextParameter = new SwitchImplementationParameter( @@ -917,17 +933,26 @@ INamedTypeSymbol UnwrapAsynchronicity(INamedTypeSymbol currentWrappedType, Stack if (_checkTypeProperties.GetConstructorChoiceFor(implementationType) is not { } constructor) { - return implementationType.NullableAnnotation == NullableAnnotation.Annotated - ? (new NullResolution(RootReferenceGenerator.Generate(implementationType), - implementationType.FullName()), null) // todo warning - : (new ErrorTreeItem(Diagnostics.CompilationError(implementationType.InstanceConstructors.Length switch + if (implementationType.NullableAnnotation == NullableAnnotation.Annotated) + { + _diagLogger.Log(Diagnostics.NullResolutionWarning( + $"Interface: Multiple or no implementations where a single is required for \"{implementationType.FullName()}\", but injecting null instead.", + ExecutionPhase.Resolution)); + return (new NullResolution(RootReferenceGenerator.Generate(implementationType), + implementationType.FullName()), null); + } + return (new ErrorTreeItem(Diagnostics.CompilationError( + implementationType.InstanceConstructors.Length switch { - 0 => ErrorMessage(implementationStack, implementationType, $"Class.Constructor: No constructor found for implementation {implementationType.FullName()}"), - > 1 => ErrorMessage(implementationStack, implementationType, $"Class.Constructor: More than one constructor found for implementation {implementationType.FullName()}"), - _ => ErrorMessage(implementationStack, implementationType, $"Class.Constructor: {implementationType.InstanceConstructors[0].Name} is not a method symbol") + 0 => ErrorMessage(implementationStack, implementationType, + $"Class.Constructor: No constructor found for implementation {implementationType.FullName()}"), + > 1 => ErrorMessage(implementationStack, implementationType, + $"Class.Constructor: More than one constructor found for implementation {implementationType.FullName()}"), + _ => ErrorMessage(implementationStack, implementationType, + $"Class.Constructor: {implementationType.InstanceConstructors[0].Name} is not a method symbol") }, _rangeResolutionBaseBuilder.ErrorContext.Location, - ExecutionPhase.Resolution)), - null); + ExecutionPhase.Resolution)), + null); } var implementationCycle = implementationStack.Contains(implementationType, SymbolEqualityComparer.Default); diff --git a/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs index 49e9e7ce..2b6b0d8a 100644 --- a/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/LocalFunctionResolutionBuilder.cs @@ -20,7 +20,8 @@ public CreateFunctionResolutionBuilder( // dependencies WellKnownTypes wellKnownTypes, IReferenceGeneratorFactory referenceGeneratorFactory, - IFunctionCycleTracker functionCycleTracker) + IFunctionCycleTracker functionCycleTracker, + IDiagLogger diagLogger) : base( rangeResolutionBaseBuilder, returnType, @@ -30,7 +31,8 @@ public CreateFunctionResolutionBuilder( wellKnownTypes, referenceGeneratorFactory, - functionCycleTracker) + functionCycleTracker, + diagLogger) { _returnType = returnType; _accessModifier = accessModifier; diff --git a/Main/ResolutionBuilding/Function/RangedFunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/RangedFunctionResolutionBuilder.cs index 885cad0a..24f5f82a 100644 --- a/Main/ResolutionBuilding/Function/RangedFunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/RangedFunctionResolutionBuilder.cs @@ -19,7 +19,8 @@ public RangedFunctionResolutionBuilder( // dependencies WellKnownTypes wellKnownTypes, IReferenceGeneratorFactory referenceGeneratorFactory, - IFunctionCycleTracker functionCycleTracker) + IFunctionCycleTracker functionCycleTracker, + IDiagLogger diagLogger) : base( rangeResolutionBaseBuilder, forConstructorParameter.ImplementationType, @@ -29,7 +30,8 @@ public RangedFunctionResolutionBuilder( wellKnownTypes, referenceGeneratorFactory, - functionCycleTracker) + functionCycleTracker, + diagLogger) { _forConstructorParameter = forConstructorParameter; diff --git a/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs b/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs index 03f729d0..cc4c51bd 100644 --- a/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs +++ b/Main/ResolutionBuilding/Function/ScopeRootCreateFunctionResolutionBuilder.cs @@ -17,7 +17,8 @@ public ScopeRootCreateFunctionResolutionBuilder( // dependencies WellKnownTypes wellKnownTypes, IReferenceGeneratorFactory referenceGeneratorFactory, - IFunctionCycleTracker functionCycleTracker) + IFunctionCycleTracker functionCycleTracker, + IDiagLogger diagLogger) : base( rangeResolutionBaseBuilder, parameter.ReturnType, @@ -27,7 +28,8 @@ public ScopeRootCreateFunctionResolutionBuilder( wellKnownTypes, referenceGeneratorFactory, - functionCycleTracker) + functionCycleTracker, + diagLogger) { _parameter = parameter; diff --git a/Main/ResolutionTreeItem.cs b/Main/ResolutionTreeItem.cs index ee7270fd..79fcc48a 100644 --- a/Main/ResolutionTreeItem.cs +++ b/Main/ResolutionTreeItem.cs @@ -427,7 +427,7 @@ internal Resolvable Inner case (SynchronicityDecision.AsyncValueTask, SynchronicityDecision.AsyncTask): return new TaskFromWrappedValueTaskResolution(FunctionCall.SelectedFunctionCall, Reference, TypeFullName); default: - throw new ArgumentOutOfRangeException(); // todo + throw new ImpossibleDieException(new Guid("822DB30A-0DB6-4560-8389-B5AF5D19481D")); } } } diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index 75b2dbe7..20393c61 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -232,7 +232,8 @@ ICreateFunctionResolutionBuilder CreateFunctionResolutionBuilderFactory( wellKnownTypes, referenceGeneratorFactory, - functionCycleTracker); + functionCycleTracker, + diagLogger); IScopeRootCreateFunctionResolutionBuilder ScopeRootCreateFunctionResolutionBuilderFactory( IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, @@ -243,7 +244,8 @@ IScopeRootCreateFunctionResolutionBuilder ScopeRootCreateFunctionResolutionBuild wellKnownTypes, referenceGeneratorFactory, - functionCycleTracker); + functionCycleTracker, + diagLogger); IRangedFunctionResolutionBuilder RangedFunctionResolutionBuilderFactory( IRangeResolutionBaseBuilder rangeResolutionBaseBuilder, @@ -259,7 +261,8 @@ IRangedFunctionResolutionBuilder RangedFunctionResolutionBuilderFactory( wellKnownTypes, referenceGeneratorFactory, - functionCycleTracker); + functionCycleTracker, + diagLogger); IRangedFunctionGroupResolutionBuilder RangedFunctionGroupResolutionBuilderFactory( string label, @@ -282,7 +285,7 @@ IFunctionResolutionSynchronicityDecisionMaker FunctionResolutionSynchronicityDec new FunctionResolutionSynchronicityDecisionMaker(); } IContainerInfo ContainerInfoFactory(INamedTypeSymbol type) => new ContainerInfo(type, wellKnownTypesMiscellaneous); - IReferenceGenerator ReferenceGeneratorFactory(int j) => new ReferenceGenerator(j); + IReferenceGenerator ReferenceGeneratorFactory(int j) => new ReferenceGenerator(j, diagLogger); IContainerCodeBuilder ContainerCodeBuilderFactory( IContainerInfo containerInfo, diff --git a/Main/UserDefinedElements.cs b/Main/UserDefinedElements.cs index d225cd6c..c554e50b 100644 --- a/Main/UserDefinedElements.cs +++ b/Main/UserDefinedElements.cs @@ -55,7 +55,7 @@ public UserDefinedElements( IFieldSymbol fs => fs.Type, IPropertySymbol ps => ps.Type, IMethodSymbol ms => ms.ReturnType, - _ => throw new Exception("Impossible") + _ => throw new ImpossibleDieException(new Guid("B75E24B2-61A3-4C37-B5A5-C7E6D390279D")) }, SymbolEqualityComparer.Default) .Where(g => g.Count() > 1) .ToImmutableArray(); From c0884799d9df62451817a2f418c203671a598eb6 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sat, 24 Sep 2022 18:40:19 +0200 Subject: [PATCH 153/162] Turning testing in CI --- .github/workflows/main.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ea938ed8..91533821 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -26,6 +26,8 @@ jobs: run: dotnet restore .\MrMeeseeks.DIE.sln - name: Build run: dotnet build .\MrMeeseeks.DIE.sln --configuration Release --no-restore + - name: Test + run: dotnet test .\Test\Test.csproj --no-restore --verbosity normal - name: Publish to NuGet uses: brandedoutcast/publish-nuget@master with: From 534277d48e1a02423d2c9b25de07adb3e60a0e1c Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sat, 24 Sep 2022 20:40:24 +0200 Subject: [PATCH 154/162] Updated .Net SDK --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 91533821..fdd77b40 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -20,7 +20,7 @@ jobs: - name: Setup .NET Core uses: actions/setup-dotnet@v2.1.0 with: - dotnet-version: 6.0.400 + dotnet-version: 6.0.401 - run: set DOTNET_CLI_TELEMETRY_OPTOUT=1 - name: Install dependencies run: dotnet restore .\MrMeeseeks.DIE.sln From dbc525b6a7940369b3249ad68dde688668ad1524 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sun, 25 Sep 2022 09:19:20 +0200 Subject: [PATCH 155/162] Removed unused project SampleChild --- MrMeeseeks.DIE.sln | 6 -- Sample/Sample.csproj | 1 - SampleChild/AssemblyInfo.cs | 17 ----- SampleChild/Public.cs | 124 -------------------------------- SampleChild/SampleChild.csproj | 11 --- SampleChild/lnternal.cs | 125 --------------------------------- Test/Test.csproj | 2 +- 7 files changed, 1 insertion(+), 285 deletions(-) delete mode 100644 SampleChild/AssemblyInfo.cs delete mode 100644 SampleChild/Public.cs delete mode 100644 SampleChild/SampleChild.csproj delete mode 100644 SampleChild/lnternal.cs diff --git a/MrMeeseeks.DIE.sln b/MrMeeseeks.DIE.sln index 79a2bf46..a65561b0 100644 --- a/MrMeeseeks.DIE.sln +++ b/MrMeeseeks.DIE.sln @@ -17,8 +17,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test", "Test\Test.csproj", EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestChild", "TestChild\TestChild.csproj", "{1CCECD48-C564-4799-8A4C-19A9BF847795}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SampleChild", "SampleChild\SampleChild.csproj", "{73D1DC76-4CD8-4534-8717-0551B635F864}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestNotInternalsVisibleToChild", "TestNotInternalsVisibleToChild\TestNotInternalsVisibleToChild.csproj", "{E1D7CC3A-1340-4817-81C7-6820A2F31A8D}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestInternalsVisibleToChild", "TestInternalsVisibleToChild\TestInternalsVisibleToChild.csproj", "{AB74CB8A-5195-4CB0-9844-71AFB1F5C926}" @@ -47,10 +45,6 @@ Global {1CCECD48-C564-4799-8A4C-19A9BF847795}.Debug|Any CPU.Build.0 = Debug|Any CPU {1CCECD48-C564-4799-8A4C-19A9BF847795}.Release|Any CPU.ActiveCfg = Release|Any CPU {1CCECD48-C564-4799-8A4C-19A9BF847795}.Release|Any CPU.Build.0 = Release|Any CPU - {73D1DC76-4CD8-4534-8717-0551B635F864}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {73D1DC76-4CD8-4534-8717-0551B635F864}.Debug|Any CPU.Build.0 = Debug|Any CPU - {73D1DC76-4CD8-4534-8717-0551B635F864}.Release|Any CPU.ActiveCfg = Release|Any CPU - {73D1DC76-4CD8-4534-8717-0551B635F864}.Release|Any CPU.Build.0 = Release|Any CPU {E1D7CC3A-1340-4817-81C7-6820A2F31A8D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E1D7CC3A-1340-4817-81C7-6820A2F31A8D}.Debug|Any CPU.Build.0 = Debug|Any CPU {E1D7CC3A-1340-4817-81C7-6820A2F31A8D}.Release|Any CPU.ActiveCfg = Release|Any CPU diff --git a/Sample/Sample.csproj b/Sample/Sample.csproj index f21bc7a0..3a5f8710 100644 --- a/Sample/Sample.csproj +++ b/Sample/Sample.csproj @@ -22,7 +22,6 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - diff --git a/SampleChild/AssemblyInfo.cs b/SampleChild/AssemblyInfo.cs deleted file mode 100644 index 1f84de8f..00000000 --- a/SampleChild/AssemblyInfo.cs +++ /dev/null @@ -1,17 +0,0 @@ -global using Microsoft.CodeAnalysis; -global using System; -global using System.Collections.Generic; -global using System.Collections.Immutable; -global using System.Collections.ObjectModel; -global using System.Linq; -global using System.Text; -using System.Runtime.CompilerServices; - -[assembly:InternalsVisibleTo("MrMeeseeks.DIE.Sample")] - -namespace MrMeeseeks.DIE.SampleChild; - -public class AssemblyInfo -{ - -} \ No newline at end of file diff --git a/SampleChild/Public.cs b/SampleChild/Public.cs deleted file mode 100644 index 338213e8..00000000 --- a/SampleChild/Public.cs +++ /dev/null @@ -1,124 +0,0 @@ -namespace MrMeeseeks.DIE.SampleChild; - -public interface IClass {} - -public class Class : IClass -{ - public Class() - { - } - - public Class(int i) - { - - } -} - -public interface IClassToo {} - -public class ClassToo : IClassToo -{ - public ClassToo() - { - - } - - public ClassToo(int i) - { - - } -} - -public interface IClass {} - -public class Class : IClass -{ - public Class() - { - } - - public Class(int i) - { - - } -} - -public static class StaticParent -{ - public class Class : IClass - { - public Class() - { - } - - public Class(int i) - { - - } - } - - public class ClassToo : IClassToo - { - public ClassToo() - { - - } - - public ClassToo(int i) - { - - } - } - - public class Class : IClass - { - public Class() - { - } - - public Class(int i) - { - - } - } -} - -public class Parent -{ - public class Class : IClass - { - public Class() - { - } - - public Class(int i) - { - - } - } - - public class ClassToo : IClassToo - { - public ClassToo() - { - - } - - public ClassToo(int i) - { - - } - } - - public class Class : IClass - { - public Class() - { - } - - public Class(int i) - { - - } - } -} \ No newline at end of file diff --git a/SampleChild/SampleChild.csproj b/SampleChild/SampleChild.csproj deleted file mode 100644 index 0990b974..00000000 --- a/SampleChild/SampleChild.csproj +++ /dev/null @@ -1,11 +0,0 @@ - - - - net6.0 - - MrMeeseeks.DIE.SampleChild - MrMeeseeks.DIE.SampleChild - true - $(BaseIntermediateOutputPath)\GeneratedFiles - - diff --git a/SampleChild/lnternal.cs b/SampleChild/lnternal.cs deleted file mode 100644 index 2edcde79..00000000 --- a/SampleChild/lnternal.cs +++ /dev/null @@ -1,125 +0,0 @@ -namespace MrMeeseeks.DIE.SampleChild.Internal; - -internal interface IClass {} - -internal class Class : IClass -{ - internal Class() - { - } - - internal Class(int i) - { - - } -} - -internal interface IClassToo {} - -internal class ClassToo : IClassToo -{ - internal ClassToo() - { - - } - - internal ClassToo(int i) - { - - } -} - -internal interface IClass {} - -internal class Class : IClass -{ - internal Class() - { - } - - internal Class(int i) - { - - } -} - -internal static class StaticParent -{ - internal class Class : IClass - { - internal Class() - { - } - - internal Class(int i) - { - - } - } - - internal class ClassToo : IClassToo - { - internal ClassToo() - { - - } - - internal ClassToo(int i) - { - - } - } - - internal class Class : IClass - { - internal Class() - { - } - - internal Class(int i) - { - - } - } -} - -internal class Parent -{ - internal Parent() {} - internal class Class : IClass - { - internal Class() - { - } - - internal Class(int i) - { - - } - } - - internal class ClassToo : IClassToo - { - internal ClassToo() - { - - } - - internal ClassToo(int i) - { - - } - } - - internal class Class : IClass - { - internal Class() - { - } - - internal Class(int i) - { - - } - } -} \ No newline at end of file diff --git a/Test/Test.csproj b/Test/Test.csproj index e2dbd1d2..78318ddf 100644 --- a/Test/Test.csproj +++ b/Test/Test.csproj @@ -15,7 +15,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + runtime; build; native; contentfiles; analyzers; buildtransitive From 703ef1b620a534c8287e28be2041bec40ae06a89 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sun, 25 Sep 2022 12:31:55 +0200 Subject: [PATCH 156/162] Better unofficial support for .Net Core 3.1 --- Main/CodeBuilding/ContainerCodeBuilder.cs | 6 ++--- Main/CodeBuilding/RangeCodeBaseBuilder.cs | 10 ++++---- Sample/Container.cs | 23 +++++++------------ Test/Func/AsyncWrapped/MultipleTaskAtStart.cs | 5 +--- .../AsyncWrapped/MultipleValueTaskAtStart.cs | 5 +--- Test/Func/AsyncWrapped/SingleTask.cs | 5 +--- Test/Func/AsyncWrapped/SingleValueTask.cs | 5 +--- Test/Generics/Configuration/AsyncTransient.cs | 5 +--- .../AsyncTransientWithJustTransient.cs | 5 +--- Test/Initializer/AsyncValueTask.cs | 4 ++-- Test/Lazy/AsyncWrapped/MultipleTaskAtStart.cs | 5 +--- .../AsyncWrapped/MultipleValueTaskAtStart.cs | 5 +--- Test/Lazy/AsyncWrapped/SingleTask.cs | 5 +--- Test/Lazy/AsyncWrapped/SingleValueTask.cs | 5 +--- .../FactoryField/InContainercsValueTask.cs | 2 +- .../FactoryMethod/InContainercsValueTask.cs | 2 +- .../WithParameterInContainercs.cs | 1 + .../FactoryProperty/InContainerValueTask.cs | 2 +- TestInternalsVisibleToChild/AssemblyInfo.cs | 7 ------ .../AssemblyInfo.cs | 8 ------- 20 files changed, 32 insertions(+), 83 deletions(-) diff --git a/Main/CodeBuilding/ContainerCodeBuilder.cs b/Main/CodeBuilding/ContainerCodeBuilder.cs index 4ead6f12..a91db141 100644 --- a/Main/CodeBuilding/ContainerCodeBuilder.cs +++ b/Main/CodeBuilding/ContainerCodeBuilder.cs @@ -120,16 +120,16 @@ public override StringBuilder Build(StringBuilder stringBuilder) .AppendLine($"private class {_containerResolution.NopAsyncDisposable.ClassName} : {asyncDisposableTypeFullName}") .AppendLine($"{{") .AppendLine($"internal static {asyncDisposableTypeFullName} {_containerResolution.NopAsyncDisposable.InstanceReference} {{ get; }} = new {_containerResolution.NopAsyncDisposable.ClassName}();") - .AppendLine($"public {valueTaskFullName} DisposeAsync() => {valueTaskFullName}.CompletedTask;") + .AppendLine($"public {valueTaskFullName} DisposeAsync() => new {valueTaskFullName}();") .AppendLine($"}}") .AppendLine($"private class {_containerResolution.SyncToAsyncDisposable.ClassName} : {asyncDisposableTypeFullName}") .AppendLine($"{{") .AppendLine($"private readonly {disposableTypeFullName} {_containerResolution.SyncToAsyncDisposable.DisposableFieldReference};") .AppendLine($"internal {_containerResolution.SyncToAsyncDisposable.ClassName}({disposableTypeFullName} {_containerResolution.SyncToAsyncDisposable.DisposableParameterReference}) => {_containerResolution.SyncToAsyncDisposable.DisposableFieldReference} = {_containerResolution.SyncToAsyncDisposable.DisposableParameterReference};") - .AppendLine($"public {valueTaskFullName} DisposeAsync()") + .AppendLine($"public async {valueTaskFullName} DisposeAsync()") .AppendLine($"{{") + .AppendLine($"await {WellKnownTypes.Task.FullName()}.Yield();") .AppendLine($"{_containerResolution.SyncToAsyncDisposable.DisposableFieldReference}.Dispose();") - .AppendLine($"return {valueTaskFullName}.CompletedTask;") .AppendLine($"}}") .AppendLine($"}}"); diff --git a/Main/CodeBuilding/RangeCodeBaseBuilder.cs b/Main/CodeBuilding/RangeCodeBaseBuilder.cs index 0162db32..64334b9a 100644 --- a/Main/CodeBuilding/RangeCodeBaseBuilder.cs +++ b/Main/CodeBuilding/RangeCodeBaseBuilder.cs @@ -69,10 +69,10 @@ private StringBuilder GenerateDisposalFunction( .AppendLine("{") .AppendLine($"var {disposalHandling.DisposedLocalReference} = global::System.Threading.Interlocked.Exchange(ref this.{disposalHandling.DisposedFieldReference}, 1);") .AppendLine("}") - .AppendLine($"public {WellKnownTypes.ValueTask.FullName()} DisposeAsync()") + .AppendLine($"public async {WellKnownTypes.ValueTask.FullName()} DisposeAsync()") .AppendLine("{") + .AppendLine($"await {WellKnownTypes.Task.FullName()}.Yield();") .AppendLine($"Dispose();") - .AppendLine($"return new {WellKnownTypes.ValueTask.FullName()}({WellKnownTypes.Task.FullName()}.CompletedTask);") .AppendLine("}"); } @@ -161,10 +161,10 @@ private StringBuilder GenerateDisposalFunction( if (_containerResolution.DisposalType.HasFlag(DisposalType.Sync) && !_containerResolution.DisposalType.HasFlag(DisposalType.Async)) stringBuilder = stringBuilder - .AppendLine($"public {WellKnownTypes.ValueTask.FullName()} DisposeAsync()") + .AppendLine($"public async {WellKnownTypes.ValueTask.FullName()} DisposeAsync()") .AppendLine($"{{") + .AppendLine($"await {WellKnownTypes.Task.FullName()}.Yield();") .AppendLine($"Dispose();") - .AppendLine($"return new {WellKnownTypes.ValueTask.FullName()}({WellKnownTypes.Task.FullName()}.CompletedTask);") .AppendLine($"}}"); return stringBuilder; @@ -332,7 +332,7 @@ private StringBuilder GenerateResolutions( break; case ValueTaskFromSyncResolution(var wrappedResolvable, var valueTaskReference, var valueTaskFullName): stringBuilder = GenerateResolutions(stringBuilder, wrappedResolvable); - stringBuilder = stringBuilder.AppendLine($"{valueTaskFullName} {valueTaskReference} = {WellKnownTypes.ValueTask.FullName()}.FromResult({wrappedResolvable.Reference});"); + stringBuilder = stringBuilder.AppendLine($"{valueTaskFullName} {valueTaskReference} = new {valueTaskFullName}({wrappedResolvable.Reference});"); break; case TransientScopeRootResolution(var transientScopeReference, var transientScopeTypeFullName, var containerInstanceScopeReference, var createFunctionCall): stringBuilder = stringBuilder diff --git a/Sample/Container.cs b/Sample/Container.cs index e3d46e46..091e4788 100644 --- a/Sample/Container.cs +++ b/Sample/Container.cs @@ -1,20 +1,13 @@ -using MrMeeseeks.DIE.Configuration.Attributes; -using MrMeeseeks.DIE.Sample; +using System.IO; +using MrMeeseeks.DIE.Configuration.Attributes; -namespace Asdf; +namespace MrMeeseeks.DIE.Test.UserDefinedElements.FactoryMethod.WithParameterInContainer; -internal class Dependency : IScopeRoot -{ - internal Dependency(InnerDependency inner) {} -} - -internal class InnerDependency : IScopeInstance -{ - internal InnerDependency(Dependency inner) {} -} - -[CreateFunction(typeof(Dependency), "Create")] +[FilterAllImplementationsAggregation] +[ImplementationAggregation(typeof(FileInfo))] +[CreateFunction(typeof(FileInfo), "Create")] internal sealed partial class Container { - + private string DIE_Factory_Path => "C:\\Yeah.txt"; + private FileInfo DIE_Factory(string path) => new (path); } \ No newline at end of file diff --git a/Test/Func/AsyncWrapped/MultipleTaskAtStart.cs b/Test/Func/AsyncWrapped/MultipleTaskAtStart.cs index 13087ee2..4fb90ee0 100644 --- a/Test/Func/AsyncWrapped/MultipleTaskAtStart.cs +++ b/Test/Func/AsyncWrapped/MultipleTaskAtStart.cs @@ -7,10 +7,7 @@ namespace MrMeeseeks.DIE.Test.Func.AsyncWrapped.MultipleTaskAtStart; internal class Dependency : IValueTaskInitializer { - public ValueTask InitializeAsync() - { - return ValueTask.CompletedTask; - } + public ValueTask InitializeAsync() => default; } internal class OuterDependency diff --git a/Test/Func/AsyncWrapped/MultipleValueTaskAtStart.cs b/Test/Func/AsyncWrapped/MultipleValueTaskAtStart.cs index 2fdbd8da..3bf304fc 100644 --- a/Test/Func/AsyncWrapped/MultipleValueTaskAtStart.cs +++ b/Test/Func/AsyncWrapped/MultipleValueTaskAtStart.cs @@ -7,10 +7,7 @@ namespace MrMeeseeks.DIE.Test.Func.AsyncWrapped.MultipleValueTaskAtStart; internal class Dependency : IValueTaskInitializer { - public ValueTask InitializeAsync() - { - return ValueTask.CompletedTask; - } + public ValueTask InitializeAsync() => default; } internal class OuterDependency diff --git a/Test/Func/AsyncWrapped/SingleTask.cs b/Test/Func/AsyncWrapped/SingleTask.cs index 861b40e5..24660eda 100644 --- a/Test/Func/AsyncWrapped/SingleTask.cs +++ b/Test/Func/AsyncWrapped/SingleTask.cs @@ -7,10 +7,7 @@ namespace MrMeeseeks.DIE.Test.Func.AsyncWrapped.SingleTask; internal class Dependency : IValueTaskInitializer { - public ValueTask InitializeAsync() - { - return ValueTask.CompletedTask; - } + public ValueTask InitializeAsync() => default; } internal class OuterDependency diff --git a/Test/Func/AsyncWrapped/SingleValueTask.cs b/Test/Func/AsyncWrapped/SingleValueTask.cs index cdf0e1ba..b4a94e7b 100644 --- a/Test/Func/AsyncWrapped/SingleValueTask.cs +++ b/Test/Func/AsyncWrapped/SingleValueTask.cs @@ -7,10 +7,7 @@ namespace MrMeeseeks.DIE.Test.Func.AsyncWrapped.SingleValueTask; internal class Dependency : IValueTaskInitializer { - public ValueTask InitializeAsync() - { - return ValueTask.CompletedTask; - } + public ValueTask InitializeAsync() => default; } internal class OuterDependency diff --git a/Test/Generics/Configuration/AsyncTransient.cs b/Test/Generics/Configuration/AsyncTransient.cs index 5c2a1331..c1a0131a 100644 --- a/Test/Generics/Configuration/AsyncTransient.cs +++ b/Test/Generics/Configuration/AsyncTransient.cs @@ -7,10 +7,7 @@ namespace MrMeeseeks.DIE.Test.Generics.Configuration.AsyncTransient; internal class Managed : IAsyncDisposable { - public ValueTask DisposeAsync() - { - return ValueTask.CompletedTask; - } + public ValueTask DisposeAsync() => default; } internal class Class : IAsyncTransient, IAsyncDisposable diff --git a/Test/Generics/Configuration/AsyncTransientWithJustTransient.cs b/Test/Generics/Configuration/AsyncTransientWithJustTransient.cs index 2241ced0..5d38bdac 100644 --- a/Test/Generics/Configuration/AsyncTransientWithJustTransient.cs +++ b/Test/Generics/Configuration/AsyncTransientWithJustTransient.cs @@ -7,10 +7,7 @@ namespace MrMeeseeks.DIE.Test.Generics.Configuration.AsyncTransientWithJustTrans internal class Managed : IAsyncDisposable { - public ValueTask DisposeAsync() - { - return ValueTask.CompletedTask; - } + public ValueTask DisposeAsync() => default; } internal class Class : ITransient, IAsyncDisposable diff --git a/Test/Initializer/AsyncValueTask.cs b/Test/Initializer/AsyncValueTask.cs index adfb3d47..dc7052d2 100644 --- a/Test/Initializer/AsyncValueTask.cs +++ b/Test/Initializer/AsyncValueTask.cs @@ -8,10 +8,10 @@ internal class Dependency : IValueTaskInitializer { public bool IsInitialized { get; private set; } - ValueTask IValueTaskInitializer.InitializeAsync() + async ValueTask IValueTaskInitializer.InitializeAsync() { + await Task.Yield(); IsInitialized = true; - return ValueTask.CompletedTask; } } diff --git a/Test/Lazy/AsyncWrapped/MultipleTaskAtStart.cs b/Test/Lazy/AsyncWrapped/MultipleTaskAtStart.cs index 95f6fe02..b0916675 100644 --- a/Test/Lazy/AsyncWrapped/MultipleTaskAtStart.cs +++ b/Test/Lazy/AsyncWrapped/MultipleTaskAtStart.cs @@ -7,10 +7,7 @@ namespace MrMeeseeks.DIE.Test.Lazy.AsyncWrapped.MultipleTaskAtStart; internal class Dependency : IValueTaskInitializer { - public ValueTask InitializeAsync() - { - return ValueTask.CompletedTask; - } + public ValueTask InitializeAsync() => default; } internal class OuterDependency diff --git a/Test/Lazy/AsyncWrapped/MultipleValueTaskAtStart.cs b/Test/Lazy/AsyncWrapped/MultipleValueTaskAtStart.cs index 8096ba38..7d3278b3 100644 --- a/Test/Lazy/AsyncWrapped/MultipleValueTaskAtStart.cs +++ b/Test/Lazy/AsyncWrapped/MultipleValueTaskAtStart.cs @@ -7,10 +7,7 @@ namespace MrMeeseeks.DIE.Test.Lazy.AsyncWrapped.MultipleValueTaskAtStart; internal class Dependency : IValueTaskInitializer { - public ValueTask InitializeAsync() - { - return ValueTask.CompletedTask; - } + public ValueTask InitializeAsync() => default; } internal class OuterDependency diff --git a/Test/Lazy/AsyncWrapped/SingleTask.cs b/Test/Lazy/AsyncWrapped/SingleTask.cs index cf71b505..6d247c8c 100644 --- a/Test/Lazy/AsyncWrapped/SingleTask.cs +++ b/Test/Lazy/AsyncWrapped/SingleTask.cs @@ -7,10 +7,7 @@ namespace MrMeeseeks.DIE.Test.Lazy.AsyncWrapped.SingleTask; internal class Dependency : IValueTaskInitializer { - public ValueTask InitializeAsync() - { - return ValueTask.CompletedTask; - } + public ValueTask InitializeAsync() => default; } internal class OuterDependency diff --git a/Test/Lazy/AsyncWrapped/SingleValueTask.cs b/Test/Lazy/AsyncWrapped/SingleValueTask.cs index 175ed7fa..168862de 100644 --- a/Test/Lazy/AsyncWrapped/SingleValueTask.cs +++ b/Test/Lazy/AsyncWrapped/SingleValueTask.cs @@ -7,10 +7,7 @@ namespace MrMeeseeks.DIE.Test.Lazy.AsyncWrapped.SingleValueTask; internal class Dependency : IValueTaskInitializer { - public ValueTask InitializeAsync() - { - return ValueTask.CompletedTask; - } + public ValueTask InitializeAsync() => default; } internal class OuterDependency diff --git a/Test/UserDefinedElements/FactoryField/InContainercsValueTask.cs b/Test/UserDefinedElements/FactoryField/InContainercsValueTask.cs index 4172842c..780fd273 100644 --- a/Test/UserDefinedElements/FactoryField/InContainercsValueTask.cs +++ b/Test/UserDefinedElements/FactoryField/InContainercsValueTask.cs @@ -14,7 +14,7 @@ internal class Wrapper [CreateFunction(typeof(Wrapper), "Create")] internal sealed partial class Container { - private readonly ValueTask DIE_Factory_Yeah = ValueTask.FromResult("Yeah"); + private readonly ValueTask DIE_Factory_Yeah = new ("Yeah"); } public class Tests diff --git a/Test/UserDefinedElements/FactoryMethod/InContainercsValueTask.cs b/Test/UserDefinedElements/FactoryMethod/InContainercsValueTask.cs index 16af4cec..ba6d00c9 100644 --- a/Test/UserDefinedElements/FactoryMethod/InContainercsValueTask.cs +++ b/Test/UserDefinedElements/FactoryMethod/InContainercsValueTask.cs @@ -14,7 +14,7 @@ internal class Wrapper [CreateFunction(typeof(Wrapper), "Create")] internal sealed partial class Container { - private ValueTask DIE_Factory_Yeah() => ValueTask.FromResult("Yeah"); + private ValueTask DIE_Factory_Yeah() => new ("Yeah"); } public class Tests diff --git a/Test/UserDefinedElements/FactoryMethod/WithParameterInContainercs.cs b/Test/UserDefinedElements/FactoryMethod/WithParameterInContainercs.cs index 9f5cb02d..3277b7f8 100644 --- a/Test/UserDefinedElements/FactoryMethod/WithParameterInContainercs.cs +++ b/Test/UserDefinedElements/FactoryMethod/WithParameterInContainercs.cs @@ -5,6 +5,7 @@ namespace MrMeeseeks.DIE.Test.UserDefinedElements.FactoryMethod.WithParameterInContainer; +[FilterAllImplementationsAggregation] [ImplementationAggregation(typeof(FileInfo))] [CreateFunction(typeof(FileInfo), "Create")] internal sealed partial class Container diff --git a/Test/UserDefinedElements/FactoryProperty/InContainerValueTask.cs b/Test/UserDefinedElements/FactoryProperty/InContainerValueTask.cs index 6b65aca7..a1f25f52 100644 --- a/Test/UserDefinedElements/FactoryProperty/InContainerValueTask.cs +++ b/Test/UserDefinedElements/FactoryProperty/InContainerValueTask.cs @@ -14,7 +14,7 @@ internal class Wrapper [CreateFunction(typeof(Wrapper), "Create")] internal sealed partial class Container { - private ValueTask DIE_Factory_Yeah => ValueTask.FromResult("Yeah"); + private ValueTask DIE_Factory_Yeah => new ("Yeah"); } public class Tests diff --git a/TestInternalsVisibleToChild/AssemblyInfo.cs b/TestInternalsVisibleToChild/AssemblyInfo.cs index 72a83f9e..d93fdd89 100644 --- a/TestInternalsVisibleToChild/AssemblyInfo.cs +++ b/TestInternalsVisibleToChild/AssemblyInfo.cs @@ -1,10 +1,3 @@ -global using Microsoft.CodeAnalysis; -global using System; -global using System.Collections.Generic; -global using System.Collections.Immutable; -global using System.Collections.ObjectModel; -global using System.Linq; -global using System.Text; using System.Runtime.CompilerServices; [assembly:InternalsVisibleTo("MrMeeseeks.DIE.Test")] diff --git a/TestNotInternalsVisibleToChild/AssemblyInfo.cs b/TestNotInternalsVisibleToChild/AssemblyInfo.cs index 0b82f08a..8eb403a3 100644 --- a/TestNotInternalsVisibleToChild/AssemblyInfo.cs +++ b/TestNotInternalsVisibleToChild/AssemblyInfo.cs @@ -1,11 +1,3 @@ -global using Microsoft.CodeAnalysis; -global using System; -global using System.Collections.Generic; -global using System.Collections.Immutable; -global using System.Collections.ObjectModel; -global using System.Linq; -global using System.Text; - namespace MrMeeseeks.DIE.TestNotInternalsVisibleToChild; public class AssemblyInfo From 83804d4b86ebb3fc31006e1af1c48718aaa1fa61 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sun, 25 Sep 2022 13:26:15 +0200 Subject: [PATCH 157/162] Removing unused nuget packages --- Main/Main.csproj | 3 --- 1 file changed, 3 deletions(-) diff --git a/Main/Main.csproj b/Main/Main.csproj index 15916b56..eb294ab5 100644 --- a/Main/Main.csproj +++ b/Main/Main.csproj @@ -27,10 +27,7 @@ - - - all runtime; build; native; contentfiles; analyzers; buildtransitive From 3001854014539d2fb0ed3e0b6e6ea4b5f0557b73 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Tue, 27 Sep 2022 22:42:34 +0200 Subject: [PATCH 158/162] Fixing decorator sequence bug --- Main/Configuration/CheckTypeProperties.cs | 2 +- Main/SourceGenerator.cs | 5 ++ Sample/Container.cs | 37 ++++++++++-- Test/Decorator/Multi.cs | 4 +- Test/Decorator/MultiOnConcrete.cs | 57 +++++++++++++++++++ ...nConcreteWithContainerInstanceDecorated.cs | 57 +++++++++++++++++++ .../MultiWithContainerInstanceDecorated.cs | 57 +++++++++++++++++++ 7 files changed, 210 insertions(+), 9 deletions(-) create mode 100644 Test/Decorator/MultiOnConcrete.cs create mode 100644 Test/Decorator/MultiOnConcreteWithContainerInstanceDecorated.cs create mode 100644 Test/Decorator/MultiWithContainerInstanceDecorated.cs diff --git a/Main/Configuration/CheckTypeProperties.cs b/Main/Configuration/CheckTypeProperties.cs index b2e6b594..0b4ee62f 100644 --- a/Main/Configuration/CheckTypeProperties.cs +++ b/Main/Configuration/CheckTypeProperties.cs @@ -149,7 +149,7 @@ public IReadOnlyList GetSequenceFor(INamedTypeSymbol interface sequence = implementationSequence; found = true; } - else if (sequenceMap.TryGetValue(implementationType.UnboundIfGeneric(), out var interfaceSequence)) + else if (sequenceMap.TryGetValue(interfaceType.UnboundIfGeneric(), out var interfaceSequence)) { sequence = interfaceSequence; found = true; diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index 20393c61..5660c9f7 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -5,6 +5,7 @@ using MrMeeseeks.DIE.Validation.Attributes; using MrMeeseeks.DIE.Validation.Range; using MrMeeseeks.DIE.Validation.Range.UserDefined; +using System.Diagnostics; namespace MrMeeseeks.DIE; @@ -16,6 +17,10 @@ public void Initialize(GeneratorInitializationContext context) new InitializeImpl(context, SyntaxReceiverFactory).Initialize(); ISyntaxReceiver SyntaxReceiverFactory() => new SyntaxReceiver(); + //if (!Debugger.IsAttached) + { + //Debugger.Launch(); + } } public void Execute(GeneratorExecutionContext context) diff --git a/Sample/Container.cs b/Sample/Container.cs index 091e4788..6762e080 100644 --- a/Sample/Container.cs +++ b/Sample/Container.cs @@ -1,13 +1,38 @@ using System.IO; using MrMeeseeks.DIE.Configuration.Attributes; +using MrMeeseeks.DIE.Sample; -namespace MrMeeseeks.DIE.Test.UserDefinedElements.FactoryMethod.WithParameterInContainer; +namespace MrMeeseeks.DIE.Test.Decorator.Multi; -[FilterAllImplementationsAggregation] -[ImplementationAggregation(typeof(FileInfo))] -[CreateFunction(typeof(FileInfo), "Create")] +internal interface IInterface +{ + IInterface Decorated { get; } +} + +internal class Dependency : IInterface +{ + public IInterface Decorated => this; +} + +internal class DecoratorA : IInterface, IDecorator +{ + public DecoratorA(IInterface decorated) => + Decorated = decorated; + + public IInterface Decorated { get; } +} + +internal class DecoratorB : IInterface, IDecorator +{ + public DecoratorB(IInterface decorated) => + Decorated = decorated; + + public IInterface Decorated { get; } +} + +[CreateFunction(typeof(IInterface), "Create")] +[DecoratorSequenceChoice(typeof(IInterface), typeof(IInterface), typeof(DecoratorA), typeof(DecoratorB))] internal sealed partial class Container { - private string DIE_Factory_Path => "C:\\Yeah.txt"; - private FileInfo DIE_Factory(string path) => new (path); + } \ No newline at end of file diff --git a/Test/Decorator/Multi.cs b/Test/Decorator/Multi.cs index ea365fe5..8ccf5219 100644 --- a/Test/Decorator/Multi.cs +++ b/Test/Decorator/Multi.cs @@ -40,9 +40,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var decorated = container.Create(); var decoratedB = decorated; var decoratedA = decorated.Decorated; diff --git a/Test/Decorator/MultiOnConcrete.cs b/Test/Decorator/MultiOnConcrete.cs new file mode 100644 index 00000000..963f4f2e --- /dev/null +++ b/Test/Decorator/MultiOnConcrete.cs @@ -0,0 +1,57 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Decorator.MultiOnConcrete; + +internal interface IInterface +{ + IInterface Decorated { get; } +} + +internal class Dependency : IInterface +{ + public IInterface Decorated => this; +} + +internal class DecoratorA : IInterface, IDecorator +{ + public DecoratorA(IInterface decorated) => + Decorated = decorated; + + public IInterface Decorated { get; } +} + +internal class DecoratorB : IInterface, IDecorator +{ + public DecoratorB(IInterface decorated) => + Decorated = decorated; + + public IInterface Decorated { get; } +} + +[CreateFunction(typeof(IInterface), "Create")] +[DecoratorSequenceChoice(typeof(IInterface), typeof(Dependency), typeof(DecoratorA), typeof(DecoratorB))] +internal sealed partial class Container +{ + +} + +public class Tests +{ + [Fact] + public void Test() + { + using var container = new Container(); + var decorated = container.Create(); + var decoratedB = decorated; + var decoratedA = decorated.Decorated; + var decoratedBasis = decoratedA.Decorated; + Assert.NotEqual(decoratedBasis, decoratedA); + Assert.NotEqual(decoratedBasis, decoratedB); + Assert.NotEqual(decoratedA, decoratedB); + Assert.IsType(decoratedBasis); + Assert.IsType(decoratedA); + Assert.IsType(decoratedB); + } +} \ No newline at end of file diff --git a/Test/Decorator/MultiOnConcreteWithContainerInstanceDecorated.cs b/Test/Decorator/MultiOnConcreteWithContainerInstanceDecorated.cs new file mode 100644 index 00000000..1890bca8 --- /dev/null +++ b/Test/Decorator/MultiOnConcreteWithContainerInstanceDecorated.cs @@ -0,0 +1,57 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Decorator.MultiOnConcreteWithContainerInstanceDecorated; + +internal interface IInterface +{ + IInterface Decorated { get; } +} + +internal class Dependency : IInterface, IContainerInstance +{ + public IInterface Decorated => this; +} + +internal class DecoratorA : IInterface, IDecorator +{ + public DecoratorA(IInterface decorated) => + Decorated = decorated; + + public IInterface Decorated { get; } +} + +internal class DecoratorB : IInterface, IDecorator +{ + public DecoratorB(IInterface decorated) => + Decorated = decorated; + + public IInterface Decorated { get; } +} + +[CreateFunction(typeof(IInterface), "Create")] +[DecoratorSequenceChoice(typeof(IInterface), typeof(Dependency), typeof(DecoratorA), typeof(DecoratorB))] +internal sealed partial class Container +{ + +} + +public class Tests +{ + [Fact] + public void Test() + { + using var container = new Container(); + var decorated = container.Create(); + var decoratedB = decorated; + var decoratedA = decorated.Decorated; + var decoratedBasis = decoratedA.Decorated; + Assert.NotEqual(decoratedBasis, decoratedA); + Assert.NotEqual(decoratedBasis, decoratedB); + Assert.NotEqual(decoratedA, decoratedB); + Assert.IsType(decoratedBasis); + Assert.IsType(decoratedA); + Assert.IsType(decoratedB); + } +} \ No newline at end of file diff --git a/Test/Decorator/MultiWithContainerInstanceDecorated.cs b/Test/Decorator/MultiWithContainerInstanceDecorated.cs new file mode 100644 index 00000000..5fc273ef --- /dev/null +++ b/Test/Decorator/MultiWithContainerInstanceDecorated.cs @@ -0,0 +1,57 @@ +using System.Threading.Tasks; +using MrMeeseeks.DIE.Configuration.Attributes; +using Xunit; + +namespace MrMeeseeks.DIE.Test.Decorator.MultiWithContainerInstanceDecorated; + +internal interface IInterface +{ + IInterface Decorated { get; } +} + +internal class Dependency : IInterface, IContainerInstance +{ + public IInterface Decorated => this; +} + +internal class DecoratorA : IInterface, IDecorator +{ + public DecoratorA(IInterface decorated) => + Decorated = decorated; + + public IInterface Decorated { get; } +} + +internal class DecoratorB : IInterface, IDecorator +{ + public DecoratorB(IInterface decorated) => + Decorated = decorated; + + public IInterface Decorated { get; } +} + +[CreateFunction(typeof(IInterface), "Create")] +[DecoratorSequenceChoice(typeof(IInterface), typeof(IInterface), typeof(DecoratorA), typeof(DecoratorB))] +internal sealed partial class Container +{ + +} + +public class Tests +{ + [Fact] + public void Test() + { + using var container = new Container(); + var decorated = container.Create(); + var decoratedB = decorated; + var decoratedA = decorated.Decorated; + var decoratedBasis = decoratedA.Decorated; + Assert.NotEqual(decoratedBasis, decoratedA); + Assert.NotEqual(decoratedBasis, decoratedB); + Assert.NotEqual(decoratedA, decoratedB); + Assert.IsType(decoratedBasis); + Assert.IsType(decoratedA); + Assert.IsType(decoratedB); + } +} \ No newline at end of file From 9fe18a01e9bb00c2a8a823a00a7de764db0164fb Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Thu, 29 Sep 2022 22:16:08 +0200 Subject: [PATCH 159/162] Removing ValueTask return type on tests where ever possible --- Main/SourceGenerator.cs | 1 - Sample/Container.cs | 3 +-- Test/Abstraction/AbstractClass/Collection.cs | 5 ++--- .../AbstractClass/CollectionWithoutChoice.cs | 5 ++--- .../AbstractClass/SingleInCollection.cs | 7 +++---- Test/Abstraction/AbstractClass/Vanilla.cs | 7 +++---- .../AbstractClass/VanillaWithoutChoice.cs | 7 +++---- .../AbstractClass/WithSingleInCollection.cs | 7 +++---- Test/Abstraction/ArrayType.cs | 7 +++---- Test/Abstraction/Interface/Collection.cs | 5 ++--- .../Interface/CollectionWithoutChoice.cs | 5 ++--- .../Interface/SingleInCollection.cs | 7 +++---- Test/Abstraction/Interface/Vanilla.cs | 7 +++---- .../Interface/VanillaWithoutChoice.cs | 7 +++---- .../Interface/WithSingleInCollection.cs | 7 +++---- ...UngenericImplementationGenericInterface.cs | 7 +++---- Test/Collection/Composite/Array.cs | 7 +++---- Test/Collection/Composite/IEnumerable.cs | 5 ++--- .../Composite/IReadOnlyCollection.cs | 5 ++--- Test/Collection/Composite/IReadOnlyList.cs | 5 ++--- Test/Collection/Injection/Array.cs | 7 +++---- Test/Collection/Injection/IEnumerable.cs | 5 ++--- .../Injection/IReadOnlyCollection.cs | 5 ++--- Test/Collection/Injection/IReadOnlyList.cs | 5 ++--- Test/Composite/Container.cs | 11 ++++------ Test/Composite/Decorated.cs | 9 ++++---- Test/Composite/MixedScoping.cs | 9 ++++---- Test/Composite/Normal.cs | 9 ++++---- Test/Composite/ScopeRoot.cs | 9 ++++---- Test/ConstructorChoice/Parameterless.cs | 5 ++--- Test/ConstructorChoice/WithParameter.cs | 5 ++--- .../NoCycle/DirectRecursionContainerFunc.cs | 5 ++--- .../NoCycle/DirectRecursionContainerLazy.cs | 5 ++--- .../NoCycle/DirectRecursionScopeFunc.cs | 5 ++--- .../NoCycle/DirectRecursionScopeLazy.cs | 5 ++--- .../DirectRecursionTransientScopeFunc.cs | 5 ++--- .../DirectRecursionTransientScopeLazy.cs | 5 ++--- .../NoCycle/NoCycleInParallel.cs | 5 ++--- Test/Decorator/ContainerInstance.cs | 5 ++--- Test/Decorator/List.cs | 5 ++--- Test/Decorator/Multi.cs | 1 - Test/Decorator/MultiOnConcrete.cs | 1 - ...nConcreteWithContainerInstanceDecorated.cs | 1 - .../MultiWithContainerInstanceDecorated.cs | 1 - Test/Decorator/Normal.cs | 5 ++--- ...OneImplementationTwoDecoratedInterfaces.cs | 17 +++++++-------- .../ScopeDecoratorForContainerDependency.cs | 14 +++---------- ...opeDecoratorForTransientScopeDependency.cs | 14 +++---------- Test/Decorator/SequenceEdgeCase.cs | 7 +++---- Test/Func/AsyncWrapped/MultipleTaskAtStart.cs | 4 ++-- .../AsyncWrapped/MultipleValueTaskAtStart.cs | 4 ++-- Test/Func/AsyncWrapped/SingleTask.cs | 4 ++-- Test/Func/AsyncWrapped/SingleValueTask.cs | 4 ++-- Test/Func/Double.cs | 5 ++--- Test/Func/Override.cs | 5 ++--- Test/Func/OverrideCombination.cs | 5 ++--- Test/Func/OverrideExistingOverride.cs | 5 ++--- .../OverrideMultipleParameterOfSameType.cs | 5 ++--- Test/Func/OverrideMultipleTypes.cs | 5 ++--- Test/Func/OverrideScoped.cs | 5 ++--- Test/Func/ReductionCase.cs | 5 ++--- Test/Func/ReductionCaseTransientScope.cs | 5 ++--- Test/Func/Vanilla.cs | 5 ++--- Test/Func/WithArrayParameter.cs | 5 ++--- Test/Generics/Choice/Double.cs | 7 +++---- Test/Generics/Choice/DoubleBothChosen.cs | 7 +++---- ...ubleBothChosenWithSingleOtherSubstitute.cs | 7 +++---- .../Choice/DoubleWithSingleOtherSubstitute.cs | 7 +++---- Test/Generics/Choice/Single.cs | 7 +++---- .../Choice/SingleWithSingleOtherSubstitute.cs | 7 +++---- .../Double.cs | 7 +++---- .../Single.cs | 7 +++---- Test/Generics/Configuration/Composite.cs | 5 ++--- .../Configuration/ConstructorChoice.cs | 5 ++--- .../Configuration/ContainerInstance.cs | 5 ++--- ...erInstanceWithDifferentGenericParameter.cs | 5 ++--- Test/Generics/Configuration/Decorator.cs | 5 ++--- .../InitializerImplementationSync.cs | 5 ++--- .../Configuration/InitializerInterfaceSync.cs | 5 ++--- .../InterfaceGenericComposite.cs | 5 ++--- .../InterfaceGenericDecorator.cs | 5 ++--- Test/Generics/Configuration/ScopeInstance.cs | 5 ++--- ...peInstanceWithDifferentGenericParameter.cs | 5 ++--- Test/Generics/Configuration/ScopeRoot.cs | 5 ++--- Test/Generics/Configuration/SyncTransient.cs | 5 ++--- .../SyncTransientWithJustTransient.cs | 5 ++--- .../Configuration/TransientScopeInstance.cs | 5 ++--- ...peInstanceWithDifferentGenericParameter.cs | 5 ++--- .../Configuration/TransientScopeRoot.cs | 5 ++--- Test/Generics/Implementation/Double.cs | 7 +++---- Test/Generics/Implementation/Single.cs | 7 +++---- Test/Generics/Interface/Double.cs | 7 +++---- Test/Generics/Interface/DoubleAndOneFixed.cs | 7 +++---- Test/Generics/Interface/DoubleAndSetToSame.cs | 7 +++---- Test/Generics/Interface/DoubleSwitched.cs | 7 +++---- Test/Generics/Interface/Single.cs | 7 +++---- ...eAndBaseImplementationDoubleButOneFixed.cs | 7 +++---- Test/Generics/SubstituteCollection/Double.cs | 5 ++--- .../DoubleBothSubstituted.cs | 5 ++--- .../DoubleBothSubstitutedWithChoice.cs | 5 ++--- .../SubstituteCollection/DoubleWithChoice.cs | 5 ++--- Test/Generics/SubstituteCollection/Single.cs | 5 ++--- .../SubstituteCollection/SingleWithChoice.cs | 5 ++--- .../SubstituteCollection/TripleInsanity.cs | 5 ++--- .../AssemblyImplementationsAggregation.cs | 5 ++--- .../Aggregation/ExternalType.cs | 5 ++--- .../Aggregation/FilterAllImplementations.cs | 5 ++--- .../Aggregation/InternalsVisibleTo.cs | 5 ++--- Test/Implementation/ArrayType.cs | 7 +++---- Test/Implementation/Choice/Collection.cs | 5 ++--- .../Choice/CollectionWithoutChoice.cs | 5 ++--- .../Choice/SingleInCollection.cs | 7 +++---- Test/Implementation/Choice/Vanilla.cs | 7 +++---- .../Choice/VanillaWithoutChoice.cs | 7 +++---- .../Choice/WithSingleInCollection.cs | 7 +++---- Test/InitProperty/Vanilla.cs | 5 ++--- Test/Initializer/Sync.cs | 5 ++--- Test/Initializer/WithParameters.cs | 5 ++--- Test/Lazy/AsyncWrapped/MultipleTaskAtStart.cs | 4 ++-- .../AsyncWrapped/MultipleValueTaskAtStart.cs | 4 ++-- Test/Lazy/AsyncWrapped/SingleTask.cs | 4 ++-- Test/Lazy/AsyncWrapped/SingleValueTask.cs | 4 ++-- Test/Lazy/Override.cs | 5 ++--- Test/Lazy/Vanilla.cs | 5 ++--- .../NonOptional/MultipleImplementations.cs | 5 ++--- .../NonOptional/NoImplementation.cs | 5 ++--- .../Optional/MultipleImplementations.cs | 5 ++--- Test/Nullability/Optional/NoImplementation.cs | 5 ++--- Test/Record/CustomProperty.cs | 5 ++--- Test/Record/PrimaryConstr.cs | 5 ++--- Test/Record/Vanilla.cs | 5 ++--- Test/Scoping/FuncContainerInstance.cs | 5 ++--- Test/Scoping/InScope.cs | 5 ++--- .../MultipleReferencesOfSameScopedInstance.cs | 5 ++--- .../ScopeSpecificAttributes/Decorator.cs | 21 +++++++++---------- .../ScopeSpecificAttributes/Implementation.cs | 13 ++++++------ .../ImplementationCollection.cs | 13 ++++++------ .../TransientScopeInstance/InContainer.cs | 5 ++--- .../Scoping/TransientScopeInstance/InScope.cs | 5 ++--- .../TransientScopeInstance/InScopeInScope.cs | 5 ++--- .../InTransientScope.cs | 5 ++--- .../InTransientScopeWithScopes.cs | 5 ++--- Test/Struct/NoExplicitConstructor.cs | 5 ++--- Test/Struct/OneExplicitConstructor.cs | 5 ++--- Test/Struct/RangedInScope.cs | 5 ++--- Test/Struct/RecordNoExplicitConstructor.cs | 5 ++--- Test/Struct/RecordOneExplicitConstructor.cs | 5 ++--- Test/Tuple/NonSyntaxVariant.cs | 7 +++---- Test/Tuple/NonSyntaxVariantSingleItem.cs | 7 +++---- Test/Tuple/TupleTests.cs | 7 +++---- .../FactoryField/InContainercs.cs | 5 ++--- .../FactoryField/InScope.cs | 5 ++--- .../FactoryField/InTransientScope.cs | 5 ++--- .../FactoryMethod/InContainercs.cs | 5 ++--- .../FactoryMethod/InScope.cs | 5 ++--- .../FactoryMethod/InTransientScope.cs | 5 ++--- .../WithParameterInContainercs.cs | 5 ++--- .../FactoryMethod/WithParameterInScope.cs | 5 ++--- .../WithParameterInTransientScope.cs | 5 ++--- .../FactoryProperty/InContainer.cs | 5 ++--- .../FactoryProperty/InScope.cs | 5 ++--- .../FactoryProperty/InTransientScope.cs | 5 ++--- .../InjectionConstrParams/Vanilla.cs | 5 ++--- .../InjectionConstrParams/VanillaInScope.cs | 5 ++--- .../VanillaInTransientScope.cs | 5 ++--- .../InjectionConstrParams/WithDependency.cs | 5 ++--- .../WithDependencyInScope.cs | 5 ++--- .../WithDependencyInTransientScope.cs | 5 ++--- .../InjectionInitParams/Vanilla.cs | 5 ++--- .../InjectionInitParams/VanillaInScope.cs | 5 ++--- .../VanillaInTransientScope.cs | 5 ++--- .../InjectionInitParams/WithDependency.cs | 5 ++--- .../WithDependencyInScope.cs | 5 ++--- .../WithDependencyInTransientScope.cs | 5 ++--- .../InjectionProps/Vanilla.cs | 5 ++--- .../InjectionProps/VanillaInScope.cs | 5 ++--- .../InjectionProps/VanillaInTransientScope.cs | 5 ++--- .../InjectionProps/WithDependency.cs | 5 ++--- .../InjectionProps/WithDependencyInScope.cs | 5 ++--- .../WithDependencyInTransientScope.cs | 5 ++--- Test/ValueTuple/NonSyntaxVariant.cs | 7 +++---- Test/ValueTuple/NonSyntaxVariantSingleItem.cs | 7 +++---- Test/ValueTuple/SyntaxVariant.cs | 7 +++---- Test/ValueTuple/ValueTupleTests.cs | 7 +++---- 184 files changed, 432 insertions(+), 624 deletions(-) diff --git a/Main/SourceGenerator.cs b/Main/SourceGenerator.cs index 5660c9f7..9134cbbb 100644 --- a/Main/SourceGenerator.cs +++ b/Main/SourceGenerator.cs @@ -5,7 +5,6 @@ using MrMeeseeks.DIE.Validation.Attributes; using MrMeeseeks.DIE.Validation.Range; using MrMeeseeks.DIE.Validation.Range.UserDefined; -using System.Diagnostics; namespace MrMeeseeks.DIE; diff --git a/Sample/Container.cs b/Sample/Container.cs index 6762e080..7b1b7d15 100644 --- a/Sample/Container.cs +++ b/Sample/Container.cs @@ -1,5 +1,4 @@ -using System.IO; -using MrMeeseeks.DIE.Configuration.Attributes; +using MrMeeseeks.DIE.Configuration.Attributes; using MrMeeseeks.DIE.Sample; namespace MrMeeseeks.DIE.Test.Decorator.Multi; diff --git a/Test/Abstraction/AbstractClass/Collection.cs b/Test/Abstraction/AbstractClass/Collection.cs index 3f82d250..ba2400fc 100644 --- a/Test/Abstraction/AbstractClass/Collection.cs +++ b/Test/Abstraction/AbstractClass/Collection.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -20,9 +19,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instances = container.Create(); Assert.True(instances.Count == 2); Assert.True(instances[0].GetType() == typeof(SubClassA) && instances[1].GetType() == typeof(SubClassB) diff --git a/Test/Abstraction/AbstractClass/CollectionWithoutChoice.cs b/Test/Abstraction/AbstractClass/CollectionWithoutChoice.cs index 517ee647..492445c5 100644 --- a/Test/Abstraction/AbstractClass/CollectionWithoutChoice.cs +++ b/Test/Abstraction/AbstractClass/CollectionWithoutChoice.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -17,9 +16,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instances = container.Create(); Assert.True(instances.Count == 2); } diff --git a/Test/Abstraction/AbstractClass/SingleInCollection.cs b/Test/Abstraction/AbstractClass/SingleInCollection.cs index 714bcb62..e6b130b5 100644 --- a/Test/Abstraction/AbstractClass/SingleInCollection.cs +++ b/Test/Abstraction/AbstractClass/SingleInCollection.cs @@ -1,5 +1,4 @@ -using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration.Attributes; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Abstraction.AbstractClass.SingleInCollection; @@ -17,9 +16,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.IsType(instance); } diff --git a/Test/Abstraction/AbstractClass/Vanilla.cs b/Test/Abstraction/AbstractClass/Vanilla.cs index 23affc82..ec1671bb 100644 --- a/Test/Abstraction/AbstractClass/Vanilla.cs +++ b/Test/Abstraction/AbstractClass/Vanilla.cs @@ -1,5 +1,4 @@ -using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration.Attributes; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Abstraction.AbstractClass.Vanilla; @@ -17,9 +16,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.IsType(instance); } diff --git a/Test/Abstraction/AbstractClass/VanillaWithoutChoice.cs b/Test/Abstraction/AbstractClass/VanillaWithoutChoice.cs index 7a46181c..3cffd440 100644 --- a/Test/Abstraction/AbstractClass/VanillaWithoutChoice.cs +++ b/Test/Abstraction/AbstractClass/VanillaWithoutChoice.cs @@ -1,5 +1,4 @@ -using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration.Attributes; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Abstraction.AbstractClass.VanillaWithoutChoice; @@ -14,9 +13,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.IsType(instance); } diff --git a/Test/Abstraction/AbstractClass/WithSingleInCollection.cs b/Test/Abstraction/AbstractClass/WithSingleInCollection.cs index 7a5e2b3f..f3bd5b46 100644 --- a/Test/Abstraction/AbstractClass/WithSingleInCollection.cs +++ b/Test/Abstraction/AbstractClass/WithSingleInCollection.cs @@ -1,5 +1,4 @@ -using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration.Attributes; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Abstraction.AbstractClass.WithSingleInCollection; @@ -18,9 +17,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.IsType(instance); } diff --git a/Test/Abstraction/ArrayType.cs b/Test/Abstraction/ArrayType.cs index 93775ffd..a393d699 100644 --- a/Test/Abstraction/ArrayType.cs +++ b/Test/Abstraction/ArrayType.cs @@ -1,5 +1,4 @@ -using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration.Attributes; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Abstraction.ArrayType; @@ -18,9 +17,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.Equal(3, instance.Length); Assert.IsAssignableFrom(instance[0]); diff --git a/Test/Abstraction/Interface/Collection.cs b/Test/Abstraction/Interface/Collection.cs index a8213f5c..9dd064d1 100644 --- a/Test/Abstraction/Interface/Collection.cs +++ b/Test/Abstraction/Interface/Collection.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -20,9 +19,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instances = container.Create(); Assert.True(instances.Count == 2); Assert.True(instances[0].GetType() == typeof(SubClassA) && instances[1].GetType() == typeof(SubClassB) diff --git a/Test/Abstraction/Interface/CollectionWithoutChoice.cs b/Test/Abstraction/Interface/CollectionWithoutChoice.cs index a0094dac..817a6cf5 100644 --- a/Test/Abstraction/Interface/CollectionWithoutChoice.cs +++ b/Test/Abstraction/Interface/CollectionWithoutChoice.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -17,9 +16,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instances = container.Create(); Assert.True(instances.Count == 2); } diff --git a/Test/Abstraction/Interface/SingleInCollection.cs b/Test/Abstraction/Interface/SingleInCollection.cs index 5c51aa76..7ffb7ffc 100644 --- a/Test/Abstraction/Interface/SingleInCollection.cs +++ b/Test/Abstraction/Interface/SingleInCollection.cs @@ -1,5 +1,4 @@ -using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration.Attributes; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Abstraction.Interface.SingleInCollection; @@ -17,9 +16,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.IsType(instance); } diff --git a/Test/Abstraction/Interface/Vanilla.cs b/Test/Abstraction/Interface/Vanilla.cs index c01bd9c8..86b3b1a7 100644 --- a/Test/Abstraction/Interface/Vanilla.cs +++ b/Test/Abstraction/Interface/Vanilla.cs @@ -1,5 +1,4 @@ -using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration.Attributes; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Abstraction.Interface.Vanilla; @@ -17,9 +16,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.IsType(instance); } diff --git a/Test/Abstraction/Interface/VanillaWithoutChoice.cs b/Test/Abstraction/Interface/VanillaWithoutChoice.cs index a24a6aec..608313e2 100644 --- a/Test/Abstraction/Interface/VanillaWithoutChoice.cs +++ b/Test/Abstraction/Interface/VanillaWithoutChoice.cs @@ -1,5 +1,4 @@ -using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration.Attributes; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Abstraction.Interface.VanillaWithoutChoice; @@ -14,9 +13,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.IsType(instance); } diff --git a/Test/Abstraction/Interface/WithSingleInCollection.cs b/Test/Abstraction/Interface/WithSingleInCollection.cs index 28a6fd66..7efea39d 100644 --- a/Test/Abstraction/Interface/WithSingleInCollection.cs +++ b/Test/Abstraction/Interface/WithSingleInCollection.cs @@ -1,5 +1,4 @@ -using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration.Attributes; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Abstraction.Interface.WithSingleInCollection; @@ -18,9 +17,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.IsType(instance); } diff --git a/Test/Bugs/UngenericImplementationGenericInterface.cs b/Test/Bugs/UngenericImplementationGenericInterface.cs index 208db73c..92145134 100644 --- a/Test/Bugs/UngenericImplementationGenericInterface.cs +++ b/Test/Bugs/UngenericImplementationGenericInterface.cs @@ -1,5 +1,4 @@ -using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration.Attributes; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Bugs.UngenericImplementationGenericInterface; @@ -18,9 +17,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.IsType(instance); } diff --git a/Test/Collection/Composite/Array.cs b/Test/Collection/Composite/Array.cs index c8468f63..d9a8f0f3 100644 --- a/Test/Collection/Composite/Array.cs +++ b/Test/Collection/Composite/Array.cs @@ -1,5 +1,4 @@ -using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration.Attributes; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Collection.Composite.Array; @@ -23,9 +22,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var _ = container.Create(); } } \ No newline at end of file diff --git a/Test/Collection/Composite/IEnumerable.cs b/Test/Collection/Composite/IEnumerable.cs index 935443f4..f4ded128 100644 --- a/Test/Collection/Composite/IEnumerable.cs +++ b/Test/Collection/Composite/IEnumerable.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -24,9 +23,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var _ = container.Create(); } } \ No newline at end of file diff --git a/Test/Collection/Composite/IReadOnlyCollection.cs b/Test/Collection/Composite/IReadOnlyCollection.cs index aca083bf..b0a8a04e 100644 --- a/Test/Collection/Composite/IReadOnlyCollection.cs +++ b/Test/Collection/Composite/IReadOnlyCollection.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -24,9 +23,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var _ = container.Create(); } } \ No newline at end of file diff --git a/Test/Collection/Composite/IReadOnlyList.cs b/Test/Collection/Composite/IReadOnlyList.cs index 9336e3e4..0754b731 100644 --- a/Test/Collection/Composite/IReadOnlyList.cs +++ b/Test/Collection/Composite/IReadOnlyList.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -24,9 +23,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var _ = container.Create(); } } \ No newline at end of file diff --git a/Test/Collection/Injection/Array.cs b/Test/Collection/Injection/Array.cs index 4c628374..40a4ac69 100644 --- a/Test/Collection/Injection/Array.cs +++ b/Test/Collection/Injection/Array.cs @@ -1,5 +1,4 @@ -using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration.Attributes; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Collection.Injection.Array; @@ -18,9 +17,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var collection = container.Create(); Assert.Equal(3, collection.Length); } diff --git a/Test/Collection/Injection/IEnumerable.cs b/Test/Collection/Injection/IEnumerable.cs index eac53ed6..96012832 100644 --- a/Test/Collection/Injection/IEnumerable.cs +++ b/Test/Collection/Injection/IEnumerable.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -19,9 +18,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var _ = container.Create(); } } \ No newline at end of file diff --git a/Test/Collection/Injection/IReadOnlyCollection.cs b/Test/Collection/Injection/IReadOnlyCollection.cs index 8af9e70e..0bd54ecb 100644 --- a/Test/Collection/Injection/IReadOnlyCollection.cs +++ b/Test/Collection/Injection/IReadOnlyCollection.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -19,9 +18,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var collection = container.Create(); Assert.Equal(3, collection.Count); } diff --git a/Test/Collection/Injection/IReadOnlyList.cs b/Test/Collection/Injection/IReadOnlyList.cs index 006e0238..c1fed234 100644 --- a/Test/Collection/Injection/IReadOnlyList.cs +++ b/Test/Collection/Injection/IReadOnlyList.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -19,9 +18,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var collection = container.Create(); Assert.Equal(3, collection.Count); } diff --git a/Test/Composite/Container.cs b/Test/Composite/Container.cs index 0eba84da..08050861 100644 --- a/Test/Composite/Container.cs +++ b/Test/Composite/Container.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -38,9 +37,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var composite = container.CreateDep(); foreach (var compositeComposite in composite.Composites) { @@ -48,14 +47,12 @@ public async ValueTask Test() var type = compositeComposite.GetType(); Assert.True(type == typeof(BasisA) || type == typeof(BasisB)); } - var nextComposite = container.CreateDep(); - Assert.Equal(composite, nextComposite); } [Fact] - public async ValueTask TestList() + public void TestList() { - await using var container = new Container(); + using var container = new Container(); var composites = container.CreateCollection(); foreach (var compositeComposite in composites) { diff --git a/Test/Composite/Decorated.cs b/Test/Composite/Decorated.cs index 9022d72f..0bcc6637 100644 --- a/Test/Composite/Decorated.cs +++ b/Test/Composite/Decorated.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -64,9 +63,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var composite = container.CreateDep(); Assert.IsType(composite); Assert.IsType(composite.Decorated); @@ -81,9 +80,9 @@ public async ValueTask Test() } [Fact] - public async ValueTask TestList() + public void TestList() { - await using var container = new Container(); + using var container = new Container(); var composites = container.CreateCollection(); foreach (var compositeComposite in composites) { diff --git a/Test/Composite/MixedScoping.cs b/Test/Composite/MixedScoping.cs index 690f83cd..49f89c05 100644 --- a/Test/Composite/MixedScoping.cs +++ b/Test/Composite/MixedScoping.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -38,9 +37,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var composite = container.CreateDep(); foreach (var compositeComposite in composite.Composites) { @@ -53,9 +52,9 @@ public async ValueTask Test() } [Fact] - public async ValueTask TestList() + public void TestList() { - await using var container = new Container(); + using var container = new Container(); var composites = container.CreateCollection(); foreach (var compositeComposite in composites) { diff --git a/Test/Composite/Normal.cs b/Test/Composite/Normal.cs index 26421e68..1ea27946 100644 --- a/Test/Composite/Normal.cs +++ b/Test/Composite/Normal.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -38,9 +37,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var composite = container.CreateDep(); foreach (var compositeComposite in composite.Composites) { @@ -51,9 +50,9 @@ public async ValueTask Test() } [Fact] - public async ValueTask TestList() + public void TestList() { - await using var container = new Container(); + using var container = new Container(); var composites = container.CreateCollection(); foreach (var compositeComposite in composites) { diff --git a/Test/Composite/ScopeRoot.cs b/Test/Composite/ScopeRoot.cs index cbb02063..c3cf61a4 100644 --- a/Test/Composite/ScopeRoot.cs +++ b/Test/Composite/ScopeRoot.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -53,9 +52,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var composite = container.CreateDep(); foreach (var compositeComposite in composite.Composites) { @@ -68,9 +67,9 @@ public async ValueTask Test() } [Fact] - public async ValueTask TestList() + public void TestList() { - await using var container = new Container(); + using var container = new Container(); var composites = container.CreateCollection(); foreach (var compositeComposite in composites) { diff --git a/Test/ConstructorChoice/Parameterless.cs b/Test/ConstructorChoice/Parameterless.cs index 24a8ff0e..3c66304a 100644 --- a/Test/ConstructorChoice/Parameterless.cs +++ b/Test/ConstructorChoice/Parameterless.cs @@ -1,5 +1,4 @@ using System; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -16,9 +15,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var dateTime = container.Create(); Assert.Equal(DateTime.MinValue, dateTime); } diff --git a/Test/ConstructorChoice/WithParameter.cs b/Test/ConstructorChoice/WithParameter.cs index d294d8ed..d8c10c45 100644 --- a/Test/ConstructorChoice/WithParameter.cs +++ b/Test/ConstructorChoice/WithParameter.cs @@ -1,6 +1,5 @@ using System; using System.IO; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -17,9 +16,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var fileInfo = container.Create()("C:\\Yeah.txt"); Assert.Equal("C:\\Yeah.txt", fileInfo.FullName); } diff --git a/Test/CycleDetection/Function/NoCycle/DirectRecursionContainerFunc.cs b/Test/CycleDetection/Function/NoCycle/DirectRecursionContainerFunc.cs index 2b559dfe..0a9244b0 100644 --- a/Test/CycleDetection/Function/NoCycle/DirectRecursionContainerFunc.cs +++ b/Test/CycleDetection/Function/NoCycle/DirectRecursionContainerFunc.cs @@ -1,5 +1,4 @@ using System; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -19,9 +18,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.IsType(instance); } diff --git a/Test/CycleDetection/Function/NoCycle/DirectRecursionContainerLazy.cs b/Test/CycleDetection/Function/NoCycle/DirectRecursionContainerLazy.cs index 7b7b9b1a..b376bc89 100644 --- a/Test/CycleDetection/Function/NoCycle/DirectRecursionContainerLazy.cs +++ b/Test/CycleDetection/Function/NoCycle/DirectRecursionContainerLazy.cs @@ -1,5 +1,4 @@ using System; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -19,9 +18,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.IsType(instance); } diff --git a/Test/CycleDetection/Function/NoCycle/DirectRecursionScopeFunc.cs b/Test/CycleDetection/Function/NoCycle/DirectRecursionScopeFunc.cs index 0362890d..2ff06ff1 100644 --- a/Test/CycleDetection/Function/NoCycle/DirectRecursionScopeFunc.cs +++ b/Test/CycleDetection/Function/NoCycle/DirectRecursionScopeFunc.cs @@ -1,5 +1,4 @@ using System; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -19,9 +18,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.IsType(instance); } diff --git a/Test/CycleDetection/Function/NoCycle/DirectRecursionScopeLazy.cs b/Test/CycleDetection/Function/NoCycle/DirectRecursionScopeLazy.cs index bcb1e78a..2cb73928 100644 --- a/Test/CycleDetection/Function/NoCycle/DirectRecursionScopeLazy.cs +++ b/Test/CycleDetection/Function/NoCycle/DirectRecursionScopeLazy.cs @@ -1,5 +1,4 @@ using System; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -19,9 +18,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.IsType(instance); } diff --git a/Test/CycleDetection/Function/NoCycle/DirectRecursionTransientScopeFunc.cs b/Test/CycleDetection/Function/NoCycle/DirectRecursionTransientScopeFunc.cs index 7bdc11d3..6dbe029a 100644 --- a/Test/CycleDetection/Function/NoCycle/DirectRecursionTransientScopeFunc.cs +++ b/Test/CycleDetection/Function/NoCycle/DirectRecursionTransientScopeFunc.cs @@ -1,5 +1,4 @@ using System; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -19,9 +18,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.IsType(instance); } diff --git a/Test/CycleDetection/Function/NoCycle/DirectRecursionTransientScopeLazy.cs b/Test/CycleDetection/Function/NoCycle/DirectRecursionTransientScopeLazy.cs index 3f118d96..03e8e440 100644 --- a/Test/CycleDetection/Function/NoCycle/DirectRecursionTransientScopeLazy.cs +++ b/Test/CycleDetection/Function/NoCycle/DirectRecursionTransientScopeLazy.cs @@ -1,5 +1,4 @@ using System; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -19,9 +18,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.IsType(instance); } diff --git a/Test/CycleDetection/Implementation/NoCycle/NoCycleInParallel.cs b/Test/CycleDetection/Implementation/NoCycle/NoCycleInParallel.cs index 75b1636e..0257e153 100644 --- a/Test/CycleDetection/Implementation/NoCycle/NoCycleInParallel.cs +++ b/Test/CycleDetection/Implementation/NoCycle/NoCycleInParallel.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -27,9 +26,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var parent = container.Create(); Assert.IsType(parent); } diff --git a/Test/Decorator/ContainerInstance.cs b/Test/Decorator/ContainerInstance.cs index 5f0578b3..890e6cca 100644 --- a/Test/Decorator/ContainerInstance.cs +++ b/Test/Decorator/ContainerInstance.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -37,9 +36,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var collection = container.Create(); Assert.NotEqual(collection[0], collection[1]); diff --git a/Test/Decorator/List.cs b/Test/Decorator/List.cs index 6fc3989b..9fc14e83 100644 --- a/Test/Decorator/List.cs +++ b/Test/Decorator/List.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -37,9 +36,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var decorated = container.Create(); var decoratedOfA = decorated[0]; var decoratedOfB = decorated[1]; diff --git a/Test/Decorator/Multi.cs b/Test/Decorator/Multi.cs index 8ccf5219..8840ad8b 100644 --- a/Test/Decorator/Multi.cs +++ b/Test/Decorator/Multi.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; diff --git a/Test/Decorator/MultiOnConcrete.cs b/Test/Decorator/MultiOnConcrete.cs index 963f4f2e..58259a51 100644 --- a/Test/Decorator/MultiOnConcrete.cs +++ b/Test/Decorator/MultiOnConcrete.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; diff --git a/Test/Decorator/MultiOnConcreteWithContainerInstanceDecorated.cs b/Test/Decorator/MultiOnConcreteWithContainerInstanceDecorated.cs index 1890bca8..f2c32ed0 100644 --- a/Test/Decorator/MultiOnConcreteWithContainerInstanceDecorated.cs +++ b/Test/Decorator/MultiOnConcreteWithContainerInstanceDecorated.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; diff --git a/Test/Decorator/MultiWithContainerInstanceDecorated.cs b/Test/Decorator/MultiWithContainerInstanceDecorated.cs index 5fc273ef..c8ab7a2d 100644 --- a/Test/Decorator/MultiWithContainerInstanceDecorated.cs +++ b/Test/Decorator/MultiWithContainerInstanceDecorated.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; diff --git a/Test/Decorator/Normal.cs b/Test/Decorator/Normal.cs index 98751a17..88e95b3f 100644 --- a/Test/Decorator/Normal.cs +++ b/Test/Decorator/Normal.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -31,9 +30,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var decorated = container.Create(); Assert.NotEqual(decorated, decorated.Decorated); Assert.IsType(decorated); diff --git a/Test/Decorator/OneImplementationTwoDecoratedInterfaces.cs b/Test/Decorator/OneImplementationTwoDecoratedInterfaces.cs index 5df7c80d..5c7417b1 100644 --- a/Test/Decorator/OneImplementationTwoDecoratedInterfaces.cs +++ b/Test/Decorator/OneImplementationTwoDecoratedInterfaces.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -73,15 +72,15 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var parent = container.Create(); - Assert.IsType(parent.DependencyA.DecoratedA); - Assert.IsType(parent.DependencyA.DecoratedA.DecoratedA); - Assert.IsType(parent.DependencyA.DecoratedA.DecoratedA.DecoratedA); - Assert.IsType(parent.DependencyB.DecoratedB); - Assert.IsType(parent.DependencyB.DecoratedB.DecoratedB); - Assert.IsType(parent.DependencyB.DecoratedB.DecoratedB.DecoratedB); + Assert.IsType(parent.DependencyA); + Assert.IsType(parent.DependencyA.DecoratedA); + Assert.IsType(parent.DependencyA.DecoratedA.DecoratedA); + Assert.IsType(parent.DependencyB); + Assert.IsType(parent.DependencyB.DecoratedB); + Assert.IsType(parent.DependencyB.DecoratedB.DecoratedB); } } \ No newline at end of file diff --git a/Test/Decorator/ScopeDecoratorForContainerDependency.cs b/Test/Decorator/ScopeDecoratorForContainerDependency.cs index a6f0bad4..5a0227f1 100644 --- a/Test/Decorator/ScopeDecoratorForContainerDependency.cs +++ b/Test/Decorator/ScopeDecoratorForContainerDependency.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -24,13 +23,8 @@ internal class Decorator : IInterface, IDecorator internal class ScopeRoot : IScopeRoot { public IInterface Decorated { get; } - public IInterface SecondDecorator { get; } - internal ScopeRoot(IInterface decorated, IInterface secondDecorator) - { - Decorated = decorated; - SecondDecorator = secondDecorator; - } + internal ScopeRoot(IInterface decorated) => Decorated = decorated; } [CreateFunction(typeof(ScopeRoot), "Create")] @@ -41,9 +35,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var scopeRoot0 = container.Create(); var decorator0 = scopeRoot0.Decorated; @@ -60,7 +54,5 @@ public async ValueTask Test() Assert.NotSame(decorator0, decorator1); Assert.Same(dependency0, dependency1); - Assert.Same(decorator0, scopeRoot0.SecondDecorator); - Assert.Same(decorator1, scopeRoot1.SecondDecorator); } } \ No newline at end of file diff --git a/Test/Decorator/ScopeDecoratorForTransientScopeDependency.cs b/Test/Decorator/ScopeDecoratorForTransientScopeDependency.cs index 41543545..af0e6847 100644 --- a/Test/Decorator/ScopeDecoratorForTransientScopeDependency.cs +++ b/Test/Decorator/ScopeDecoratorForTransientScopeDependency.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -24,13 +23,8 @@ internal class Decorator : IInterface, IDecorator internal class ScopeRoot : IScopeRoot { public IInterface Decorated { get; } - public IInterface SecondDecorator { get; } - internal ScopeRoot(IInterface decorated, IInterface secondDecorator) - { - Decorated = decorated; - SecondDecorator = secondDecorator; - } + internal ScopeRoot(IInterface decorated) => Decorated = decorated; } [CreateFunction(typeof(ScopeRoot), "Create")] @@ -41,9 +35,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var scopeRoot0 = container.Create(); var decorator0 = scopeRoot0.Decorated; @@ -60,7 +54,5 @@ public async ValueTask Test() Assert.NotSame(decorator0, decorator1); Assert.Same(dependency0, dependency1); - Assert.Same(decorator0, scopeRoot0.SecondDecorator); - Assert.Same(decorator1, scopeRoot1.SecondDecorator); } } \ No newline at end of file diff --git a/Test/Decorator/SequenceEdgeCase.cs b/Test/Decorator/SequenceEdgeCase.cs index 18b6922b..6eab292b 100644 --- a/Test/Decorator/SequenceEdgeCase.cs +++ b/Test/Decorator/SequenceEdgeCase.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -66,9 +65,9 @@ private sealed partial class DIE_Scope_1 public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container0Then1 = new Container(); + using var container0Then1 = new Container(); var _0Then1_0_2 = container0Then1.Create0().Decorated; var _0Then1_0_1 = _0Then1_0_2.Decorated; @@ -92,7 +91,7 @@ public async ValueTask Test() Assert.Same(_0Then1_1_0, _0Then1_SanityCheck); - await using var container1Then0 = new Container(); + using var container1Then0 = new Container(); var _1Then0_1_1 = container1Then0.Create1().Decorated; var _1Then0_1_0 = _1Then0_1_1.Decorated; diff --git a/Test/Func/AsyncWrapped/MultipleTaskAtStart.cs b/Test/Func/AsyncWrapped/MultipleTaskAtStart.cs index 4fb90ee0..8a8bc9af 100644 --- a/Test/Func/AsyncWrapped/MultipleTaskAtStart.cs +++ b/Test/Func/AsyncWrapped/MultipleTaskAtStart.cs @@ -27,9 +27,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var func = container.Create(); var _ = func(); } diff --git a/Test/Func/AsyncWrapped/MultipleValueTaskAtStart.cs b/Test/Func/AsyncWrapped/MultipleValueTaskAtStart.cs index 3bf304fc..c92f06eb 100644 --- a/Test/Func/AsyncWrapped/MultipleValueTaskAtStart.cs +++ b/Test/Func/AsyncWrapped/MultipleValueTaskAtStart.cs @@ -27,9 +27,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var func = container.Create(); var _ = func(); } diff --git a/Test/Func/AsyncWrapped/SingleTask.cs b/Test/Func/AsyncWrapped/SingleTask.cs index 24660eda..7f06010f 100644 --- a/Test/Func/AsyncWrapped/SingleTask.cs +++ b/Test/Func/AsyncWrapped/SingleTask.cs @@ -27,9 +27,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var func = container.Create(); var _ = func(); } diff --git a/Test/Func/AsyncWrapped/SingleValueTask.cs b/Test/Func/AsyncWrapped/SingleValueTask.cs index b4a94e7b..e989cb9c 100644 --- a/Test/Func/AsyncWrapped/SingleValueTask.cs +++ b/Test/Func/AsyncWrapped/SingleValueTask.cs @@ -27,9 +27,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var func = container.Create(); var _ = func(); } diff --git a/Test/Func/Double.cs b/Test/Func/Double.cs index 405ff5f5..3ceca697 100644 --- a/Test/Func/Double.cs +++ b/Test/Func/Double.cs @@ -1,5 +1,4 @@ using System; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -25,9 +24,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var parent = container.Create(); Assert.IsType(parent); } diff --git a/Test/Func/Override.cs b/Test/Func/Override.cs index 3e190cbe..a904801c 100644 --- a/Test/Func/Override.cs +++ b/Test/Func/Override.cs @@ -1,5 +1,4 @@ using System; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -30,9 +29,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var parent = container.Create(); Assert.IsType(parent); Assert.Equal(1, parent.Dependency.Value); diff --git a/Test/Func/OverrideCombination.cs b/Test/Func/OverrideCombination.cs index 84e1c635..ae5e3049 100644 --- a/Test/Func/OverrideCombination.cs +++ b/Test/Func/OverrideCombination.cs @@ -1,5 +1,4 @@ using System; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -45,9 +44,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var parent = container.Create(); Assert.IsType(parent); Assert.Equal(2, parent.Dependency.ValueInt); diff --git a/Test/Func/OverrideExistingOverride.cs b/Test/Func/OverrideExistingOverride.cs index 02c42314..33f79fa4 100644 --- a/Test/Func/OverrideExistingOverride.cs +++ b/Test/Func/OverrideExistingOverride.cs @@ -1,5 +1,4 @@ using System; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -38,9 +37,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var parent = container.Create(); Assert.IsType(parent); Assert.Equal(6, parent.Dependency.Value); diff --git a/Test/Func/OverrideMultipleParameterOfSameType.cs b/Test/Func/OverrideMultipleParameterOfSameType.cs index 5bdd38a2..7836bf7d 100644 --- a/Test/Func/OverrideMultipleParameterOfSameType.cs +++ b/Test/Func/OverrideMultipleParameterOfSameType.cs @@ -1,5 +1,4 @@ using System; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -30,9 +29,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var parent = container.Create(); Assert.IsType(parent); Assert.Equal(1, parent.Dependency.Value); diff --git a/Test/Func/OverrideMultipleTypes.cs b/Test/Func/OverrideMultipleTypes.cs index 94771400..7bd508f9 100644 --- a/Test/Func/OverrideMultipleTypes.cs +++ b/Test/Func/OverrideMultipleTypes.cs @@ -1,5 +1,4 @@ using System; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -45,9 +44,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var parent = container.Create(); Assert.IsType(parent); Assert.IsType(parent.Dependency); diff --git a/Test/Func/OverrideScoped.cs b/Test/Func/OverrideScoped.cs index e641afd1..c2e7c71b 100644 --- a/Test/Func/OverrideScoped.cs +++ b/Test/Func/OverrideScoped.cs @@ -1,5 +1,4 @@ using System; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -40,9 +39,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var parent = container.Create(); Assert.IsType(parent); Assert.Equal(1, parent.Dependency.Value); diff --git a/Test/Func/ReductionCase.cs b/Test/Func/ReductionCase.cs index 7a6161b5..f7ec9fad 100644 --- a/Test/Func/ReductionCase.cs +++ b/Test/Func/ReductionCase.cs @@ -1,5 +1,4 @@ using System; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -53,9 +52,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var parent = container.Create(); Assert.IsType(parent); Assert.True(0 == parent.Dependency.Value); diff --git a/Test/Func/ReductionCaseTransientScope.cs b/Test/Func/ReductionCaseTransientScope.cs index cece1ba6..75329739 100644 --- a/Test/Func/ReductionCaseTransientScope.cs +++ b/Test/Func/ReductionCaseTransientScope.cs @@ -1,5 +1,4 @@ using System; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -53,9 +52,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var parent = container.Create(); Assert.IsType(parent); Assert.True(0 == parent.Dependency.Value); diff --git a/Test/Func/Vanilla.cs b/Test/Func/Vanilla.cs index b7d0e918..823c3c0b 100644 --- a/Test/Func/Vanilla.cs +++ b/Test/Func/Vanilla.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -16,9 +15,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var _ = container.Create()(DateTime.Now, new List()); } } diff --git a/Test/Func/WithArrayParameter.cs b/Test/Func/WithArrayParameter.cs index 5e168eb5..10a71490 100644 --- a/Test/Func/WithArrayParameter.cs +++ b/Test/Func/WithArrayParameter.cs @@ -1,5 +1,4 @@ using System; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -21,9 +20,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var _ = container.Create()(new [] { container.CreateParameter(), diff --git a/Test/Generics/Choice/Double.cs b/Test/Generics/Choice/Double.cs index 4390c8a1..5215488d 100644 --- a/Test/Generics/Choice/Double.cs +++ b/Test/Generics/Choice/Double.cs @@ -1,5 +1,4 @@ -using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration.Attributes; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Choice.Double; @@ -15,9 +14,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.IsType>(instance); } diff --git a/Test/Generics/Choice/DoubleBothChosen.cs b/Test/Generics/Choice/DoubleBothChosen.cs index 33357986..30f05cfa 100644 --- a/Test/Generics/Choice/DoubleBothChosen.cs +++ b/Test/Generics/Choice/DoubleBothChosen.cs @@ -1,5 +1,4 @@ -using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration.Attributes; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Choice.DoubleBothChosen; @@ -16,9 +15,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.IsType>(instance); } diff --git a/Test/Generics/Choice/DoubleBothChosenWithSingleOtherSubstitute.cs b/Test/Generics/Choice/DoubleBothChosenWithSingleOtherSubstitute.cs index b0b2eaf1..2d1eb8d3 100644 --- a/Test/Generics/Choice/DoubleBothChosenWithSingleOtherSubstitute.cs +++ b/Test/Generics/Choice/DoubleBothChosenWithSingleOtherSubstitute.cs @@ -1,5 +1,4 @@ -using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration.Attributes; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Choice.DoubleBothChosenWithSingleOtherSubstitute; @@ -18,9 +17,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.IsType>(instance); } diff --git a/Test/Generics/Choice/DoubleWithSingleOtherSubstitute.cs b/Test/Generics/Choice/DoubleWithSingleOtherSubstitute.cs index 30f806b3..4fbd9169 100644 --- a/Test/Generics/Choice/DoubleWithSingleOtherSubstitute.cs +++ b/Test/Generics/Choice/DoubleWithSingleOtherSubstitute.cs @@ -1,5 +1,4 @@ -using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration.Attributes; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Choice.DoubleWithSingleOtherSubstitute; @@ -16,9 +15,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.IsType>(instance); } diff --git a/Test/Generics/Choice/Single.cs b/Test/Generics/Choice/Single.cs index 1cf48545..7794ea29 100644 --- a/Test/Generics/Choice/Single.cs +++ b/Test/Generics/Choice/Single.cs @@ -1,5 +1,4 @@ -using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration.Attributes; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Choice.Single; @@ -15,9 +14,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.IsType>(instance); } diff --git a/Test/Generics/Choice/SingleWithSingleOtherSubstitute.cs b/Test/Generics/Choice/SingleWithSingleOtherSubstitute.cs index 1febfc35..06153529 100644 --- a/Test/Generics/Choice/SingleWithSingleOtherSubstitute.cs +++ b/Test/Generics/Choice/SingleWithSingleOtherSubstitute.cs @@ -1,5 +1,4 @@ -using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration.Attributes; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Choice.SingleWithSingleOtherSubstitute; @@ -16,9 +15,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.IsType>(instance); } diff --git a/Test/Generics/ChoiceIndirectlyBySingleSubstitute/Double.cs b/Test/Generics/ChoiceIndirectlyBySingleSubstitute/Double.cs index 9550c0a4..745641b7 100644 --- a/Test/Generics/ChoiceIndirectlyBySingleSubstitute/Double.cs +++ b/Test/Generics/ChoiceIndirectlyBySingleSubstitute/Double.cs @@ -1,5 +1,4 @@ -using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration.Attributes; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.ChoiceIndirectlyBySingleSubstitute.Double; @@ -15,9 +14,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.IsType>(instance); } diff --git a/Test/Generics/ChoiceIndirectlyBySingleSubstitute/Single.cs b/Test/Generics/ChoiceIndirectlyBySingleSubstitute/Single.cs index 82383caf..a2cd3e23 100644 --- a/Test/Generics/ChoiceIndirectlyBySingleSubstitute/Single.cs +++ b/Test/Generics/ChoiceIndirectlyBySingleSubstitute/Single.cs @@ -1,5 +1,4 @@ -using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration.Attributes; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.ChoiceIndirectlyBySingleSubstitute.Single; @@ -15,9 +14,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.IsType>(instance); } diff --git a/Test/Generics/Configuration/Composite.cs b/Test/Generics/Configuration/Composite.cs index 3b1e4af3..e9824224 100644 --- a/Test/Generics/Configuration/Composite.cs +++ b/Test/Generics/Configuration/Composite.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -39,9 +38,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var composite = container.Create(); Assert.IsType>(composite); } diff --git a/Test/Generics/Configuration/ConstructorChoice.cs b/Test/Generics/Configuration/ConstructorChoice.cs index b1a4dad9..f96e830b 100644 --- a/Test/Generics/Configuration/ConstructorChoice.cs +++ b/Test/Generics/Configuration/ConstructorChoice.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -26,9 +25,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.IsType(instance.Dependency); } diff --git a/Test/Generics/Configuration/ContainerInstance.cs b/Test/Generics/Configuration/ContainerInstance.cs index 065cb55c..8bcb80e5 100644 --- a/Test/Generics/Configuration/ContainerInstance.cs +++ b/Test/Generics/Configuration/ContainerInstance.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -12,9 +11,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance0 = container.Create(); var instance1 = container.Create(); Assert.Same(instance0, instance1); diff --git a/Test/Generics/Configuration/ContainerInstanceWithDifferentGenericParameter.cs b/Test/Generics/Configuration/ContainerInstanceWithDifferentGenericParameter.cs index 53846bb0..6da4eca7 100644 --- a/Test/Generics/Configuration/ContainerInstanceWithDifferentGenericParameter.cs +++ b/Test/Generics/Configuration/ContainerInstanceWithDifferentGenericParameter.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -13,9 +12,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance0 = container.Create(); var instance1 = container.CreateString(); Assert.NotSame(instance0, instance1); diff --git a/Test/Generics/Configuration/Decorator.cs b/Test/Generics/Configuration/Decorator.cs index d8eaf8ab..778afbde 100644 --- a/Test/Generics/Configuration/Decorator.cs +++ b/Test/Generics/Configuration/Decorator.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -44,9 +43,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var decorator = container.Create(); Assert.IsType>(decorator); Assert.IsType>(decorator.Decorated); diff --git a/Test/Generics/Configuration/InitializerImplementationSync.cs b/Test/Generics/Configuration/InitializerImplementationSync.cs index bbed4024..7f9baa54 100644 --- a/Test/Generics/Configuration/InitializerImplementationSync.cs +++ b/Test/Generics/Configuration/InitializerImplementationSync.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -24,9 +23,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.True(instance.IsInitialized); } diff --git a/Test/Generics/Configuration/InitializerInterfaceSync.cs b/Test/Generics/Configuration/InitializerInterfaceSync.cs index 67c85309..ebe703c3 100644 --- a/Test/Generics/Configuration/InitializerInterfaceSync.cs +++ b/Test/Generics/Configuration/InitializerInterfaceSync.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -23,9 +22,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.True(instance.IsInitialized); } diff --git a/Test/Generics/Configuration/InterfaceGenericComposite.cs b/Test/Generics/Configuration/InterfaceGenericComposite.cs index cbd66c67..0bcf0711 100644 --- a/Test/Generics/Configuration/InterfaceGenericComposite.cs +++ b/Test/Generics/Configuration/InterfaceGenericComposite.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -39,9 +38,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var composite = container.Create(); Assert.IsType>(composite); } diff --git a/Test/Generics/Configuration/InterfaceGenericDecorator.cs b/Test/Generics/Configuration/InterfaceGenericDecorator.cs index 5310006e..e8303f5f 100644 --- a/Test/Generics/Configuration/InterfaceGenericDecorator.cs +++ b/Test/Generics/Configuration/InterfaceGenericDecorator.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -44,9 +43,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var decorator = container.Create(); Assert.IsType>(decorator); Assert.IsType>(decorator.Decorated); diff --git a/Test/Generics/Configuration/ScopeInstance.cs b/Test/Generics/Configuration/ScopeInstance.cs index cc44f3d4..b6d909e1 100644 --- a/Test/Generics/Configuration/ScopeInstance.cs +++ b/Test/Generics/Configuration/ScopeInstance.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -26,9 +25,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var scopeRoot = container.Create(); Assert.Same(scopeRoot.Dependency0, scopeRoot.Dependency1); } diff --git a/Test/Generics/Configuration/ScopeInstanceWithDifferentGenericParameter.cs b/Test/Generics/Configuration/ScopeInstanceWithDifferentGenericParameter.cs index ea88f9fa..b19629ce 100644 --- a/Test/Generics/Configuration/ScopeInstanceWithDifferentGenericParameter.cs +++ b/Test/Generics/Configuration/ScopeInstanceWithDifferentGenericParameter.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -26,9 +25,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var scopeRoot = container.Create(); Assert.NotSame(scopeRoot.Dependency0, scopeRoot.Dependency1); } diff --git a/Test/Generics/Configuration/ScopeRoot.cs b/Test/Generics/Configuration/ScopeRoot.cs index 6e231c3e..cb2a7579 100644 --- a/Test/Generics/Configuration/ScopeRoot.cs +++ b/Test/Generics/Configuration/ScopeRoot.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -33,9 +32,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var root = container.Create(); Assert.NotSame(root.ScopeInstance, root.ScopeRoot.ScopeInstance); } diff --git a/Test/Generics/Configuration/SyncTransient.cs b/Test/Generics/Configuration/SyncTransient.cs index 1b236ff8..4013a81e 100644 --- a/Test/Generics/Configuration/SyncTransient.cs +++ b/Test/Generics/Configuration/SyncTransient.cs @@ -1,5 +1,4 @@ using System; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -25,9 +24,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); using var instance = container.Create(); Assert.False(instance.IsDisposed); container.Dispose(); diff --git a/Test/Generics/Configuration/SyncTransientWithJustTransient.cs b/Test/Generics/Configuration/SyncTransientWithJustTransient.cs index ade2d2be..0e6c2668 100644 --- a/Test/Generics/Configuration/SyncTransientWithJustTransient.cs +++ b/Test/Generics/Configuration/SyncTransientWithJustTransient.cs @@ -1,5 +1,4 @@ using System; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -25,9 +24,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); using var instance = container.Create(); Assert.False(instance.IsDisposed); container.Dispose(); diff --git a/Test/Generics/Configuration/TransientScopeInstance.cs b/Test/Generics/Configuration/TransientScopeInstance.cs index 13e179d2..3f64f23c 100644 --- a/Test/Generics/Configuration/TransientScopeInstance.cs +++ b/Test/Generics/Configuration/TransientScopeInstance.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -26,9 +25,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var transientScopeRoot = container.Create(); Assert.Same(transientScopeRoot.Dependency0, transientScopeRoot.Dependency1); } diff --git a/Test/Generics/Configuration/TransientScopeInstanceWithDifferentGenericParameter.cs b/Test/Generics/Configuration/TransientScopeInstanceWithDifferentGenericParameter.cs index 14ce6d92..584344af 100644 --- a/Test/Generics/Configuration/TransientScopeInstanceWithDifferentGenericParameter.cs +++ b/Test/Generics/Configuration/TransientScopeInstanceWithDifferentGenericParameter.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -26,9 +25,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var transientScopeRoot = container.Create(); Assert.NotSame(transientScopeRoot.Dependency0, transientScopeRoot.Dependency1); } diff --git a/Test/Generics/Configuration/TransientScopeRoot.cs b/Test/Generics/Configuration/TransientScopeRoot.cs index e3e88a62..e31e6695 100644 --- a/Test/Generics/Configuration/TransientScopeRoot.cs +++ b/Test/Generics/Configuration/TransientScopeRoot.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -33,9 +32,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var root = container.Create(); Assert.NotSame(root.ScopeInstance, root.TransientScopeRoot.ScopeInstance); } diff --git a/Test/Generics/Implementation/Double.cs b/Test/Generics/Implementation/Double.cs index ae89f5b7..21525456 100644 --- a/Test/Generics/Implementation/Double.cs +++ b/Test/Generics/Implementation/Double.cs @@ -1,5 +1,4 @@ -using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration.Attributes; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Implementation.Double; @@ -12,9 +11,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.IsType>(instance); } diff --git a/Test/Generics/Implementation/Single.cs b/Test/Generics/Implementation/Single.cs index 27f7adec..3f6c4750 100644 --- a/Test/Generics/Implementation/Single.cs +++ b/Test/Generics/Implementation/Single.cs @@ -1,5 +1,4 @@ -using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration.Attributes; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Implementation.Single; @@ -12,9 +11,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.IsType>(instance); } diff --git a/Test/Generics/Interface/Double.cs b/Test/Generics/Interface/Double.cs index 2a205b05..cbe0507b 100644 --- a/Test/Generics/Interface/Double.cs +++ b/Test/Generics/Interface/Double.cs @@ -1,5 +1,4 @@ -using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration.Attributes; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Interface.Double; @@ -14,9 +13,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.IsType>(instance); } diff --git a/Test/Generics/Interface/DoubleAndOneFixed.cs b/Test/Generics/Interface/DoubleAndOneFixed.cs index eb05c6ef..91216ec2 100644 --- a/Test/Generics/Interface/DoubleAndOneFixed.cs +++ b/Test/Generics/Interface/DoubleAndOneFixed.cs @@ -1,5 +1,4 @@ -using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration.Attributes; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Interface.DoubleAndOneFixed; @@ -14,9 +13,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.IsType>(instance); } diff --git a/Test/Generics/Interface/DoubleAndSetToSame.cs b/Test/Generics/Interface/DoubleAndSetToSame.cs index 3c060d8a..36614041 100644 --- a/Test/Generics/Interface/DoubleAndSetToSame.cs +++ b/Test/Generics/Interface/DoubleAndSetToSame.cs @@ -1,5 +1,4 @@ -using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration.Attributes; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Interface.DoubleAndSetToSame; @@ -14,9 +13,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.IsType>(instance); } diff --git a/Test/Generics/Interface/DoubleSwitched.cs b/Test/Generics/Interface/DoubleSwitched.cs index 76e04d2d..f15e4be5 100644 --- a/Test/Generics/Interface/DoubleSwitched.cs +++ b/Test/Generics/Interface/DoubleSwitched.cs @@ -1,5 +1,4 @@ -using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration.Attributes; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Interface.DoubleSwitched; @@ -14,9 +13,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.IsType>(instance); } diff --git a/Test/Generics/Interface/Single.cs b/Test/Generics/Interface/Single.cs index 486f18f3..83cbe3fd 100644 --- a/Test/Generics/Interface/Single.cs +++ b/Test/Generics/Interface/Single.cs @@ -1,5 +1,4 @@ -using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration.Attributes; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Interface.Single; @@ -14,9 +13,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.IsType>(instance); } diff --git a/Test/Generics/Interface/SingleAndBaseImplementationDoubleButOneFixed.cs b/Test/Generics/Interface/SingleAndBaseImplementationDoubleButOneFixed.cs index d983df21..c526e384 100644 --- a/Test/Generics/Interface/SingleAndBaseImplementationDoubleButOneFixed.cs +++ b/Test/Generics/Interface/SingleAndBaseImplementationDoubleButOneFixed.cs @@ -1,5 +1,4 @@ -using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration.Attributes; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Generics.Interface.SingleAndBaseImplementationDoubleButOneFixed; @@ -16,9 +15,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.IsType>(instance); } diff --git a/Test/Generics/SubstituteCollection/Double.cs b/Test/Generics/SubstituteCollection/Double.cs index 00de61e6..4935ce3a 100644 --- a/Test/Generics/SubstituteCollection/Double.cs +++ b/Test/Generics/SubstituteCollection/Double.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -16,9 +15,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var list = container.Create(); Assert.Equal(2, list.Count); Assert.Contains(list, i => i.GetType() == typeof(Class)); diff --git a/Test/Generics/SubstituteCollection/DoubleBothSubstituted.cs b/Test/Generics/SubstituteCollection/DoubleBothSubstituted.cs index 42859ed4..94429532 100644 --- a/Test/Generics/SubstituteCollection/DoubleBothSubstituted.cs +++ b/Test/Generics/SubstituteCollection/DoubleBothSubstituted.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -17,9 +16,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var list = container.Create(); Assert.Equal(4, list.Count); Assert.Contains(list, i => i.GetType() == typeof(Class)); diff --git a/Test/Generics/SubstituteCollection/DoubleBothSubstitutedWithChoice.cs b/Test/Generics/SubstituteCollection/DoubleBothSubstitutedWithChoice.cs index d88896ac..e5cea652 100644 --- a/Test/Generics/SubstituteCollection/DoubleBothSubstitutedWithChoice.cs +++ b/Test/Generics/SubstituteCollection/DoubleBothSubstitutedWithChoice.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -19,9 +18,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var list = container.Create(); Assert.Equal(4, list.Count); Assert.Contains(list, i => i.GetType() == typeof(Class)); diff --git a/Test/Generics/SubstituteCollection/DoubleWithChoice.cs b/Test/Generics/SubstituteCollection/DoubleWithChoice.cs index 295a80d2..e338e0e7 100644 --- a/Test/Generics/SubstituteCollection/DoubleWithChoice.cs +++ b/Test/Generics/SubstituteCollection/DoubleWithChoice.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -17,9 +16,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var list = container.Create(); Assert.Equal(2, list.Count); Assert.Contains(list, i => i.GetType() == typeof(Class)); diff --git a/Test/Generics/SubstituteCollection/Single.cs b/Test/Generics/SubstituteCollection/Single.cs index 6f65e0f2..19bcb8d6 100644 --- a/Test/Generics/SubstituteCollection/Single.cs +++ b/Test/Generics/SubstituteCollection/Single.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -16,9 +15,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var list = container.Create(); Assert.Equal(2, list.Count); Assert.Contains(list, i => i.GetType() == typeof(Class)); diff --git a/Test/Generics/SubstituteCollection/SingleWithChoice.cs b/Test/Generics/SubstituteCollection/SingleWithChoice.cs index 18cb67f4..aab85855 100644 --- a/Test/Generics/SubstituteCollection/SingleWithChoice.cs +++ b/Test/Generics/SubstituteCollection/SingleWithChoice.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -17,9 +16,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var list = container.Create(); Assert.Equal(2, list.Count); Assert.Contains(list, i => i.GetType() == typeof(Class)); diff --git a/Test/Generics/SubstituteCollection/TripleInsanity.cs b/Test/Generics/SubstituteCollection/TripleInsanity.cs index 262f6427..285c0a84 100644 --- a/Test/Generics/SubstituteCollection/TripleInsanity.cs +++ b/Test/Generics/SubstituteCollection/TripleInsanity.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -18,9 +17,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var list = container.Create(); Assert.Equal(125, list.Count); } diff --git a/Test/Implementation/Aggregation/AssemblyImplementationsAggregation.cs b/Test/Implementation/Aggregation/AssemblyImplementationsAggregation.cs index 03957879..6ba7e3f4 100644 --- a/Test/Implementation/Aggregation/AssemblyImplementationsAggregation.cs +++ b/Test/Implementation/Aggregation/AssemblyImplementationsAggregation.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using MrMeeseeks.DIE.TestNotInternalsVisibleToChild.Public; using Xunit; @@ -14,9 +13,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.IsType(instance); } diff --git a/Test/Implementation/Aggregation/ExternalType.cs b/Test/Implementation/Aggregation/ExternalType.cs index 8c048036..0ac9914d 100644 --- a/Test/Implementation/Aggregation/ExternalType.cs +++ b/Test/Implementation/Aggregation/ExternalType.cs @@ -1,6 +1,5 @@ using System; using System.IO; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -18,9 +17,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var path = @"C:\HelloWorld.txt"; var fileInfo = container.Create()(path); Assert.NotNull(fileInfo); diff --git a/Test/Implementation/Aggregation/FilterAllImplementations.cs b/Test/Implementation/Aggregation/FilterAllImplementations.cs index b64b3d5a..1edd47ad 100644 --- a/Test/Implementation/Aggregation/FilterAllImplementations.cs +++ b/Test/Implementation/Aggregation/FilterAllImplementations.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -18,9 +17,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.IsType(instance); } diff --git a/Test/Implementation/Aggregation/InternalsVisibleTo.cs b/Test/Implementation/Aggregation/InternalsVisibleTo.cs index d5793377..24baf271 100644 --- a/Test/Implementation/Aggregation/InternalsVisibleTo.cs +++ b/Test/Implementation/Aggregation/InternalsVisibleTo.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using MrMeeseeks.DIE.TestInternalsVisibleToChild.Internal; using Xunit; @@ -12,9 +11,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.IsType(instance); } diff --git a/Test/Implementation/ArrayType.cs b/Test/Implementation/ArrayType.cs index ddf8b601..e59519a1 100644 --- a/Test/Implementation/ArrayType.cs +++ b/Test/Implementation/ArrayType.cs @@ -1,5 +1,4 @@ -using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration.Attributes; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Implementation.ArrayType; @@ -12,9 +11,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.IsType(instance[0]); } diff --git a/Test/Implementation/Choice/Collection.cs b/Test/Implementation/Choice/Collection.cs index 96b94ff4..779a2f07 100644 --- a/Test/Implementation/Choice/Collection.cs +++ b/Test/Implementation/Choice/Collection.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -18,9 +17,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instances = container.Create(); Assert.True(instances.Count == 2); Assert.True(instances[0].GetType() == typeof(SubClassA) && instances[1].GetType() == typeof(SubClassB) diff --git a/Test/Implementation/Choice/CollectionWithoutChoice.cs b/Test/Implementation/Choice/CollectionWithoutChoice.cs index a94a74a5..9f291c56 100644 --- a/Test/Implementation/Choice/CollectionWithoutChoice.cs +++ b/Test/Implementation/Choice/CollectionWithoutChoice.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -17,9 +16,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instances = container.Create(); Assert.True(instances.Count == 3); } diff --git a/Test/Implementation/Choice/SingleInCollection.cs b/Test/Implementation/Choice/SingleInCollection.cs index abcf892d..7e956eb2 100644 --- a/Test/Implementation/Choice/SingleInCollection.cs +++ b/Test/Implementation/Choice/SingleInCollection.cs @@ -1,5 +1,4 @@ -using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration.Attributes; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Implementation.Choice.SingleInCollection; @@ -15,9 +14,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.IsType(instance); } diff --git a/Test/Implementation/Choice/Vanilla.cs b/Test/Implementation/Choice/Vanilla.cs index 01a5afac..2a61f2b1 100644 --- a/Test/Implementation/Choice/Vanilla.cs +++ b/Test/Implementation/Choice/Vanilla.cs @@ -1,5 +1,4 @@ -using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration.Attributes; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Implementation.Choice.Vanilla; @@ -15,9 +14,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.IsType(instance); } diff --git a/Test/Implementation/Choice/VanillaWithoutChoice.cs b/Test/Implementation/Choice/VanillaWithoutChoice.cs index d9cd2e54..66616bba 100644 --- a/Test/Implementation/Choice/VanillaWithoutChoice.cs +++ b/Test/Implementation/Choice/VanillaWithoutChoice.cs @@ -1,5 +1,4 @@ -using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration.Attributes; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Implementation.Choice.VanillaWithoutChoice; @@ -14,9 +13,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.IsType(instance); } diff --git a/Test/Implementation/Choice/WithSingleInCollection.cs b/Test/Implementation/Choice/WithSingleInCollection.cs index f86262be..4fe9347d 100644 --- a/Test/Implementation/Choice/WithSingleInCollection.cs +++ b/Test/Implementation/Choice/WithSingleInCollection.cs @@ -1,5 +1,4 @@ -using System.Threading.Tasks; -using MrMeeseeks.DIE.Configuration.Attributes; +using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; namespace MrMeeseeks.DIE.Test.Implementation.Choice.WithSingleInCollection; @@ -18,9 +17,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.IsType(instance); } diff --git a/Test/InitProperty/Vanilla.cs b/Test/InitProperty/Vanilla.cs index 4eaec3fe..c09efc45 100644 --- a/Test/InitProperty/Vanilla.cs +++ b/Test/InitProperty/Vanilla.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -19,9 +18,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var hasInitProperty = container.Create(); Assert.NotNull(hasInitProperty); Assert.NotNull(hasInitProperty.Dependency); diff --git a/Test/Initializer/Sync.cs b/Test/Initializer/Sync.cs index da686846..57415058 100644 --- a/Test/Initializer/Sync.cs +++ b/Test/Initializer/Sync.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -19,9 +18,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.True(instance.IsInitialized); } diff --git a/Test/Initializer/WithParameters.cs b/Test/Initializer/WithParameters.cs index 22afa772..02c38794 100644 --- a/Test/Initializer/WithParameters.cs +++ b/Test/Initializer/WithParameters.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -31,9 +30,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.True(instance.IsInitialized); Assert.Equal(69, instance.Number); diff --git a/Test/Lazy/AsyncWrapped/MultipleTaskAtStart.cs b/Test/Lazy/AsyncWrapped/MultipleTaskAtStart.cs index b0916675..90a7cf5d 100644 --- a/Test/Lazy/AsyncWrapped/MultipleTaskAtStart.cs +++ b/Test/Lazy/AsyncWrapped/MultipleTaskAtStart.cs @@ -27,9 +27,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var lazy = container.Create(); var _ = lazy.Value; } diff --git a/Test/Lazy/AsyncWrapped/MultipleValueTaskAtStart.cs b/Test/Lazy/AsyncWrapped/MultipleValueTaskAtStart.cs index 7d3278b3..3be1e12d 100644 --- a/Test/Lazy/AsyncWrapped/MultipleValueTaskAtStart.cs +++ b/Test/Lazy/AsyncWrapped/MultipleValueTaskAtStart.cs @@ -27,9 +27,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var lazy = container.Create(); var _ = lazy.Value; } diff --git a/Test/Lazy/AsyncWrapped/SingleTask.cs b/Test/Lazy/AsyncWrapped/SingleTask.cs index 6d247c8c..9a2c84e0 100644 --- a/Test/Lazy/AsyncWrapped/SingleTask.cs +++ b/Test/Lazy/AsyncWrapped/SingleTask.cs @@ -27,9 +27,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var lazy = container.Create(); var _ = lazy.Value; } diff --git a/Test/Lazy/AsyncWrapped/SingleValueTask.cs b/Test/Lazy/AsyncWrapped/SingleValueTask.cs index 168862de..518b9fb8 100644 --- a/Test/Lazy/AsyncWrapped/SingleValueTask.cs +++ b/Test/Lazy/AsyncWrapped/SingleValueTask.cs @@ -27,9 +27,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var lazy = container.Create(); var _ = lazy.Value; } diff --git a/Test/Lazy/Override.cs b/Test/Lazy/Override.cs index 497cac75..89e7ee7c 100644 --- a/Test/Lazy/Override.cs +++ b/Test/Lazy/Override.cs @@ -1,5 +1,4 @@ using System; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -31,9 +30,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var parent = container.Create(); Assert.IsType(parent); Assert.Equal(23, parent.Dependency.Value); diff --git a/Test/Lazy/Vanilla.cs b/Test/Lazy/Vanilla.cs index cd2111d5..b9176418 100644 --- a/Test/Lazy/Vanilla.cs +++ b/Test/Lazy/Vanilla.cs @@ -1,5 +1,4 @@ using System; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -15,9 +14,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var lazy = container.Create(); var _ = lazy.Value; } diff --git a/Test/Nullability/NonOptional/MultipleImplementations.cs b/Test/Nullability/NonOptional/MultipleImplementations.cs index 9b4a4dbc..35270b71 100644 --- a/Test/Nullability/NonOptional/MultipleImplementations.cs +++ b/Test/Nullability/NonOptional/MultipleImplementations.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -25,9 +24,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var dependency = container.Create().Dependency; Assert.Null(dependency); } diff --git a/Test/Nullability/NonOptional/NoImplementation.cs b/Test/Nullability/NonOptional/NoImplementation.cs index ab5fc44b..2ad6fd35 100644 --- a/Test/Nullability/NonOptional/NoImplementation.cs +++ b/Test/Nullability/NonOptional/NoImplementation.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -21,9 +20,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var dependency = container.Create().Dependency; Assert.Null(dependency); } diff --git a/Test/Nullability/Optional/MultipleImplementations.cs b/Test/Nullability/Optional/MultipleImplementations.cs index 9eaaa7ef..5771f52b 100644 --- a/Test/Nullability/Optional/MultipleImplementations.cs +++ b/Test/Nullability/Optional/MultipleImplementations.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -25,9 +24,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var dependency = container.Create().Dependency; Assert.Null(dependency); } diff --git a/Test/Nullability/Optional/NoImplementation.cs b/Test/Nullability/Optional/NoImplementation.cs index dea2d5bd..5b36160b 100644 --- a/Test/Nullability/Optional/NoImplementation.cs +++ b/Test/Nullability/Optional/NoImplementation.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -21,9 +20,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var dependency = container.Create().Dependency; Assert.Null(dependency); } diff --git a/Test/Record/CustomProperty.cs b/Test/Record/CustomProperty.cs index cfdd6708..85f3a5c6 100644 --- a/Test/Record/CustomProperty.cs +++ b/Test/Record/CustomProperty.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -19,9 +18,9 @@ internal sealed partial class Container{} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.IsType(instance); Assert.IsType(instance.Dependency); diff --git a/Test/Record/PrimaryConstr.cs b/Test/Record/PrimaryConstr.cs index 4970aa23..3e459033 100644 --- a/Test/Record/PrimaryConstr.cs +++ b/Test/Record/PrimaryConstr.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -14,9 +13,9 @@ internal sealed partial class Container{} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.IsType(instance); Assert.IsType(instance.Dependency); diff --git a/Test/Record/Vanilla.cs b/Test/Record/Vanilla.cs index 119402f7..f732ec8d 100644 --- a/Test/Record/Vanilla.cs +++ b/Test/Record/Vanilla.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -12,9 +11,9 @@ internal sealed partial class Container{} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.IsType(instance); } diff --git a/Test/Scoping/FuncContainerInstance.cs b/Test/Scoping/FuncContainerInstance.cs index 3002d87e..825a6ef1 100644 --- a/Test/Scoping/FuncContainerInstance.cs +++ b/Test/Scoping/FuncContainerInstance.cs @@ -1,6 +1,5 @@ using MrMeeseeks.DIE.Configuration.Attributes; using System; -using System.Threading.Tasks; using Xunit; namespace MrMeeseeks.DIE.Test.Scoping.FuncContainerInstance; @@ -13,9 +12,9 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create()("Foo"); Assert.IsType(instance); } diff --git a/Test/Scoping/InScope.cs b/Test/Scoping/InScope.cs index f144f668..01c9f59f 100644 --- a/Test/Scoping/InScope.cs +++ b/Test/Scoping/InScope.cs @@ -1,5 +1,4 @@ using System; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -19,8 +18,8 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); } } \ No newline at end of file diff --git a/Test/Scoping/MultipleReferencesOfSameScopedInstance.cs b/Test/Scoping/MultipleReferencesOfSameScopedInstance.cs index 0af8b4e3..53e15fa4 100644 --- a/Test/Scoping/MultipleReferencesOfSameScopedInstance.cs +++ b/Test/Scoping/MultipleReferencesOfSameScopedInstance.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -33,9 +32,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.IsType(instance); } diff --git a/Test/Scoping/ScopeSpecificAttributes/Decorator.cs b/Test/Scoping/ScopeSpecificAttributes/Decorator.cs index bcc85d14..8c75465c 100644 --- a/Test/Scoping/ScopeSpecificAttributes/Decorator.cs +++ b/Test/Scoping/ScopeSpecificAttributes/Decorator.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -127,37 +126,37 @@ private sealed partial class DIE_Scope_A public class Tests { [Fact] - public async ValueTask Container() + public void Container() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create0(); Assert.Equal(69, instance.CheckNumber); } [Fact] - public async ValueTask TransientScope() + public void TransientScope() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create1(); Assert.Equal(23, instance.Dep.CheckNumber); } [Fact] - public async ValueTask TransientScopeSpecific() + public void TransientScopeSpecific() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create2(); Assert.Equal(7, instance.Dep.CheckNumber); } [Fact] - public async ValueTask Scope() + public void Scope() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create3(); Assert.Equal(3, instance.Dep.CheckNumber); } [Fact] - public async ValueTask ScopeSpecific() + public void ScopeSpecific() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create4(); Assert.Equal(13, instance.Dep.CheckNumber); } diff --git a/Test/Scoping/ScopeSpecificAttributes/Implementation.cs b/Test/Scoping/ScopeSpecificAttributes/Implementation.cs index f7c2689c..4a909369 100644 --- a/Test/Scoping/ScopeSpecificAttributes/Implementation.cs +++ b/Test/Scoping/ScopeSpecificAttributes/Implementation.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -50,23 +49,23 @@ private sealed partial class DIE_DefaultScope public class Tests { [Fact] - public async ValueTask Container() + public void Container() { - await using var container = new Container(); + using var container = new Container(); var dependency = container.Create0(); Assert.IsType(dependency); } [Fact] - public async ValueTask TransientScope() + public void TransientScope() { - await using var container = new Container(); + using var container = new Container(); var dependency = container.Create1(); Assert.IsType(dependency.Dependency); } [Fact] - public async ValueTask Scope() + public void Scope() { - await using var container = new Container(); + using var container = new Container(); var dependency = container.Create2(); Assert.IsType(dependency.Dependency); } diff --git a/Test/Scoping/ScopeSpecificAttributes/ImplementationCollection.cs b/Test/Scoping/ScopeSpecificAttributes/ImplementationCollection.cs index fe3767e6..ff5e2033 100644 --- a/Test/Scoping/ScopeSpecificAttributes/ImplementationCollection.cs +++ b/Test/Scoping/ScopeSpecificAttributes/ImplementationCollection.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -50,9 +49,9 @@ public class Tests { [Fact] - public async ValueTask Container() + public void Container() { - await using var container = new Container(); + using var container = new Container(); var dependencies = container.Create0(); Assert.Equal(3, dependencies.Count); Assert.Contains(dependencies, d => d.GetType() == typeof(DependencyContainer)); @@ -60,17 +59,17 @@ public async ValueTask Container() Assert.Contains(dependencies, d => d.GetType() == typeof(DependencyScope)); } [Fact] - public async ValueTask TransientScope() + public void TransientScope() { - await using var container = new Container(); + using var container = new Container(); var dependencies = container.Create1(); Assert.Equal(1, dependencies.Dependencies.Count); Assert.Contains(dependencies.Dependencies, d => d.GetType() == typeof(DependencyTransientScope)); } [Fact] - public async ValueTask Scope() + public void Scope() { - await using var container = new Container(); + using var container = new Container(); var dependencies = container.Create2(); Assert.Equal(1, dependencies.Dependencies.Count); Assert.Contains(dependencies.Dependencies, d => d.GetType() == typeof(DependencyScope)); diff --git a/Test/Scoping/TransientScopeInstance/InContainer.cs b/Test/Scoping/TransientScopeInstance/InContainer.cs index b6e2b7d2..ee1639aa 100644 --- a/Test/Scoping/TransientScopeInstance/InContainer.cs +++ b/Test/Scoping/TransientScopeInstance/InContainer.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -17,9 +16,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.IsType(instance); } diff --git a/Test/Scoping/TransientScopeInstance/InScope.cs b/Test/Scoping/TransientScopeInstance/InScope.cs index 7962ec93..068874cc 100644 --- a/Test/Scoping/TransientScopeInstance/InScope.cs +++ b/Test/Scoping/TransientScopeInstance/InScope.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -23,9 +22,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var scopeRoot = container.Create(); Assert.IsType(scopeRoot.Dependency); } diff --git a/Test/Scoping/TransientScopeInstance/InScopeInScope.cs b/Test/Scoping/TransientScopeInstance/InScopeInScope.cs index dfb3867d..9fbefb45 100644 --- a/Test/Scoping/TransientScopeInstance/InScopeInScope.cs +++ b/Test/Scoping/TransientScopeInstance/InScopeInScope.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -29,9 +28,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var scopeRoot = container.Create(); Assert.IsType(scopeRoot.InnerScope.Dependency); } diff --git a/Test/Scoping/TransientScopeInstance/InTransientScope.cs b/Test/Scoping/TransientScopeInstance/InTransientScope.cs index 971eb5b0..4a7e0117 100644 --- a/Test/Scoping/TransientScopeInstance/InTransientScope.cs +++ b/Test/Scoping/TransientScopeInstance/InTransientScope.cs @@ -1,5 +1,4 @@ using System; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -39,9 +38,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var transientScopeRoot = container.Create(); Assert.IsType(transientScopeRoot.Dependency); Assert.False(transientScopeRoot.Dependency.IsDisposed); diff --git a/Test/Scoping/TransientScopeInstance/InTransientScopeWithScopes.cs b/Test/Scoping/TransientScopeInstance/InTransientScopeWithScopes.cs index dcefab21..77a7641d 100644 --- a/Test/Scoping/TransientScopeInstance/InTransientScopeWithScopes.cs +++ b/Test/Scoping/TransientScopeInstance/InTransientScopeWithScopes.cs @@ -1,5 +1,4 @@ using System; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -66,9 +65,9 @@ internal sealed partial class Container public partial class Tests { [Fact] - public async ValueTask TransientScopeWithScopes() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var transientScopeRoot = container.Create(); Assert.NotEqual(transientScopeRoot.A, transientScopeRoot.B); Assert.Equal(transientScopeRoot.A.TransientScopeInstance, transientScopeRoot.B.TransientScopeInstance); diff --git a/Test/Struct/NoExplicitConstructor.cs b/Test/Struct/NoExplicitConstructor.cs index d817ab57..04a38249 100644 --- a/Test/Struct/NoExplicitConstructor.cs +++ b/Test/Struct/NoExplicitConstructor.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -12,9 +11,9 @@ internal sealed partial class Container { } public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var value = container.Create(); Assert.IsType(value); } diff --git a/Test/Struct/OneExplicitConstructor.cs b/Test/Struct/OneExplicitConstructor.cs index 9923e273..c5a71533 100644 --- a/Test/Struct/OneExplicitConstructor.cs +++ b/Test/Struct/OneExplicitConstructor.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -19,9 +18,9 @@ internal sealed partial class Container { } public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var value = container.Create(); Assert.IsType(value); Assert.NotNull(value.Inner); diff --git a/Test/Struct/RangedInScope.cs b/Test/Struct/RangedInScope.cs index 901c0b61..f0b73ad7 100644 --- a/Test/Struct/RangedInScope.cs +++ b/Test/Struct/RangedInScope.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -21,9 +20,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var value = container.Create(); Assert.IsType(value); Assert.Equal(23, value.Value); diff --git a/Test/Struct/RecordNoExplicitConstructor.cs b/Test/Struct/RecordNoExplicitConstructor.cs index d91f514a..2cf8538e 100644 --- a/Test/Struct/RecordNoExplicitConstructor.cs +++ b/Test/Struct/RecordNoExplicitConstructor.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -12,9 +11,9 @@ internal sealed partial class Container { } public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var value = container.Create(); Assert.IsType(value); } diff --git a/Test/Struct/RecordOneExplicitConstructor.cs b/Test/Struct/RecordOneExplicitConstructor.cs index dac94558..567cac38 100644 --- a/Test/Struct/RecordOneExplicitConstructor.cs +++ b/Test/Struct/RecordOneExplicitConstructor.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -14,9 +13,9 @@ internal sealed partial class Container { } public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var value = container.Create(); Assert.IsType(value); Assert.NotNull(value.Inner); diff --git a/Test/Tuple/NonSyntaxVariant.cs b/Test/Tuple/NonSyntaxVariant.cs index 60e35873..292546e7 100644 --- a/Test/Tuple/NonSyntaxVariant.cs +++ b/Test/Tuple/NonSyntaxVariant.cs @@ -1,5 +1,4 @@ using System; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -27,15 +26,15 @@ internal sealed partial class Container { private int _i; - private int DIE_Counter() => _i++; + private int DIE_Factory_Counter() => _i++; } public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var nonSyntaxValueTupleBase = container.Create(); Assert.Equal(25, nonSyntaxValueTupleBase.Dependency.Rest.Rest.Rest.Item5); } diff --git a/Test/Tuple/NonSyntaxVariantSingleItem.cs b/Test/Tuple/NonSyntaxVariantSingleItem.cs index db531904..d8c3d20d 100644 --- a/Test/Tuple/NonSyntaxVariantSingleItem.cs +++ b/Test/Tuple/NonSyntaxVariantSingleItem.cs @@ -1,5 +1,4 @@ using System; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -21,15 +20,15 @@ internal sealed partial class Container { private int _i; - private int DIE_Counter() => _i++; + private int DIE_Factory_Counter() => _i++; } public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var wrapper = container.Create(); Assert.Equal(0, wrapper.Dependency.Item1); } diff --git a/Test/Tuple/TupleTests.cs b/Test/Tuple/TupleTests.cs index eb9e4167..3eabc2d4 100644 --- a/Test/Tuple/TupleTests.cs +++ b/Test/Tuple/TupleTests.cs @@ -1,5 +1,4 @@ using System; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -21,15 +20,15 @@ internal sealed partial class Container { private int _i; - private int DIE_Counter() => _i++; + private int DIE_Factory_Counter() => _i++; } public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var wrapper = container.Create(); Assert.Equal(1, wrapper.Dependency.Item2); } diff --git a/Test/UserDefinedElements/FactoryField/InContainercs.cs b/Test/UserDefinedElements/FactoryField/InContainercs.cs index 1078edb7..bf51d507 100644 --- a/Test/UserDefinedElements/FactoryField/InContainercs.cs +++ b/Test/UserDefinedElements/FactoryField/InContainercs.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -21,9 +20,9 @@ public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var wrapper = container.Create(); Assert.Equal("Yeah", wrapper.Property); } diff --git a/Test/UserDefinedElements/FactoryField/InScope.cs b/Test/UserDefinedElements/FactoryField/InScope.cs index f61e3b27..769736cd 100644 --- a/Test/UserDefinedElements/FactoryField/InScope.cs +++ b/Test/UserDefinedElements/FactoryField/InScope.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -24,9 +23,9 @@ public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var scopeRoot = container.Create(); Assert.Equal("Yeah", scopeRoot.Property); } diff --git a/Test/UserDefinedElements/FactoryField/InTransientScope.cs b/Test/UserDefinedElements/FactoryField/InTransientScope.cs index 171012ea..8c189516 100644 --- a/Test/UserDefinedElements/FactoryField/InTransientScope.cs +++ b/Test/UserDefinedElements/FactoryField/InTransientScope.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -24,9 +23,9 @@ public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var transientScopeRoot = container.Create(); Assert.Equal("Yeah", transientScopeRoot.Property); } diff --git a/Test/UserDefinedElements/FactoryMethod/InContainercs.cs b/Test/UserDefinedElements/FactoryMethod/InContainercs.cs index 775ec8be..3dbe2b22 100644 --- a/Test/UserDefinedElements/FactoryMethod/InContainercs.cs +++ b/Test/UserDefinedElements/FactoryMethod/InContainercs.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -21,9 +20,9 @@ public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var wrapper = container.Create(); Assert.Equal("Yeah", wrapper.Property); } diff --git a/Test/UserDefinedElements/FactoryMethod/InScope.cs b/Test/UserDefinedElements/FactoryMethod/InScope.cs index 726695be..cfb3ee6a 100644 --- a/Test/UserDefinedElements/FactoryMethod/InScope.cs +++ b/Test/UserDefinedElements/FactoryMethod/InScope.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -24,9 +23,9 @@ public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var scopeRoot = container.Create(); Assert.Equal("Yeah", scopeRoot.Property); } diff --git a/Test/UserDefinedElements/FactoryMethod/InTransientScope.cs b/Test/UserDefinedElements/FactoryMethod/InTransientScope.cs index 0c26a143..cff63f05 100644 --- a/Test/UserDefinedElements/FactoryMethod/InTransientScope.cs +++ b/Test/UserDefinedElements/FactoryMethod/InTransientScope.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -24,9 +23,9 @@ public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var transientScopeRoot = container.Create(); Assert.Equal("Yeah", transientScopeRoot.Property); } diff --git a/Test/UserDefinedElements/FactoryMethod/WithParameterInContainercs.cs b/Test/UserDefinedElements/FactoryMethod/WithParameterInContainercs.cs index 3277b7f8..3f38149c 100644 --- a/Test/UserDefinedElements/FactoryMethod/WithParameterInContainercs.cs +++ b/Test/UserDefinedElements/FactoryMethod/WithParameterInContainercs.cs @@ -1,5 +1,4 @@ using System.IO; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -17,9 +16,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var fileInfo = container.Create(); Assert.Equal("C:\\Yeah.txt", fileInfo.FullName); } diff --git a/Test/UserDefinedElements/FactoryMethod/WithParameterInScope.cs b/Test/UserDefinedElements/FactoryMethod/WithParameterInScope.cs index 54b39551..5a36a5cc 100644 --- a/Test/UserDefinedElements/FactoryMethod/WithParameterInScope.cs +++ b/Test/UserDefinedElements/FactoryMethod/WithParameterInScope.cs @@ -1,5 +1,4 @@ using System.IO; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -25,9 +24,9 @@ private sealed partial class DIE_DefaultScope public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var scopeRoot = container.Create(); Assert.Equal("C:\\Yeah.txt", scopeRoot.Property.FullName); } diff --git a/Test/UserDefinedElements/FactoryMethod/WithParameterInTransientScope.cs b/Test/UserDefinedElements/FactoryMethod/WithParameterInTransientScope.cs index a6988e7f..7ba91ae3 100644 --- a/Test/UserDefinedElements/FactoryMethod/WithParameterInTransientScope.cs +++ b/Test/UserDefinedElements/FactoryMethod/WithParameterInTransientScope.cs @@ -1,5 +1,4 @@ using System.IO; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -25,9 +24,9 @@ private sealed partial class DIE_DefaultTransientScope public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var transientScopeRoot = container.Create(); Assert.Equal("C:\\Yeah.txt", transientScopeRoot.Property.FullName); } diff --git a/Test/UserDefinedElements/FactoryProperty/InContainer.cs b/Test/UserDefinedElements/FactoryProperty/InContainer.cs index 1c066a1e..4bb35a2f 100644 --- a/Test/UserDefinedElements/FactoryProperty/InContainer.cs +++ b/Test/UserDefinedElements/FactoryProperty/InContainer.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -21,9 +20,9 @@ public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var wrapper = container.Create(); Assert.Equal("Yeah", wrapper.Property); } diff --git a/Test/UserDefinedElements/FactoryProperty/InScope.cs b/Test/UserDefinedElements/FactoryProperty/InScope.cs index bab2c0cd..41c5cd09 100644 --- a/Test/UserDefinedElements/FactoryProperty/InScope.cs +++ b/Test/UserDefinedElements/FactoryProperty/InScope.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -24,9 +23,9 @@ public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var scopeRoot = container.Create(); Assert.Equal("Yeah", scopeRoot.Property); } diff --git a/Test/UserDefinedElements/FactoryProperty/InTransientScope.cs b/Test/UserDefinedElements/FactoryProperty/InTransientScope.cs index 25f0c913..bb75c03b 100644 --- a/Test/UserDefinedElements/FactoryProperty/InTransientScope.cs +++ b/Test/UserDefinedElements/FactoryProperty/InTransientScope.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -24,9 +23,9 @@ public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var transientScopeRoot = container.Create(); Assert.Equal("Yeah", transientScopeRoot.Property); } diff --git a/Test/UserDefinedElements/InjectionConstrParams/Vanilla.cs b/Test/UserDefinedElements/InjectionConstrParams/Vanilla.cs index 63771d41..b549fc5f 100644 --- a/Test/UserDefinedElements/InjectionConstrParams/Vanilla.cs +++ b/Test/UserDefinedElements/InjectionConstrParams/Vanilla.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -21,9 +20,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.Equal(69, instance.Number); } diff --git a/Test/UserDefinedElements/InjectionConstrParams/VanillaInScope.cs b/Test/UserDefinedElements/InjectionConstrParams/VanillaInScope.cs index 67c34e95..b70527d3 100644 --- a/Test/UserDefinedElements/InjectionConstrParams/VanillaInScope.cs +++ b/Test/UserDefinedElements/InjectionConstrParams/VanillaInScope.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -32,9 +31,9 @@ private sealed partial class DIE_DefaultScope public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create().Dependency; Assert.Equal(69, instance.Number); } diff --git a/Test/UserDefinedElements/InjectionConstrParams/VanillaInTransientScope.cs b/Test/UserDefinedElements/InjectionConstrParams/VanillaInTransientScope.cs index fc4ec87b..c5f6b504 100644 --- a/Test/UserDefinedElements/InjectionConstrParams/VanillaInTransientScope.cs +++ b/Test/UserDefinedElements/InjectionConstrParams/VanillaInTransientScope.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -32,9 +31,9 @@ private sealed partial class DIE_DefaultTransientScope public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create().Dependency; Assert.Equal(69, instance.Number); } diff --git a/Test/UserDefinedElements/InjectionConstrParams/WithDependency.cs b/Test/UserDefinedElements/InjectionConstrParams/WithDependency.cs index 3f8f1970..2779bedf 100644 --- a/Test/UserDefinedElements/InjectionConstrParams/WithDependency.cs +++ b/Test/UserDefinedElements/InjectionConstrParams/WithDependency.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -26,9 +25,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.Equal(69, instance.Number); } diff --git a/Test/UserDefinedElements/InjectionConstrParams/WithDependencyInScope.cs b/Test/UserDefinedElements/InjectionConstrParams/WithDependencyInScope.cs index 52953ba0..89103f5e 100644 --- a/Test/UserDefinedElements/InjectionConstrParams/WithDependencyInScope.cs +++ b/Test/UserDefinedElements/InjectionConstrParams/WithDependencyInScope.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -37,9 +36,9 @@ private sealed partial class DIE_DefaultScope public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.Equal(69, instance.Dependency.Number); } diff --git a/Test/UserDefinedElements/InjectionConstrParams/WithDependencyInTransientScope.cs b/Test/UserDefinedElements/InjectionConstrParams/WithDependencyInTransientScope.cs index 50ed9aac..71d8d163 100644 --- a/Test/UserDefinedElements/InjectionConstrParams/WithDependencyInTransientScope.cs +++ b/Test/UserDefinedElements/InjectionConstrParams/WithDependencyInTransientScope.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -37,9 +36,9 @@ private sealed partial class DIE_DefaultTransientScope public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.Equal(69, instance.Dependency.Number); } diff --git a/Test/UserDefinedElements/InjectionInitParams/Vanilla.cs b/Test/UserDefinedElements/InjectionInitParams/Vanilla.cs index 43cba0c2..dc432bb6 100644 --- a/Test/UserDefinedElements/InjectionInitParams/Vanilla.cs +++ b/Test/UserDefinedElements/InjectionInitParams/Vanilla.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -22,9 +21,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.Equal(69, instance.Number); } diff --git a/Test/UserDefinedElements/InjectionInitParams/VanillaInScope.cs b/Test/UserDefinedElements/InjectionInitParams/VanillaInScope.cs index 229f66e1..318fbc59 100644 --- a/Test/UserDefinedElements/InjectionInitParams/VanillaInScope.cs +++ b/Test/UserDefinedElements/InjectionInitParams/VanillaInScope.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -33,9 +32,9 @@ private sealed partial class DIE_DefaultScope public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create().Dependency; Assert.Equal(69, instance.Number); } diff --git a/Test/UserDefinedElements/InjectionInitParams/VanillaInTransientScope.cs b/Test/UserDefinedElements/InjectionInitParams/VanillaInTransientScope.cs index e8a30a73..f748893b 100644 --- a/Test/UserDefinedElements/InjectionInitParams/VanillaInTransientScope.cs +++ b/Test/UserDefinedElements/InjectionInitParams/VanillaInTransientScope.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -33,9 +32,9 @@ private sealed partial class DIE_DefaultTransientScope public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create().Dependency; Assert.Equal(69, instance.Number); } diff --git a/Test/UserDefinedElements/InjectionInitParams/WithDependency.cs b/Test/UserDefinedElements/InjectionInitParams/WithDependency.cs index 45a6e3ae..28ce8d62 100644 --- a/Test/UserDefinedElements/InjectionInitParams/WithDependency.cs +++ b/Test/UserDefinedElements/InjectionInitParams/WithDependency.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -27,9 +26,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.Equal(69, instance.Number); } diff --git a/Test/UserDefinedElements/InjectionInitParams/WithDependencyInScope.cs b/Test/UserDefinedElements/InjectionInitParams/WithDependencyInScope.cs index 1f25f459..d8f002fd 100644 --- a/Test/UserDefinedElements/InjectionInitParams/WithDependencyInScope.cs +++ b/Test/UserDefinedElements/InjectionInitParams/WithDependencyInScope.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -38,9 +37,9 @@ private sealed partial class DIE_DefaultScope public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.Equal(69, instance.Dependency.Number); } diff --git a/Test/UserDefinedElements/InjectionInitParams/WithDependencyInTransientScope.cs b/Test/UserDefinedElements/InjectionInitParams/WithDependencyInTransientScope.cs index 25c1f9d8..d7c5afbf 100644 --- a/Test/UserDefinedElements/InjectionInitParams/WithDependencyInTransientScope.cs +++ b/Test/UserDefinedElements/InjectionInitParams/WithDependencyInTransientScope.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -38,9 +37,9 @@ private sealed partial class DIE_DefaultTransientScope public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.Equal(69, instance.Dependency.Number); } diff --git a/Test/UserDefinedElements/InjectionProps/Vanilla.cs b/Test/UserDefinedElements/InjectionProps/Vanilla.cs index e6d305c8..e21c103b 100644 --- a/Test/UserDefinedElements/InjectionProps/Vanilla.cs +++ b/Test/UserDefinedElements/InjectionProps/Vanilla.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -19,9 +18,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.Equal(69, instance.Number); } diff --git a/Test/UserDefinedElements/InjectionProps/VanillaInScope.cs b/Test/UserDefinedElements/InjectionProps/VanillaInScope.cs index 268da8fc..0b8ac251 100644 --- a/Test/UserDefinedElements/InjectionProps/VanillaInScope.cs +++ b/Test/UserDefinedElements/InjectionProps/VanillaInScope.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -30,9 +29,9 @@ private sealed partial class DIE_DefaultScope public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create().Dependency; Assert.Equal(69, instance.Number); } diff --git a/Test/UserDefinedElements/InjectionProps/VanillaInTransientScope.cs b/Test/UserDefinedElements/InjectionProps/VanillaInTransientScope.cs index 0712fc77..197dd2ef 100644 --- a/Test/UserDefinedElements/InjectionProps/VanillaInTransientScope.cs +++ b/Test/UserDefinedElements/InjectionProps/VanillaInTransientScope.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -30,9 +29,9 @@ private sealed partial class DIE_DefaultTransientScope public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create().Dependency; Assert.Equal(69, instance.Number); } diff --git a/Test/UserDefinedElements/InjectionProps/WithDependency.cs b/Test/UserDefinedElements/InjectionProps/WithDependency.cs index 16d51d53..e38bb7a7 100644 --- a/Test/UserDefinedElements/InjectionProps/WithDependency.cs +++ b/Test/UserDefinedElements/InjectionProps/WithDependency.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -24,9 +23,9 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.Equal(69, instance.Number); } diff --git a/Test/UserDefinedElements/InjectionProps/WithDependencyInScope.cs b/Test/UserDefinedElements/InjectionProps/WithDependencyInScope.cs index 2670745f..973b0ac8 100644 --- a/Test/UserDefinedElements/InjectionProps/WithDependencyInScope.cs +++ b/Test/UserDefinedElements/InjectionProps/WithDependencyInScope.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -35,9 +34,9 @@ private sealed partial class DIE_DefaultScope public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.Equal(69, instance.Dependency.Number); } diff --git a/Test/UserDefinedElements/InjectionProps/WithDependencyInTransientScope.cs b/Test/UserDefinedElements/InjectionProps/WithDependencyInTransientScope.cs index 6ebe4d14..d1a875c5 100644 --- a/Test/UserDefinedElements/InjectionProps/WithDependencyInTransientScope.cs +++ b/Test/UserDefinedElements/InjectionProps/WithDependencyInTransientScope.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -35,9 +34,9 @@ private sealed partial class DIE_DefaultTransientScope public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var instance = container.Create(); Assert.Equal(69, instance.Dependency.Number); } diff --git a/Test/ValueTuple/NonSyntaxVariant.cs b/Test/ValueTuple/NonSyntaxVariant.cs index b45fab79..906ca921 100644 --- a/Test/ValueTuple/NonSyntaxVariant.cs +++ b/Test/ValueTuple/NonSyntaxVariant.cs @@ -1,5 +1,4 @@ using System; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -27,15 +26,15 @@ internal sealed partial class Container { private int _i; - private int DIE_Counter() => _i++; + private int DIE_Factory_Counter() => _i++; } public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var nonSyntaxValueTupleBase = container.Create(); Assert.Equal(25, nonSyntaxValueTupleBase.Dependency.Item26); } diff --git a/Test/ValueTuple/NonSyntaxVariantSingleItem.cs b/Test/ValueTuple/NonSyntaxVariantSingleItem.cs index 0b3de5ae..4d790edd 100644 --- a/Test/ValueTuple/NonSyntaxVariantSingleItem.cs +++ b/Test/ValueTuple/NonSyntaxVariantSingleItem.cs @@ -1,5 +1,4 @@ using System; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -21,15 +20,15 @@ internal sealed partial class Container { private int _i; - private int DIE_Counter() => _i++; + private int DIE_Factory_Counter() => _i++; } public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var wrapper = container.Create(); Assert.Equal(0, wrapper.Dependency.Item1); } diff --git a/Test/ValueTuple/SyntaxVariant.cs b/Test/ValueTuple/SyntaxVariant.cs index dfac1277..855edd56 100644 --- a/Test/ValueTuple/SyntaxVariant.cs +++ b/Test/ValueTuple/SyntaxVariant.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -28,15 +27,15 @@ internal sealed partial class Container { private int _i; - private int DIE_Counter() => _i++; + private int DIE_Factory_Counter() => _i++; } public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var valueTupleBase = container.Create(); Assert.Equal(25, valueTupleBase.Dependency._25); } diff --git a/Test/ValueTuple/ValueTupleTests.cs b/Test/ValueTuple/ValueTupleTests.cs index 63b758ce..ac211f38 100644 --- a/Test/ValueTuple/ValueTupleTests.cs +++ b/Test/ValueTuple/ValueTupleTests.cs @@ -1,5 +1,4 @@ using System; -using System.Threading.Tasks; using MrMeeseeks.DIE.Configuration.Attributes; using Xunit; @@ -21,15 +20,15 @@ internal sealed partial class Container { private int _i; - private int DIE_Counter() => _i++; + private int DIE_Factory_Counter() => _i++; } public class Tests { [Fact] - public async ValueTask Test() + public void Test() { - await using var container = new Container(); + using var container = new Container(); var wrapper = container.Create(); Assert.Equal(1, wrapper.Dependency.Item2); } From 3259221813c6816c2a20eb9e1673f3306ad31e28 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sun, 2 Oct 2022 10:38:37 +0200 Subject: [PATCH 160/162] Fixing remaining potential false positive tests due to ValueTask-bug of xUnit --- Test/Async/Awaited/AsyncScopeRootCallAsTask.cs | 2 +- Test/Async/Awaited/AsyncScopeRootCallAsValueTask.cs | 2 +- Test/Async/Awaited/AsyncScopeRootCallAwaited.cs | 2 +- Test/Async/Awaited/ContainerInstanceFunctionAsTask.cs | 2 +- Test/Async/Awaited/ContainerInstanceFunctionAsValueTask.cs | 2 +- Test/Async/Awaited/ScopeInstanceFunctionAsTask.cs | 2 +- Test/Async/Awaited/ScopeInstanceFunctionAsValueTask.cs | 2 +- Test/Async/Awaited/TaskTypeInitializerTask.cs | 2 +- Test/Async/Awaited/TaskTypeInitializerValueTask.cs | 2 +- Test/Async/Awaited/TransientScopeInstanceFunctionAsTask.cs | 2 +- Test/Async/Awaited/TransientScopeInstanceFunctionAsValueTask.cs | 2 +- .../TransientScopeInstanceFunction_DifferentSynchronicity.cs | 2 +- Test/Async/Wrapped/ContainerInstanceFunctionAsTask.cs | 2 +- Test/Async/Wrapped/ContainerInstanceFunctionAsValueTask.cs | 2 +- Test/Async/Wrapped/DecorationChaining.cs | 2 +- Test/Async/Wrapped/Func.cs | 2 +- Test/Async/Wrapped/Lazy.cs | 2 +- Test/Async/Wrapped/ScopeInstanceFunctionAsTask.cs | 2 +- Test/Async/Wrapped/ScopeInstanceFunctionAsValueTask.cs | 2 +- Test/Async/Wrapped/SyncToTask.cs | 2 +- Test/Async/Wrapped/SyncToValueTask.cs | 2 +- Test/Async/Wrapped/TaskCollection.cs | 2 +- Test/Async/Wrapped/TaskComposition.cs | 2 +- Test/Async/Wrapped/TaskToTask.cs | 2 +- Test/Async/Wrapped/TaskToValueTask.cs | 2 +- Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask.cs | 2 +- ...ansientScopeInstanceFunctionAsTask_DifferentSynchronicity.cs | 2 +- Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask.cs | 2 +- ...ntScopeInstanceFunctionAsValueTask_DifferentSynchronicity.cs | 2 +- Test/Async/Wrapped/ValueTaskCollection.cs | 2 +- Test/Async/Wrapped/ValueTaskComposition.cs | 2 +- Test/Async/Wrapped/ValueTaskToTask.cs | 2 +- Test/Async/Wrapped/ValueTaskToValueTask.cs | 2 +- Test/Disposal/Async/InContainer.cs | 2 +- Test/Disposal/Async/InScope.cs | 2 +- Test/Disposal/Async/InScopeInTransientScope.cs | 2 +- Test/Disposal/Async/InTransientScope.cs | 2 +- Test/Disposal/Async/InTransientScopeInTransientScope.cs | 2 +- Test/Disposal/Calls/AsyncOnly.cs | 2 +- Test/Disposal/Calls/Both.cs | 2 +- Test/Disposal/Calls/None.cs | 2 +- Test/Disposal/Calls/SyncOnly.cs | 2 +- Test/Disposal/ContainerUserDefinedAddForDisposal.cs | 2 +- Test/Disposal/ContainerUserDefinedAddForDisposalAsync.cs | 2 +- Test/Disposal/ScopeUserDefinedAddForDisposal.cs | 2 +- Test/Disposal/ScopeUserDefinedAddForDisposalAsync.cs | 2 +- .../AsyncContainerToAsyncDisposalHandle.cs | 2 +- .../NoneContainerToAsyncDisposalHandle.cs | 2 +- .../SyncContainerToAsyncDisposalHandle.cs | 2 +- Test/Disposal/TransientScopeUserDefinedAddForDisposal.cs | 2 +- Test/Disposal/TransientScopeUserDefinedAddForDisposalAsync.cs | 2 +- Test/Generics/Configuration/AsyncTransient.cs | 2 +- Test/Generics/Configuration/AsyncTransientWithJustTransient.cs | 2 +- Test/Generics/Configuration/InitializerImplementationAsync.cs | 2 +- .../Configuration/InitializerImplementationAsyncValue.cs | 2 +- Test/Generics/Configuration/InitializerInterfaceAsync.cs | 2 +- Test/Generics/Configuration/InitializerInterfaceAsyncValue.cs | 2 +- Test/Initializer/AsyncTask.cs | 2 +- Test/Initializer/AsyncValueTask.cs | 2 +- Test/UserDefinedElements/FactoryField/InContainercsTask.cs | 2 +- Test/UserDefinedElements/FactoryField/InContainercsValueTask.cs | 2 +- Test/UserDefinedElements/FactoryMethod/InContainercsTask.cs | 2 +- .../UserDefinedElements/FactoryMethod/InContainercsValueTask.cs | 2 +- Test/UserDefinedElements/FactoryProperty/InContainerTask.cs | 2 +- .../UserDefinedElements/FactoryProperty/InContainerValueTask.cs | 2 +- .../InjectionConstrParams/WithAsyncDependency.cs | 2 +- .../InjectionConstrParams/WithAsyncDependencyInScope.cs | 2 +- .../WithAsyncDependencyInTransientScope.cs | 2 +- .../InjectionInitParams/WithAsyncDependency.cs | 2 +- .../InjectionInitParams/WithAsyncDependencyInScope.cs | 2 +- .../InjectionInitParams/WithAsyncDependencyInTransientScope.cs | 2 +- Test/UserDefinedElements/InjectionProps/WithAsyncDependency.cs | 2 +- .../InjectionProps/WithAsyncDependencyInScope.cs | 2 +- .../InjectionProps/WithAsyncDependencyInTransientScope.cs | 2 +- 74 files changed, 74 insertions(+), 74 deletions(-) diff --git a/Test/Async/Awaited/AsyncScopeRootCallAsTask.cs b/Test/Async/Awaited/AsyncScopeRootCallAsTask.cs index 5e3a933b..78c6883d 100644 --- a/Test/Async/Awaited/AsyncScopeRootCallAsTask.cs +++ b/Test/Async/Awaited/AsyncScopeRootCallAsTask.cs @@ -33,7 +33,7 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var root = await container.Create().ConfigureAwait(false); diff --git a/Test/Async/Awaited/AsyncScopeRootCallAsValueTask.cs b/Test/Async/Awaited/AsyncScopeRootCallAsValueTask.cs index 71fb5250..beacba57 100644 --- a/Test/Async/Awaited/AsyncScopeRootCallAsValueTask.cs +++ b/Test/Async/Awaited/AsyncScopeRootCallAsValueTask.cs @@ -33,7 +33,7 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var root = await container.Create().ConfigureAwait(false); diff --git a/Test/Async/Awaited/AsyncScopeRootCallAwaited.cs b/Test/Async/Awaited/AsyncScopeRootCallAwaited.cs index fd3ba33c..37d94f0f 100644 --- a/Test/Async/Awaited/AsyncScopeRootCallAwaited.cs +++ b/Test/Async/Awaited/AsyncScopeRootCallAwaited.cs @@ -33,7 +33,7 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var root = await container.CreateValueAsync().ConfigureAwait(false); diff --git a/Test/Async/Awaited/ContainerInstanceFunctionAsTask.cs b/Test/Async/Awaited/ContainerInstanceFunctionAsTask.cs index bd2dc127..7624ecf5 100644 --- a/Test/Async/Awaited/ContainerInstanceFunctionAsTask.cs +++ b/Test/Async/Awaited/ContainerInstanceFunctionAsTask.cs @@ -24,7 +24,7 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var instance = container.CreateValueAsync(); diff --git a/Test/Async/Awaited/ContainerInstanceFunctionAsValueTask.cs b/Test/Async/Awaited/ContainerInstanceFunctionAsValueTask.cs index df08f47b..95ee3a33 100644 --- a/Test/Async/Awaited/ContainerInstanceFunctionAsValueTask.cs +++ b/Test/Async/Awaited/ContainerInstanceFunctionAsValueTask.cs @@ -24,7 +24,7 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var instance = container.CreateValueAsync(); diff --git a/Test/Async/Awaited/ScopeInstanceFunctionAsTask.cs b/Test/Async/Awaited/ScopeInstanceFunctionAsTask.cs index 54be62d9..1022a605 100644 --- a/Test/Async/Awaited/ScopeInstanceFunctionAsTask.cs +++ b/Test/Async/Awaited/ScopeInstanceFunctionAsTask.cs @@ -24,7 +24,7 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var instance = container.CreateValueAsync(); diff --git a/Test/Async/Awaited/ScopeInstanceFunctionAsValueTask.cs b/Test/Async/Awaited/ScopeInstanceFunctionAsValueTask.cs index 735b7628..de3e862c 100644 --- a/Test/Async/Awaited/ScopeInstanceFunctionAsValueTask.cs +++ b/Test/Async/Awaited/ScopeInstanceFunctionAsValueTask.cs @@ -24,7 +24,7 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var instance = container.CreateValueAsync(); diff --git a/Test/Async/Awaited/TaskTypeInitializerTask.cs b/Test/Async/Awaited/TaskTypeInitializerTask.cs index fd820365..ee31db1c 100644 --- a/Test/Async/Awaited/TaskTypeInitializerTask.cs +++ b/Test/Async/Awaited/TaskTypeInitializerTask.cs @@ -24,7 +24,7 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var instance = await container.CreateAsync().ConfigureAwait(false); diff --git a/Test/Async/Awaited/TaskTypeInitializerValueTask.cs b/Test/Async/Awaited/TaskTypeInitializerValueTask.cs index e64dbf5d..0dc75380 100644 --- a/Test/Async/Awaited/TaskTypeInitializerValueTask.cs +++ b/Test/Async/Awaited/TaskTypeInitializerValueTask.cs @@ -24,7 +24,7 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var instance = await container.CreateAsync().ConfigureAwait(false); diff --git a/Test/Async/Awaited/TransientScopeInstanceFunctionAsTask.cs b/Test/Async/Awaited/TransientScopeInstanceFunctionAsTask.cs index ead39ca5..c601e01a 100644 --- a/Test/Async/Awaited/TransientScopeInstanceFunctionAsTask.cs +++ b/Test/Async/Awaited/TransientScopeInstanceFunctionAsTask.cs @@ -23,7 +23,7 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var instance = container.CreateValueAsync(); diff --git a/Test/Async/Awaited/TransientScopeInstanceFunctionAsValueTask.cs b/Test/Async/Awaited/TransientScopeInstanceFunctionAsValueTask.cs index a03e0f70..bf0f30cb 100644 --- a/Test/Async/Awaited/TransientScopeInstanceFunctionAsValueTask.cs +++ b/Test/Async/Awaited/TransientScopeInstanceFunctionAsValueTask.cs @@ -23,7 +23,7 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var instance = container.CreateValueAsync(); diff --git a/Test/Async/Awaited/TransientScopeInstanceFunction_DifferentSynchronicity.cs b/Test/Async/Awaited/TransientScopeInstanceFunction_DifferentSynchronicity.cs index 7e0d7080..4372cdc9 100644 --- a/Test/Async/Awaited/TransientScopeInstanceFunction_DifferentSynchronicity.cs +++ b/Test/Async/Awaited/TransientScopeInstanceFunction_DifferentSynchronicity.cs @@ -72,7 +72,7 @@ private sealed partial class DIE_TransientScope1 public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var instance0 = container.Create0ValueAsync(); diff --git a/Test/Async/Wrapped/ContainerInstanceFunctionAsTask.cs b/Test/Async/Wrapped/ContainerInstanceFunctionAsTask.cs index 80d5eb83..121140b9 100644 --- a/Test/Async/Wrapped/ContainerInstanceFunctionAsTask.cs +++ b/Test/Async/Wrapped/ContainerInstanceFunctionAsTask.cs @@ -24,7 +24,7 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var instance = container.Create(); diff --git a/Test/Async/Wrapped/ContainerInstanceFunctionAsValueTask.cs b/Test/Async/Wrapped/ContainerInstanceFunctionAsValueTask.cs index 4210e742..894d6231 100644 --- a/Test/Async/Wrapped/ContainerInstanceFunctionAsValueTask.cs +++ b/Test/Async/Wrapped/ContainerInstanceFunctionAsValueTask.cs @@ -24,7 +24,7 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var instance = container.Create(); diff --git a/Test/Async/Wrapped/DecorationChaining.cs b/Test/Async/Wrapped/DecorationChaining.cs index 78fc9241..70b297fa 100644 --- a/Test/Async/Wrapped/DecorationChaining.cs +++ b/Test/Async/Wrapped/DecorationChaining.cs @@ -56,7 +56,7 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var instance = await container.Create().ConfigureAwait(false); diff --git a/Test/Async/Wrapped/Func.cs b/Test/Async/Wrapped/Func.cs index fb34b8b3..f9482b47 100644 --- a/Test/Async/Wrapped/Func.cs +++ b/Test/Async/Wrapped/Func.cs @@ -25,7 +25,7 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var instance = container.Create(); diff --git a/Test/Async/Wrapped/Lazy.cs b/Test/Async/Wrapped/Lazy.cs index 09f73dfc..73b5ac69 100644 --- a/Test/Async/Wrapped/Lazy.cs +++ b/Test/Async/Wrapped/Lazy.cs @@ -24,7 +24,7 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var instance = container.Create(); diff --git a/Test/Async/Wrapped/ScopeInstanceFunctionAsTask.cs b/Test/Async/Wrapped/ScopeInstanceFunctionAsTask.cs index 33f3da1d..544fcafa 100644 --- a/Test/Async/Wrapped/ScopeInstanceFunctionAsTask.cs +++ b/Test/Async/Wrapped/ScopeInstanceFunctionAsTask.cs @@ -24,7 +24,7 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var instance = container.Create(); diff --git a/Test/Async/Wrapped/ScopeInstanceFunctionAsValueTask.cs b/Test/Async/Wrapped/ScopeInstanceFunctionAsValueTask.cs index 7fec55fc..1f07583f 100644 --- a/Test/Async/Wrapped/ScopeInstanceFunctionAsValueTask.cs +++ b/Test/Async/Wrapped/ScopeInstanceFunctionAsValueTask.cs @@ -24,7 +24,7 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var instance = container.Create(); diff --git a/Test/Async/Wrapped/SyncToTask.cs b/Test/Async/Wrapped/SyncToTask.cs index 17bf4a0a..a85a8443 100644 --- a/Test/Async/Wrapped/SyncToTask.cs +++ b/Test/Async/Wrapped/SyncToTask.cs @@ -22,7 +22,7 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var instance = await container.Create().ConfigureAwait(false); diff --git a/Test/Async/Wrapped/SyncToValueTask.cs b/Test/Async/Wrapped/SyncToValueTask.cs index 0fc9d3bf..226fd908 100644 --- a/Test/Async/Wrapped/SyncToValueTask.cs +++ b/Test/Async/Wrapped/SyncToValueTask.cs @@ -22,7 +22,7 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var instance = await container.Create().ConfigureAwait(false); diff --git a/Test/Async/Wrapped/TaskCollection.cs b/Test/Async/Wrapped/TaskCollection.cs index 3ab6d7d1..27724845 100644 --- a/Test/Async/Wrapped/TaskCollection.cs +++ b/Test/Async/Wrapped/TaskCollection.cs @@ -55,7 +55,7 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var instance = container.Create(); diff --git a/Test/Async/Wrapped/TaskComposition.cs b/Test/Async/Wrapped/TaskComposition.cs index 807c7329..88ac39ce 100644 --- a/Test/Async/Wrapped/TaskComposition.cs +++ b/Test/Async/Wrapped/TaskComposition.cs @@ -74,7 +74,7 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var instance = await container.Create().ConfigureAwait(false); diff --git a/Test/Async/Wrapped/TaskToTask.cs b/Test/Async/Wrapped/TaskToTask.cs index f746452f..35137b7f 100644 --- a/Test/Async/Wrapped/TaskToTask.cs +++ b/Test/Async/Wrapped/TaskToTask.cs @@ -23,7 +23,7 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var instance = await container.Create().ConfigureAwait(false); diff --git a/Test/Async/Wrapped/TaskToValueTask.cs b/Test/Async/Wrapped/TaskToValueTask.cs index 6c62c48c..a32f76e6 100644 --- a/Test/Async/Wrapped/TaskToValueTask.cs +++ b/Test/Async/Wrapped/TaskToValueTask.cs @@ -24,7 +24,7 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var instance = await container.Create().ConfigureAwait(false); diff --git a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask.cs b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask.cs index 4e442c01..33b31b2b 100644 --- a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask.cs +++ b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask.cs @@ -23,7 +23,7 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var instance = container.Create(); diff --git a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask_DifferentSynchronicity.cs b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask_DifferentSynchronicity.cs index 65cf59db..552a4d82 100644 --- a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask_DifferentSynchronicity.cs +++ b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsTask_DifferentSynchronicity.cs @@ -72,7 +72,7 @@ private sealed partial class DIE_TransientScope1 public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var instance0 = container.Create0(); diff --git a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask.cs b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask.cs index 1a4d28d7..773f1d31 100644 --- a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask.cs +++ b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask.cs @@ -23,7 +23,7 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var instance = container.Create(); diff --git a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask_DifferentSynchronicity.cs b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask_DifferentSynchronicity.cs index a0406c0e..53dcec00 100644 --- a/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask_DifferentSynchronicity.cs +++ b/Test/Async/Wrapped/TransientScopeInstanceFunctionAsValueTask_DifferentSynchronicity.cs @@ -72,7 +72,7 @@ private sealed partial class DIE_TransientScope1 public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var instance0 = container.Create0(); diff --git a/Test/Async/Wrapped/ValueTaskCollection.cs b/Test/Async/Wrapped/ValueTaskCollection.cs index 5358e80f..982ca7ee 100644 --- a/Test/Async/Wrapped/ValueTaskCollection.cs +++ b/Test/Async/Wrapped/ValueTaskCollection.cs @@ -55,7 +55,7 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var instance = container.Create(); diff --git a/Test/Async/Wrapped/ValueTaskComposition.cs b/Test/Async/Wrapped/ValueTaskComposition.cs index e231d8ea..c53c2b6a 100644 --- a/Test/Async/Wrapped/ValueTaskComposition.cs +++ b/Test/Async/Wrapped/ValueTaskComposition.cs @@ -75,7 +75,7 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var instance = await container.Create().ConfigureAwait(false); diff --git a/Test/Async/Wrapped/ValueTaskToTask.cs b/Test/Async/Wrapped/ValueTaskToTask.cs index 7c49ab8c..8f1004ed 100644 --- a/Test/Async/Wrapped/ValueTaskToTask.cs +++ b/Test/Async/Wrapped/ValueTaskToTask.cs @@ -24,7 +24,7 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var instance = await container.Create().ConfigureAwait(false); diff --git a/Test/Async/Wrapped/ValueTaskToValueTask.cs b/Test/Async/Wrapped/ValueTaskToValueTask.cs index bd265997..01402736 100644 --- a/Test/Async/Wrapped/ValueTaskToValueTask.cs +++ b/Test/Async/Wrapped/ValueTaskToValueTask.cs @@ -24,7 +24,7 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var instance = await container.Create().ConfigureAwait(false); diff --git a/Test/Disposal/Async/InContainer.cs b/Test/Disposal/Async/InContainer.cs index b67497f7..b7ef4714 100644 --- a/Test/Disposal/Async/InContainer.cs +++ b/Test/Disposal/Async/InContainer.cs @@ -25,7 +25,7 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var dependency = container.Create(); diff --git a/Test/Disposal/Async/InScope.cs b/Test/Disposal/Async/InScope.cs index b0c8b5e2..54edb54f 100644 --- a/Test/Disposal/Async/InScope.cs +++ b/Test/Disposal/Async/InScope.cs @@ -32,7 +32,7 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var dependency = container.Create(); diff --git a/Test/Disposal/Async/InScopeInTransientScope.cs b/Test/Disposal/Async/InScopeInTransientScope.cs index 9c88feef..49c4f45a 100644 --- a/Test/Disposal/Async/InScopeInTransientScope.cs +++ b/Test/Disposal/Async/InScopeInTransientScope.cs @@ -48,7 +48,7 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var transientScopeRoot = container.Create(); diff --git a/Test/Disposal/Async/InTransientScope.cs b/Test/Disposal/Async/InTransientScope.cs index 820ef323..e4616a9b 100644 --- a/Test/Disposal/Async/InTransientScope.cs +++ b/Test/Disposal/Async/InTransientScope.cs @@ -32,7 +32,7 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var dependency = container.Create(); diff --git a/Test/Disposal/Async/InTransientScopeInTransientScope.cs b/Test/Disposal/Async/InTransientScopeInTransientScope.cs index dae27a0a..78184f8b 100644 --- a/Test/Disposal/Async/InTransientScopeInTransientScope.cs +++ b/Test/Disposal/Async/InTransientScopeInTransientScope.cs @@ -51,7 +51,7 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var transientScopeRoot = container.Create(); diff --git a/Test/Disposal/Calls/AsyncOnly.cs b/Test/Disposal/Calls/AsyncOnly.cs index c7bab767..2329bf03 100644 --- a/Test/Disposal/Calls/AsyncOnly.cs +++ b/Test/Disposal/Calls/AsyncOnly.cs @@ -32,7 +32,7 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var dependency = container.Create(); diff --git a/Test/Disposal/Calls/Both.cs b/Test/Disposal/Calls/Both.cs index cee2b2d0..9614d2b5 100644 --- a/Test/Disposal/Calls/Both.cs +++ b/Test/Disposal/Calls/Both.cs @@ -32,7 +32,7 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var dependency = container.Create(); diff --git a/Test/Disposal/Calls/None.cs b/Test/Disposal/Calls/None.cs index a5c23093..916fcfd4 100644 --- a/Test/Disposal/Calls/None.cs +++ b/Test/Disposal/Calls/None.cs @@ -32,7 +32,7 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var dependency = container.Create(); diff --git a/Test/Disposal/Calls/SyncOnly.cs b/Test/Disposal/Calls/SyncOnly.cs index b2968526..075414ed 100644 --- a/Test/Disposal/Calls/SyncOnly.cs +++ b/Test/Disposal/Calls/SyncOnly.cs @@ -32,7 +32,7 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var dependency = container.Create(); diff --git a/Test/Disposal/ContainerUserDefinedAddForDisposal.cs b/Test/Disposal/ContainerUserDefinedAddForDisposal.cs index e297fe05..e704d745 100644 --- a/Test/Disposal/ContainerUserDefinedAddForDisposal.cs +++ b/Test/Disposal/ContainerUserDefinedAddForDisposal.cs @@ -31,7 +31,7 @@ private Dependency DIE_Factory_Dependency public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var instance = container.Create(); diff --git a/Test/Disposal/ContainerUserDefinedAddForDisposalAsync.cs b/Test/Disposal/ContainerUserDefinedAddForDisposalAsync.cs index bfacd5b2..e4bfd07f 100644 --- a/Test/Disposal/ContainerUserDefinedAddForDisposalAsync.cs +++ b/Test/Disposal/ContainerUserDefinedAddForDisposalAsync.cs @@ -35,7 +35,7 @@ private Dependency DIE_Factory_Dependency public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var instance = container.Create(); diff --git a/Test/Disposal/ScopeUserDefinedAddForDisposal.cs b/Test/Disposal/ScopeUserDefinedAddForDisposal.cs index 1f63d7d9..b0e32b8e 100644 --- a/Test/Disposal/ScopeUserDefinedAddForDisposal.cs +++ b/Test/Disposal/ScopeUserDefinedAddForDisposal.cs @@ -44,7 +44,7 @@ private Dependency DIE_Factory_Dependency public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var root = container.Create(); diff --git a/Test/Disposal/ScopeUserDefinedAddForDisposalAsync.cs b/Test/Disposal/ScopeUserDefinedAddForDisposalAsync.cs index 8313eb35..69fa6430 100644 --- a/Test/Disposal/ScopeUserDefinedAddForDisposalAsync.cs +++ b/Test/Disposal/ScopeUserDefinedAddForDisposalAsync.cs @@ -48,7 +48,7 @@ private Dependency DIE_Factory_Dependency public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var instance = container.Create(); diff --git a/Test/Disposal/TransientScopeDisposalHandle/AsyncContainerToAsyncDisposalHandle.cs b/Test/Disposal/TransientScopeDisposalHandle/AsyncContainerToAsyncDisposalHandle.cs index 39956b8a..14521c45 100644 --- a/Test/Disposal/TransientScopeDisposalHandle/AsyncContainerToAsyncDisposalHandle.cs +++ b/Test/Disposal/TransientScopeDisposalHandle/AsyncContainerToAsyncDisposalHandle.cs @@ -38,7 +38,7 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var transientScopeRoot = container.Create(); diff --git a/Test/Disposal/TransientScopeDisposalHandle/NoneContainerToAsyncDisposalHandle.cs b/Test/Disposal/TransientScopeDisposalHandle/NoneContainerToAsyncDisposalHandle.cs index 27713fe4..1c6376f2 100644 --- a/Test/Disposal/TransientScopeDisposalHandle/NoneContainerToAsyncDisposalHandle.cs +++ b/Test/Disposal/TransientScopeDisposalHandle/NoneContainerToAsyncDisposalHandle.cs @@ -32,7 +32,7 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { var container = new Container(); var transientScopeRoot = container.Create(); diff --git a/Test/Disposal/TransientScopeDisposalHandle/SyncContainerToAsyncDisposalHandle.cs b/Test/Disposal/TransientScopeDisposalHandle/SyncContainerToAsyncDisposalHandle.cs index 34c72bfb..497dc5b0 100644 --- a/Test/Disposal/TransientScopeDisposalHandle/SyncContainerToAsyncDisposalHandle.cs +++ b/Test/Disposal/TransientScopeDisposalHandle/SyncContainerToAsyncDisposalHandle.cs @@ -34,7 +34,7 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { using var container = new Container(); var transientScopeRoot = container.Create(); diff --git a/Test/Disposal/TransientScopeUserDefinedAddForDisposal.cs b/Test/Disposal/TransientScopeUserDefinedAddForDisposal.cs index 394673de..e94003b6 100644 --- a/Test/Disposal/TransientScopeUserDefinedAddForDisposal.cs +++ b/Test/Disposal/TransientScopeUserDefinedAddForDisposal.cs @@ -44,7 +44,7 @@ private Dependency DIE_Factory_Dependency public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var root = container.Create(); diff --git a/Test/Disposal/TransientScopeUserDefinedAddForDisposalAsync.cs b/Test/Disposal/TransientScopeUserDefinedAddForDisposalAsync.cs index 92ef61b8..299343d9 100644 --- a/Test/Disposal/TransientScopeUserDefinedAddForDisposalAsync.cs +++ b/Test/Disposal/TransientScopeUserDefinedAddForDisposalAsync.cs @@ -48,7 +48,7 @@ private Dependency DIE_Factory_Dependency public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var instance = container.Create(); diff --git a/Test/Generics/Configuration/AsyncTransient.cs b/Test/Generics/Configuration/AsyncTransient.cs index c1a0131a..a3471a55 100644 --- a/Test/Generics/Configuration/AsyncTransient.cs +++ b/Test/Generics/Configuration/AsyncTransient.cs @@ -27,7 +27,7 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); await using var instance = container.Create(); diff --git a/Test/Generics/Configuration/AsyncTransientWithJustTransient.cs b/Test/Generics/Configuration/AsyncTransientWithJustTransient.cs index 5d38bdac..06897bf6 100644 --- a/Test/Generics/Configuration/AsyncTransientWithJustTransient.cs +++ b/Test/Generics/Configuration/AsyncTransientWithJustTransient.cs @@ -27,7 +27,7 @@ internal sealed partial class Container {} public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); await using var instance = container.Create(); diff --git a/Test/Generics/Configuration/InitializerImplementationAsync.cs b/Test/Generics/Configuration/InitializerImplementationAsync.cs index b642530d..a3dbaa65 100644 --- a/Test/Generics/Configuration/InitializerImplementationAsync.cs +++ b/Test/Generics/Configuration/InitializerImplementationAsync.cs @@ -25,7 +25,7 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var instance = await container.CreateValueAsync().ConfigureAwait(false); diff --git a/Test/Generics/Configuration/InitializerImplementationAsyncValue.cs b/Test/Generics/Configuration/InitializerImplementationAsyncValue.cs index 6458cb99..bf3c167d 100644 --- a/Test/Generics/Configuration/InitializerImplementationAsyncValue.cs +++ b/Test/Generics/Configuration/InitializerImplementationAsyncValue.cs @@ -25,7 +25,7 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var instance = await container.CreateValueAsync().ConfigureAwait(false); diff --git a/Test/Generics/Configuration/InitializerInterfaceAsync.cs b/Test/Generics/Configuration/InitializerInterfaceAsync.cs index 713b8cad..09857236 100644 --- a/Test/Generics/Configuration/InitializerInterfaceAsync.cs +++ b/Test/Generics/Configuration/InitializerInterfaceAsync.cs @@ -24,7 +24,7 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var instance = await container.CreateValueAsync().ConfigureAwait(false); diff --git a/Test/Generics/Configuration/InitializerInterfaceAsyncValue.cs b/Test/Generics/Configuration/InitializerInterfaceAsyncValue.cs index df5589f1..764ed86c 100644 --- a/Test/Generics/Configuration/InitializerInterfaceAsyncValue.cs +++ b/Test/Generics/Configuration/InitializerInterfaceAsyncValue.cs @@ -24,7 +24,7 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var instance = await container.CreateValueAsync().ConfigureAwait(false); diff --git a/Test/Initializer/AsyncTask.cs b/Test/Initializer/AsyncTask.cs index 17be0e23..44cb843c 100644 --- a/Test/Initializer/AsyncTask.cs +++ b/Test/Initializer/AsyncTask.cs @@ -23,7 +23,7 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var instance = await container.CreateAsync().ConfigureAwait(false); diff --git a/Test/Initializer/AsyncValueTask.cs b/Test/Initializer/AsyncValueTask.cs index dc7052d2..65c53839 100644 --- a/Test/Initializer/AsyncValueTask.cs +++ b/Test/Initializer/AsyncValueTask.cs @@ -23,7 +23,7 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var instance = await container.CreateValueAsync().ConfigureAwait(false); diff --git a/Test/UserDefinedElements/FactoryField/InContainercsTask.cs b/Test/UserDefinedElements/FactoryField/InContainercsTask.cs index 50a3d607..fa5f83a6 100644 --- a/Test/UserDefinedElements/FactoryField/InContainercsTask.cs +++ b/Test/UserDefinedElements/FactoryField/InContainercsTask.cs @@ -21,7 +21,7 @@ public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var wrapper = container.Create(); diff --git a/Test/UserDefinedElements/FactoryField/InContainercsValueTask.cs b/Test/UserDefinedElements/FactoryField/InContainercsValueTask.cs index 780fd273..6db372e3 100644 --- a/Test/UserDefinedElements/FactoryField/InContainercsValueTask.cs +++ b/Test/UserDefinedElements/FactoryField/InContainercsValueTask.cs @@ -21,7 +21,7 @@ public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var wrapper = await container.CreateValueAsync().ConfigureAwait(false); diff --git a/Test/UserDefinedElements/FactoryMethod/InContainercsTask.cs b/Test/UserDefinedElements/FactoryMethod/InContainercsTask.cs index e02b67a6..36fd5723 100644 --- a/Test/UserDefinedElements/FactoryMethod/InContainercsTask.cs +++ b/Test/UserDefinedElements/FactoryMethod/InContainercsTask.cs @@ -21,7 +21,7 @@ public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var wrapper = container.Create(); diff --git a/Test/UserDefinedElements/FactoryMethod/InContainercsValueTask.cs b/Test/UserDefinedElements/FactoryMethod/InContainercsValueTask.cs index ba6d00c9..fa64881f 100644 --- a/Test/UserDefinedElements/FactoryMethod/InContainercsValueTask.cs +++ b/Test/UserDefinedElements/FactoryMethod/InContainercsValueTask.cs @@ -21,7 +21,7 @@ public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var wrapper = await container.CreateValueAsync().ConfigureAwait(false); diff --git a/Test/UserDefinedElements/FactoryProperty/InContainerTask.cs b/Test/UserDefinedElements/FactoryProperty/InContainerTask.cs index 91799a2e..2c96b6f9 100644 --- a/Test/UserDefinedElements/FactoryProperty/InContainerTask.cs +++ b/Test/UserDefinedElements/FactoryProperty/InContainerTask.cs @@ -21,7 +21,7 @@ public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var wrapper = container.Create(); diff --git a/Test/UserDefinedElements/FactoryProperty/InContainerValueTask.cs b/Test/UserDefinedElements/FactoryProperty/InContainerValueTask.cs index a1f25f52..c97a5286 100644 --- a/Test/UserDefinedElements/FactoryProperty/InContainerValueTask.cs +++ b/Test/UserDefinedElements/FactoryProperty/InContainerValueTask.cs @@ -21,7 +21,7 @@ public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var wrapper = await container.CreateValueAsync().ConfigureAwait(false); diff --git a/Test/UserDefinedElements/InjectionConstrParams/WithAsyncDependency.cs b/Test/UserDefinedElements/InjectionConstrParams/WithAsyncDependency.cs index e17c0e2d..a819b5c2 100644 --- a/Test/UserDefinedElements/InjectionConstrParams/WithAsyncDependency.cs +++ b/Test/UserDefinedElements/InjectionConstrParams/WithAsyncDependency.cs @@ -27,7 +27,7 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var instance = await container.CreateAsync().ConfigureAwait(false); diff --git a/Test/UserDefinedElements/InjectionConstrParams/WithAsyncDependencyInScope.cs b/Test/UserDefinedElements/InjectionConstrParams/WithAsyncDependencyInScope.cs index 5cfff15a..898dae04 100644 --- a/Test/UserDefinedElements/InjectionConstrParams/WithAsyncDependencyInScope.cs +++ b/Test/UserDefinedElements/InjectionConstrParams/WithAsyncDependencyInScope.cs @@ -38,7 +38,7 @@ private sealed partial class DIE_DefaultScope public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var instance = await container.CreateAsync().ConfigureAwait(false); diff --git a/Test/UserDefinedElements/InjectionConstrParams/WithAsyncDependencyInTransientScope.cs b/Test/UserDefinedElements/InjectionConstrParams/WithAsyncDependencyInTransientScope.cs index 85135f11..f04e2faf 100644 --- a/Test/UserDefinedElements/InjectionConstrParams/WithAsyncDependencyInTransientScope.cs +++ b/Test/UserDefinedElements/InjectionConstrParams/WithAsyncDependencyInTransientScope.cs @@ -38,7 +38,7 @@ private sealed partial class DIE_DefaultTransientScope public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var instance = await container.CreateAsync().ConfigureAwait(false); diff --git a/Test/UserDefinedElements/InjectionInitParams/WithAsyncDependency.cs b/Test/UserDefinedElements/InjectionInitParams/WithAsyncDependency.cs index 69fb8eda..cbb3aef4 100644 --- a/Test/UserDefinedElements/InjectionInitParams/WithAsyncDependency.cs +++ b/Test/UserDefinedElements/InjectionInitParams/WithAsyncDependency.cs @@ -28,7 +28,7 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var instance = await container.CreateAsync().ConfigureAwait(false); diff --git a/Test/UserDefinedElements/InjectionInitParams/WithAsyncDependencyInScope.cs b/Test/UserDefinedElements/InjectionInitParams/WithAsyncDependencyInScope.cs index a8fc96dc..b2df2c8c 100644 --- a/Test/UserDefinedElements/InjectionInitParams/WithAsyncDependencyInScope.cs +++ b/Test/UserDefinedElements/InjectionInitParams/WithAsyncDependencyInScope.cs @@ -39,7 +39,7 @@ private sealed partial class DIE_DefaultScope public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var instance = await container.CreateAsync().ConfigureAwait(false); diff --git a/Test/UserDefinedElements/InjectionInitParams/WithAsyncDependencyInTransientScope.cs b/Test/UserDefinedElements/InjectionInitParams/WithAsyncDependencyInTransientScope.cs index 217372b3..858f580e 100644 --- a/Test/UserDefinedElements/InjectionInitParams/WithAsyncDependencyInTransientScope.cs +++ b/Test/UserDefinedElements/InjectionInitParams/WithAsyncDependencyInTransientScope.cs @@ -39,7 +39,7 @@ private sealed partial class DIE_DefaultTransientScope public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var instance = await container.CreateAsync().ConfigureAwait(false); diff --git a/Test/UserDefinedElements/InjectionProps/WithAsyncDependency.cs b/Test/UserDefinedElements/InjectionProps/WithAsyncDependency.cs index 7a3a8b06..174af384 100644 --- a/Test/UserDefinedElements/InjectionProps/WithAsyncDependency.cs +++ b/Test/UserDefinedElements/InjectionProps/WithAsyncDependency.cs @@ -25,7 +25,7 @@ internal sealed partial class Container public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var instance = await container.CreateAsync().ConfigureAwait(false); diff --git a/Test/UserDefinedElements/InjectionProps/WithAsyncDependencyInScope.cs b/Test/UserDefinedElements/InjectionProps/WithAsyncDependencyInScope.cs index f063efa5..e73d6889 100644 --- a/Test/UserDefinedElements/InjectionProps/WithAsyncDependencyInScope.cs +++ b/Test/UserDefinedElements/InjectionProps/WithAsyncDependencyInScope.cs @@ -36,7 +36,7 @@ private sealed partial class DIE_DefaultScope public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var instance = await container.CreateAsync().ConfigureAwait(false); diff --git a/Test/UserDefinedElements/InjectionProps/WithAsyncDependencyInTransientScope.cs b/Test/UserDefinedElements/InjectionProps/WithAsyncDependencyInTransientScope.cs index b5d7e30d..5c7e772c 100644 --- a/Test/UserDefinedElements/InjectionProps/WithAsyncDependencyInTransientScope.cs +++ b/Test/UserDefinedElements/InjectionProps/WithAsyncDependencyInTransientScope.cs @@ -36,7 +36,7 @@ private sealed partial class DIE_DefaultTransientScope public class Tests { [Fact] - public async ValueTask Test() + public async Task Test() { await using var container = new Container(); var instance = await container.CreateAsync().ConfigureAwait(false); From 2a4b239f7c81b6c1cbac93aef4b98a9bc002b651 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Sun, 2 Oct 2022 14:17:20 +0200 Subject: [PATCH 161/162] Xml Doc for public attributes --- Main/Configuration/Attributes/Aggregation.cs | 240 +++++++++++++++--- Main/Configuration/Attributes/Choice.cs | 68 ++++- .../Configuration/Attributes/Miscellaneous.cs | 31 +++ 3 files changed, 297 insertions(+), 42 deletions(-) diff --git a/Main/Configuration/Attributes/Aggregation.cs b/Main/Configuration/Attributes/Aggregation.cs index 2b108d88..3b4119b5 100644 --- a/Main/Configuration/Attributes/Aggregation.cs +++ b/Main/Configuration/Attributes/Aggregation.cs @@ -1,250 +1,418 @@ // ReSharper disable UnusedParameter.Local namespace MrMeeseeks.DIE.Configuration.Attributes; +/// +/// Aggregates all implementations of the current assembly and all referenced assemblies. This includes .Net assemblies and assemblies from nuget packages. +/// See https://die.mrmeeseeks.dev/configuration/implementations/ +/// [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = false)] public class AllImplementationsAggregationAttribute : Attribute { } +/// +/// Filters all implementations. +/// See https://die.mrmeeseeks.dev/configuration/implementations/ +/// [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] public class FilterAllImplementationsAggregationAttribute : Attribute { } +/// +/// Aggregates all implementations of a given assembly. Assemblies are passed by referencing any type from the assembly, because assemblies themselves cannot be referenced in code. You may pass multiple types to this attribute. +/// See https://die.mrmeeseeks.dev/configuration/implementations/ +/// [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class AssemblyImplementationsAggregationAttribute : Attribute { public AssemblyImplementationsAggregationAttribute(params Type[] typesFromAssemblies) {} } +/// +/// Filters all implementations of a given assembly. Assemblies are passed by any type from the assembly because assemblies themselves cannot be referenced in code. You may pass multiple types to this attribute. +/// See https://die.mrmeeseeks.dev/configuration/implementations/ +/// [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class FilterAssemblyImplementationsAggregationAttribute : Attribute { public FilterAssemblyImplementationsAggregationAttribute(params Type[] typesFromAssemblies) {} } +/// +/// Aggregates all given implementations. Types passed must be implementations. You may pass multiple types to this attribute. +/// See https://die.mrmeeseeks.dev/configuration/implementations/ +/// [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class ImplementationAggregationAttribute : Attribute { public ImplementationAggregationAttribute(params Type[] types) {} } +/// +/// Filters all given implementations. Types passed must be implementations. You may pass multiple types to this attribute. +/// See https://die.mrmeeseeks.dev/configuration/implementations/ +/// [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class FilterImplementationAggregationAttribute : Attribute { public FilterImplementationAggregationAttribute(params Type[] types) {} } - + +/// +/// For any given abstraction, all of its implementations are completely ignored for disposal management. +/// See https://die.mrmeeseeks.dev/configuration/disposal/ +/// [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class TransientAbstractionAggregationAttribute : Attribute { public TransientAbstractionAggregationAttribute(params Type[] types) {} } - + +/// +/// For each given abstraction, all of its implementations are considered again for disposal management. +/// See https://die.mrmeeseeks.dev/configuration/disposal/ +/// [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class FilterTransientAbstractionAggregationAttribute : Attribute { public FilterTransientAbstractionAggregationAttribute(params Type[] types) {} } - + +/// +/// Any given implementation is completely ignored for disposal management. +/// See https://die.mrmeeseeks.dev/configuration/disposal/ +/// [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class TransientImplementationAggregationAttribute : Attribute { public TransientImplementationAggregationAttribute(params Type[] types) {} } - + +/// +/// Each given implementation will be considered again for disposal management. +/// See https://die.mrmeeseeks.dev/configuration/disposal/ +/// [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class FilterTransientImplementationAggregationAttribute : Attribute { public FilterTransientImplementationAggregationAttribute(params Type[] types) {} } - + +/// +/// For any given abstraction, all of its implementations are ignored for sync disposal management. +/// See https://die.mrmeeseeks.dev/configuration/disposal/ +/// [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class SyncTransientAbstractionAggregationAttribute : Attribute { public SyncTransientAbstractionAggregationAttribute(params Type[] types) {} } - + +/// +/// For each given abstraction, all of its implementations are considered again for sync disposal management. +/// See https://die.mrmeeseeks.dev/configuration/disposal/ +/// [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class FilterSyncTransientAbstractionAggregationAttribute : Attribute { public FilterSyncTransientAbstractionAggregationAttribute(params Type[] types) {} } - + +/// +/// Any given implementation will be ignored for sync disposal management. +/// See https://die.mrmeeseeks.dev/configuration/disposal/ +/// [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class SyncTransientImplementationAggregationAttribute : Attribute { public SyncTransientImplementationAggregationAttribute(params Type[] types) {} } - + +/// +/// Any given implementation will be considered again for sync disposal management. +/// See https://die.mrmeeseeks.dev/configuration/disposal/ +/// [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class FilterSyncTransientImplementationAggregationAttribute : Attribute { public FilterSyncTransientImplementationAggregationAttribute(params Type[] types) {} } - + +/// +/// For any given abstraction, all of its implementations are ignored for async disposal management. +/// See https://die.mrmeeseeks.dev/configuration/disposal/ +/// [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class AsyncTransientAbstractionAggregationAttribute : Attribute { public AsyncTransientAbstractionAggregationAttribute(params Type[] types) {} } - + +/// +/// For each given abstraction, all of its implementations are considered again for async disposal management. +/// See https://die.mrmeeseeks.dev/configuration/disposal/ +/// [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class FilterAsyncTransientAbstractionAggregationAttribute : Attribute { public FilterAsyncTransientAbstractionAggregationAttribute(params Type[] types) {} } - + +/// +/// Any given implementation is ignored for async disposal management. +/// See https://die.mrmeeseeks.dev/configuration/disposal/ +/// [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class AsyncTransientImplementationAggregationAttribute : Attribute { public AsyncTransientImplementationAggregationAttribute(params Type[] types) {} } - + +/// +/// Any given implementation is considered for async disposal management. +/// See https://die.mrmeeseeks.dev/configuration/disposal/ +/// [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class FilterAsyncTransientImplementationAggregationAttribute : Attribute { public FilterAsyncTransientImplementationAggregationAttribute(params Type[] types) {} } - + +/// +/// For each given abstraction, all of its implementations are marked as scoped instances for the container. +/// See https://die.mrmeeseeks.dev/configuration/scoping/ +/// [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class ContainerInstanceAbstractionAggregationAttribute : Attribute { public ContainerInstanceAbstractionAggregationAttribute(params Type[] types) {} } - + +/// +/// For each given abstraction, all of its implementations are discarded as scoped instances for the container. +/// See https://die.mrmeeseeks.dev/configuration/scoping/ +/// [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class FilterContainerInstanceAbstractionAggregationAttribute : Attribute { public FilterContainerInstanceAbstractionAggregationAttribute(params Type[] types) {} } - + +/// +/// Given implementations are marked as scoped instances for the container. +/// See https://die.mrmeeseeks.dev/configuration/scoping/ +/// [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class ContainerInstanceImplementationAggregationAttribute : Attribute { public ContainerInstanceImplementationAggregationAttribute(params Type[] types) {} } - + +/// +/// Given implementations are discarded as scoped instances for the container. +/// See https://die.mrmeeseeks.dev/configuration/scoping/ +/// [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class FilterContainerInstanceImplementationAggregationAttribute : Attribute { public FilterContainerInstanceImplementationAggregationAttribute(params Type[] types) {} } - + +/// +/// For each given abstraction, all of its implementations are marked as scoped instances for transient scopes. +/// See https://die.mrmeeseeks.dev/configuration/scoping/ +/// [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class TransientScopeInstanceAbstractionAggregationAttribute : Attribute { public TransientScopeInstanceAbstractionAggregationAttribute(params Type[] types) {} } - + +/// +/// For any given abstraction, all of its implementations are discarded as scoped instances for transient scopes. +/// See https://die.mrmeeseeks.dev/configuration/scoping/ +/// [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class FilterTransientScopeInstanceAbstractionAggregationAttribute : Attribute { public FilterTransientScopeInstanceAbstractionAggregationAttribute(params Type[] types) {} } - + +/// +/// Given implementations are marked as scoped instances for transient scopes. +/// See https://die.mrmeeseeks.dev/configuration/scoping/ +/// [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class TransientScopeInstanceImplementationAggregationAttribute : Attribute { public TransientScopeInstanceImplementationAggregationAttribute(params Type[] types) {} } - + +/// +/// Given implementations are discarded as scoped instances for transient scopes. +/// See https://die.mrmeeseeks.dev/configuration/scoping/ +/// [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class FilterTransientScopeInstanceImplementationAggregationAttribute : Attribute { public FilterTransientScopeInstanceImplementationAggregationAttribute(params Type[] types) {} } - + +/// +/// For each given abstraction, all of its implementations are marked as scoped instances for scopes. +/// See https://die.mrmeeseeks.dev/configuration/scoping/ +/// [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class ScopeInstanceAbstractionAggregationAttribute : Attribute { public ScopeInstanceAbstractionAggregationAttribute(params Type[] types) {} } - + +/// +/// Of any given abstraction, all of its implementations are discarded as scoped instances for scopes. +/// See https://die.mrmeeseeks.dev/configuration/scoping/ +/// [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class FilterScopeInstanceAbstractionAggregationAttribute : Attribute { public FilterScopeInstanceAbstractionAggregationAttribute(params Type[] types) {} } - + +/// +/// Given implementations are marked as scoped instances for scopes. +/// See https://die.mrmeeseeks.dev/configuration/scoping/ +/// [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class ScopeInstanceImplementationAggregationAttribute : Attribute { public ScopeInstanceImplementationAggregationAttribute(params Type[] types) {} } - + +/// +/// Given implementations are discarded as scoped instances for scopes. +/// See https://die.mrmeeseeks.dev/configuration/scoping/ +/// [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class FilterScopeInstanceImplementationAggregationAttribute : Attribute { public FilterScopeInstanceImplementationAggregationAttribute(params Type[] types) {} } - + +/// +/// For each given abstraction, all of its implementations are marked as scope roots for transient scopes. +/// See https://die.mrmeeseeks.dev/configuration/scoping/ +/// [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class TransientScopeRootAbstractionAggregationAttribute : Attribute { public TransientScopeRootAbstractionAggregationAttribute(params Type[] types) {} } - + +/// +/// For any given abstraction, all of its implementations are discarded as scope roots for transient scopes. +/// See https://die.mrmeeseeks.dev/configuration/scoping/ +/// [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class FilterTransientScopeRootAbstractionAggregationAttribute : Attribute { public FilterTransientScopeRootAbstractionAggregationAttribute(params Type[] types) {} } - + +/// +/// Given implementations are marked as scope roots for transient scopes. +/// See https://die.mrmeeseeks.dev/configuration/scoping/ +/// [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class TransientScopeRootImplementationAggregationAttribute : Attribute { public TransientScopeRootImplementationAggregationAttribute(params Type[] types) {} } - + +/// +/// Given implementations are discarded as scope roots for transient scopes. +/// See https://die.mrmeeseeks.dev/configuration/scoping/ +/// [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class FilterTransientScopeRootImplementationAggregationAttribute : Attribute { public FilterTransientScopeRootImplementationAggregationAttribute(params Type[] types) {} } - + +/// +/// For each given abstraction, all of its implementations are marked as scope roots for scopes. +/// See https://die.mrmeeseeks.dev/configuration/scoping/ +/// [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class ScopeRootAbstractionAggregationAttribute : Attribute { public ScopeRootAbstractionAggregationAttribute(params Type[] types) {} } - + +/// +/// For any given abstraction, all of its implementations are discarded as scope roots for scopes. +/// See https://die.mrmeeseeks.dev/configuration/scoping/ +/// [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class FilterScopeRootAbstractionAggregationAttribute : Attribute { public FilterScopeRootAbstractionAggregationAttribute(params Type[] types) {} } - + +/// +/// Given implementations are marked as scope roots for scopes. +/// See https://die.mrmeeseeks.dev/configuration/scoping/ +/// [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class ScopeRootImplementationAggregationAttribute : Attribute { public ScopeRootImplementationAggregationAttribute(params Type[] types) {} } - + +/// +/// Given implementations are discarded as scope roots for scopes. +/// See https://die.mrmeeseeks.dev/configuration/scoping/ +/// [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class FilterScopeRootImplementationAggregationAttribute : Attribute { public FilterScopeRootImplementationAggregationAttribute(params Type[] types) {} } - + +/// +/// Of each given abstraction, all its implementations are interpreted as decorators. All abstractions are required to have a single generic type parameter. +/// See https://die.mrmeeseeks.dev/configuration/decorator-composite/ +/// [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class DecoratorAbstractionAggregationAttribute : Attribute { public DecoratorAbstractionAggregationAttribute(params Type[] types) {} } - + +/// +/// Of each given abstraction, all its implementations are stopped being interpreted as decorators. All abstractions are required to have a single generic type parameter. +/// See https://die.mrmeeseeks.dev/configuration/decorator-composite/ +/// [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class FilterDecoratorAbstractionAggregationAttribute : Attribute { public FilterDecoratorAbstractionAggregationAttribute(params Type[] types) {} } - + +/// +/// Of each given abstraction, all its implementations are interpreted as composites. All abstractions are required to have a single generic type parameter. +/// See https://die.mrmeeseeks.dev/configuration/decorator-composite/ +/// [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class CompositeAbstractionAggregationAttribute : Attribute { public CompositeAbstractionAggregationAttribute(params Type[] types) {} } - + +/// +/// Of each given abstraction, all its implementations are interpreted as composites. All abstractions are required to have a single generic type parameter. +/// See https://die.mrmeeseeks.dev/configuration/decorator-composite/ +/// [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class FilterCompositeAbstractionAggregationAttribute : Attribute { diff --git a/Main/Configuration/Attributes/Choice.cs b/Main/Configuration/Attributes/Choice.cs index 8589c147..564b9a4b 100644 --- a/Main/Configuration/Attributes/Choice.cs +++ b/Main/Configuration/Attributes/Choice.cs @@ -1,42 +1,70 @@ // ReSharper disable UnusedParameter.Local namespace MrMeeseeks.DIE.Configuration.Attributes; - + +/// +/// Aggregates generic type substitutes for the given unbound generic implementation and the selected generic parameter. +/// See https://die.mrmeeseeks.dev/configuration/generics/ +/// [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class GenericParameterSubstitutesChoiceAttribute : Attribute { public GenericParameterSubstitutesChoiceAttribute(Type unboundGenericType, string genericArgumentName, params Type[] types) {} } - + +/// +/// Discards generic type substitutions for the given unbound generic implementation and the selected generic parameter. +/// See https://die.mrmeeseeks.dev/configuration/generics/ +/// [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class FilterGenericParameterSubstitutesChoiceAttribute : Attribute { public FilterGenericParameterSubstitutesChoiceAttribute(Type unboundGenericType, string genericArgumentName) {} } - + +/// +/// Specifies the generic type choice for the given unbound generic implementation and the selected generic parameter. For collections, this choice is automatically added. +/// See https://die.mrmeeseeks.dev/configuration/generics/ +/// [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class GenericParameterChoiceAttribute : Attribute { public GenericParameterChoiceAttribute(Type unboundGenericType, string genericArgumentName, Type chosenType) {} } - + +/// +/// Discards the generic type choice for the given unbound generic implementation and the selected generic parameter. +/// See https://die.mrmeeseeks.dev/configuration/generics/ +/// [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class FilterGenericParameterChoiceAttribute : Attribute { public FilterGenericParameterChoiceAttribute(Type unboundGenericType, string genericArgumentName) {} } - + +/// +/// Selects a sequence of decorators to apply to the decorated implementation. This attribute is mandatory for all decorated implementations that have multiple decorators. A sequence can be configured either for the decorator interface type or for the concrete implementation. The configuration for the interface will be applied to all of its implementations, but if present, the configurations for the concrete implementation will take precedence. First, pass the decorated type interface, then the interface again (for fallback) or decorated implementation type (for specific), and then a list of decorator implementation types. The decorator implementations will be applied in order, that is, the decorated implementation instance will be injected into the first decorator implementation instance, which will be injected into the second, and so on. You can also disable decoration by leaving the list of decorator types empty. +/// See https://die.mrmeeseeks.dev/configuration/decorator-composite/ +/// [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class DecoratorSequenceChoiceAttribute : Attribute { public DecoratorSequenceChoiceAttribute(Type interfaceType, Type decoratedType, params Type[] types) {} } - + +/// +/// Cancels an active Decoration Sequence selection. +/// See https://die.mrmeeseeks.dev/configuration/decorator-composite/ +/// [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class FilterDecoratorSequenceChoiceAttribute : Attribute { public FilterDecoratorSequenceChoiceAttribute(Type interfaceType, Type decoratedType) {} } +/// +/// Selects a constructor for the given implementation type to be used by DIE. If an implementation has multiple constructors that could potentially be used, choosing a constructor is mandatory for the implementation to be usable. Pass the implementation type first, then the types of the constructor parameters in the same order. To choose the parameterless constructor, just pass the only implementation type. +/// See https://die.mrmeeseeks.dev/configuration/implementations/ +/// [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class ConstructorChoiceAttribute : Attribute { @@ -45,6 +73,10 @@ public ConstructorChoiceAttribute(Type implementationType, params Type[] paramet } } +/// +/// Discards the inherited constructor choice for the given implementation type. Just pass the implementation type. +/// See https://die.mrmeeseeks.dev/configuration/implementations/ +/// [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class FilterConstructorChoiceAttribute : Attribute { @@ -53,6 +85,10 @@ public FilterConstructorChoiceAttribute(Type implementationType) } } +/// +/// Selects the properties to be injected during instantiation. These properties must be mutable for the container (i.e. either public set/init or internal set/init within the same assembly or with appropriate InternalsVisibleTo usage). If no property choice is active, DIE will inject all accessible init properties by default. On the other hand, if a property choice is active, DIE will not inject any init properties that are not passed to the choice. Pass the implementation type first, followed by the names of the properties to be injected as strings. +/// See https://die.mrmeeseeks.dev/configuration/implementations/ +/// [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class PropertyChoiceAttribute : Attribute { @@ -61,6 +97,10 @@ public PropertyChoiceAttribute(Type implementationType, params string[] property } } +/// +/// Discards the current property choice for the given implementation type. Just pass the implementation type. +/// See https://die.mrmeeseeks.dev/configuration/implementations/ +/// [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class FilterPropertyChoiceAttribute : Attribute { @@ -69,24 +109,40 @@ public FilterPropertyChoiceAttribute(Type implementationType) } } +/// +/// For the given abstraction type, it chooses the given implementation type, even if multiple implementations are registered. Pass the abstraction type first and the implementation type second. +/// See https://die.mrmeeseeks.dev/configuration/implementations/ +/// [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class ImplementationChoiceAttribute : Attribute { public ImplementationChoiceAttribute(Type type, Type implementationChoice) {} } +/// +/// Discards the current implementation choice for the given abstraction type. Pass only the abstraction type. +/// See https://die.mrmeeseeks.dev/configuration/implementations/ +/// [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class FilterImplementationChoiceAttribute : Attribute { public FilterImplementationChoiceAttribute(Type type) {} } +/// +/// For the given abstraction type, it chooses the implementation types for collection injections. Pass the abstraction type first, then the implementation types. +/// See https://die.mrmeeseeks.dev/configuration/implementations/ +/// [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class ImplementationCollectionChoiceAttribute : Attribute { public ImplementationCollectionChoiceAttribute(Type type, params Type[] implementationChoice) {} } +/// +/// Discards the inherited implementation collection choice for the given abstraction type. Pass only the abstraction type. +/// See https://die.mrmeeseeks.dev/configuration/implementations/ +/// [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class FilterImplementationCollectionChoiceAttribute : Attribute { diff --git a/Main/Configuration/Attributes/Miscellaneous.cs b/Main/Configuration/Attributes/Miscellaneous.cs index 5b952c4b..d750576b 100644 --- a/Main/Configuration/Attributes/Miscellaneous.cs +++ b/Main/Configuration/Attributes/Miscellaneous.cs @@ -1,6 +1,10 @@ // ReSharper disable UnusedParameter.Local namespace MrMeeseeks.DIE.Configuration.Attributes; +/// +/// Marks a custom (transient) scope. +/// See https://die.mrmeeseeks.dev/scoping/ +/// [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class CustomScopeForRootTypesAttribute : Attribute { @@ -9,6 +13,10 @@ public CustomScopeForRootTypesAttribute(params Type[] types) } } +/// +/// Marks an user-defined constructor parameters injection method. +/// See https://die.mrmeeseeks.dev/user-defined-elements/ +/// [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] public class UserDefinedConstructorParametersInjectionAttribute : Attribute { @@ -17,6 +25,10 @@ public UserDefinedConstructorParametersInjectionAttribute(Type type) } } +/// +/// Marks an user-defined properties injection method. +/// See https://die.mrmeeseeks.dev/user-defined-elements/ +/// [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] public class UserDefinedPropertiesInjectionAttribute : Attribute { @@ -25,6 +37,10 @@ public UserDefinedPropertiesInjectionAttribute(Type type) } } +/// +/// Marks an user-defined initializer parameters injection method. +/// See https://die.mrmeeseeks.dev/user-defined-elements/ +/// [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] public class UserDefinedInitializerParametersInjectionAttribute : Attribute { @@ -33,6 +49,10 @@ public UserDefinedInitializerParametersInjectionAttribute(Type type) } } +/// +/// Lets you specify which types have an initialization method that should be used during instantiation. Pass the type that owns the initialization method first, then the name of the method. There is one constraint on the method: it must return either nothing (void), a Task, or a ValueTask. +/// See https://die.mrmeeseeks.dev/configuration/miscellaneous/ +/// [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] public class InitializerAttribute : Attribute { @@ -41,6 +61,10 @@ public InitializerAttribute(Type type, string methodName) } } +/// +/// Discards an active initializer method definition. Pass the type that owns the initializer method. +/// See https://die.mrmeeseeks.dev/configuration/miscellaneous/ +/// [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class FilterInitializerAttribute : Attribute { @@ -49,6 +73,10 @@ public FilterInitializerAttribute(Type type) } } +/// +/// Defines a create function that DIE should create in the container. This attribute defines which classes should be interpreted as containers. Pass first the type to be returned by the create function and then the name to be given to the create function. +/// See https://die.mrmeeseeks.dev/configuration/miscellaneous/ +/// [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class CreateFunctionAttribute : Attribute { @@ -57,6 +85,9 @@ public CreateFunctionAttribute(Type type, string methodNamePrefix) } } +/// +/// Intended for internal debugging/testing use only. Will prevent build errors and instead expose the exception. +/// [AttributeUsage(AttributeTargets.Assembly)] public class ErrorDescriptionInsteadOfBuildFailureAttribute : Attribute { From 949b8503d8bf353e7bdf8230147b2d1531b9b3b9 Mon Sep 17 00:00:00 2001 From: Dima Enns Date: Mon, 3 Oct 2022 13:21:11 +0200 Subject: [PATCH 162/162] Removing Getting started sample --- GettingStarted/Container.cs | 13 ------------- GettingStarted/GettingStarted.csproj | 16 ---------------- GettingStarted/Logger.cs | 11 ----------- GettingStarted/MrMeeseeks.cs | 17 ----------------- GettingStarted/Program.cs | 5 ----- MrMeeseeks.DIE.sln | 6 ------ 6 files changed, 68 deletions(-) delete mode 100644 GettingStarted/Container.cs delete mode 100644 GettingStarted/GettingStarted.csproj delete mode 100644 GettingStarted/Logger.cs delete mode 100644 GettingStarted/MrMeeseeks.cs delete mode 100644 GettingStarted/Program.cs diff --git a/GettingStarted/Container.cs b/GettingStarted/Container.cs deleted file mode 100644 index f9d3cf3d..00000000 --- a/GettingStarted/Container.cs +++ /dev/null @@ -1,13 +0,0 @@ -using MrMeeseeks.DIE.Configuration.Attributes; - -namespace GettingStarted; - -[ImplementationAggregation( - typeof(Logger), - typeof(MrMeeseeks))] - -[CreateFunction(typeof(MrMeeseeks), "Create")] -internal sealed partial class Container -{ - -} \ No newline at end of file diff --git a/GettingStarted/GettingStarted.csproj b/GettingStarted/GettingStarted.csproj deleted file mode 100644 index 9b0a6cd1..00000000 --- a/GettingStarted/GettingStarted.csproj +++ /dev/null @@ -1,16 +0,0 @@ - - - - Exe - net6.0 - enable - enable - true - $(BaseIntermediateOutputPath)\GeneratedFiles - - - - - - - diff --git a/GettingStarted/Logger.cs b/GettingStarted/Logger.cs deleted file mode 100644 index 093311a8..00000000 --- a/GettingStarted/Logger.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace GettingStarted; - -public interface ILogger -{ - void Log(string message); -} - -internal class Logger : ILogger -{ - public void Log(string message) => Console.WriteLine(message); -} \ No newline at end of file diff --git a/GettingStarted/MrMeeseeks.cs b/GettingStarted/MrMeeseeks.cs deleted file mode 100644 index fc5d5a28..00000000 --- a/GettingStarted/MrMeeseeks.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace GettingStarted; - -internal interface IMrMeeseeks -{ - void Greet(); -} - -internal class MrMeeseeks : IMrMeeseeks -{ - private readonly ILogger _logger; - - internal MrMeeseeks(ILogger logger) => - _logger = logger; - - public void Greet() => - _logger.Log("I'm MrMeeseeks! Look at me!"); -} \ No newline at end of file diff --git a/GettingStarted/Program.cs b/GettingStarted/Program.cs deleted file mode 100644 index 6cbbce8c..00000000 --- a/GettingStarted/Program.cs +++ /dev/null @@ -1,5 +0,0 @@ -// See https://aka.ms/new-console-template for more information - -using var container = new GettingStarted.Container(); -var mrMeeseeks = container.Create(); -mrMeeseeks.Greet(); \ No newline at end of file diff --git a/MrMeeseeks.DIE.sln b/MrMeeseeks.DIE.sln index a65561b0..76ce185b 100644 --- a/MrMeeseeks.DIE.sln +++ b/MrMeeseeks.DIE.sln @@ -21,8 +21,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestNotInternalsVisibleToCh EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestInternalsVisibleToChild", "TestInternalsVisibleToChild\TestInternalsVisibleToChild.csproj", "{AB74CB8A-5195-4CB0-9844-71AFB1F5C926}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GettingStarted", "GettingStarted\GettingStarted.csproj", "{D71C272C-8CD5-44D5-B1A2-BD9271823FC3}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -53,10 +51,6 @@ Global {AB74CB8A-5195-4CB0-9844-71AFB1F5C926}.Debug|Any CPU.Build.0 = Debug|Any CPU {AB74CB8A-5195-4CB0-9844-71AFB1F5C926}.Release|Any CPU.ActiveCfg = Release|Any CPU {AB74CB8A-5195-4CB0-9844-71AFB1F5C926}.Release|Any CPU.Build.0 = Release|Any CPU - {D71C272C-8CD5-44D5-B1A2-BD9271823FC3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D71C272C-8CD5-44D5-B1A2-BD9271823FC3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D71C272C-8CD5-44D5-B1A2-BD9271823FC3}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D71C272C-8CD5-44D5-B1A2-BD9271823FC3}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE