From 34d0e2749e715f97909a8e73ee80d37d7b5cda56 Mon Sep 17 00:00:00 2001 From: xzb <2598514867@qq.com> Date: Thu, 31 Oct 2024 22:15:22 +0800 Subject: [PATCH] replace_all new test zz reflect diable in lhs --- gopls/doc/assets/extract-val-all-before.png | Bin 0 -> 48847 bytes gopls/doc/assets/extract-var-all-after.png | Bin 0 -> 54571 bytes gopls/doc/features/transformation.md | 13 +- gopls/doc/release/v0.18.0.md | 5 + gopls/internal/golang/codeaction.go | 36 +- gopls/internal/golang/extract.go | 391 +++++++++++++++--- gopls/internal/golang/fix.go | 2 + gopls/internal/golang/undeclared.go | 7 +- gopls/internal/settings/codeactionkind.go | 12 +- gopls/internal/settings/default.go | 2 + .../codeaction/extract_variable-67905.txt | 4 +- .../codeaction/extract_variable-70563.txt | 50 +++ .../codeaction/extract_variable-if.txt | 8 +- .../codeaction/extract_variable-inexact.txt | 16 +- .../codeaction/extract_variable-toplevel.txt | 26 +- .../testdata/codeaction/extract_variable.txt | 24 +- .../codeaction/extract_variable_all.txt | 238 +++++++++++ .../extract_variable_all_resolve.txt | 249 +++++++++++ .../codeaction/extract_variable_resolve.txt | 24 +- gopls/internal/util/astutil/util.go | 84 ++++ internal/analysisinternal/analysis.go | 84 ---- 21 files changed, 1067 insertions(+), 208 deletions(-) create mode 100644 gopls/doc/assets/extract-val-all-before.png create mode 100644 gopls/doc/assets/extract-var-all-after.png create mode 100644 gopls/internal/test/marker/testdata/codeaction/extract_variable-70563.txt create mode 100644 gopls/internal/test/marker/testdata/codeaction/extract_variable_all.txt create mode 100644 gopls/internal/test/marker/testdata/codeaction/extract_variable_all_resolve.txt diff --git a/gopls/doc/assets/extract-val-all-before.png b/gopls/doc/assets/extract-val-all-before.png new file mode 100644 index 0000000000000000000000000000000000000000..1791283f30fcc68280cce985889f6aa8b2125258 GIT binary patch literal 48847 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 NDrzZwkb4#Oe*oZF0$Tt8 literal 0 HcmV?d00001 diff --git a/gopls/doc/assets/extract-var-all-after.png b/gopls/doc/assets/extract-var-all-after.png new file mode 100644 index 0000000000000000000000000000000000000000..0340e4c6e7b644dd28485d75f6d4df9d7b0a7dbd GIT binary patch literal 54571 zcma%Cg;SePw8eiwk>FZf(-ti*g%B)Q2nj9jP@q8Zwzw8|cPN1*Sn&b{N`c}~Bv8C9 z?owPI?+(;}7UFZ%E7_O%*4dS z!$b9$hn)K<YC8%M{K^pwcBk01Q~r=}*qcYm+?T=`sDrg5k;tGviY!7SW3 z@RL{WK;+ks*hX~$m8bNAoUB}2tgP%0hOjd+aI!J8b5d-hx^Qr&gfzj*@ON{&zm%Q0 zl>y-K3w>`Qn!q=nhVO=2Y9Kl35kCKlvzM$vffhx$uZ=FH*wKzltw)>f_n#ClAuYFKg_Vsth z)Rg1*%Ajfv3uf_ewxFRbpI4OUqtmV?cp(j%{S;Z8*#vyU3x`tW`$OYK5R#vwHn6Ru zroDE}*AwPKE@#Rr;v8|8Hy(o{Lsn%!{pw>xb9@xp6Z-g@U+fh>YiNlZy816k;d{)_ zl$6OM7bD%4_huOudY(%AJ**=~-j{Dbx6l3eJg%C3bi+Ghw+YvtqQD|^%@g&dAYr8a z2Wz(55Vk9kbT1?&LA38fhf_D33U+xn|B(T$W_{$pfQr^XPko^;Rd3%K+S%0!UEbd> z3}76Iz*KQ=zVcM%Y(I+Su0gxH^2vzVS%oAHs-wD{!$96g1x zh?A8Qb>c#&0hP?TIu(PD6JZD?B=DQ~+rXo91(bGPEMCL!4f-UcNh@nthzF#3N z;-IJ?x>vO4o70$e+#%b^-KnwYyt{35rx8GQaS`!Rg@y=L8PG$)>10$~>vCA*Y#7m| z7T@zQ59e1tfp(kxU*5>9rvrT5HT-8PQyh$YKOZmNvwC-Sjed5jlU{4^Ebjao_29z;Sl9-%3yDJqgi1^}gn zCecny4D$T>5E2U0`g2yJKm#t~$IRdnfan={dfu&}flhmfR*h1b~S&&L*|_nFbMc0ifv9 zN*O-{=lVX0u+5waRL0n;odSvE7nHmfak@Nr<5sA#mYJ&!?t`XiYcA#%4OQ1|iU|Gh zb0p(rb_ULw{Wwi;Nij$3KQj9VG@jJ& zG;VkG_oMWTP)16&%>CRUB`EOt5u7#&$1Vg!)nn)%HHJyTZ+~RtKNV&ML2^we={!>1 zhBZc*OO0_%>tG}VkWpRPpE?J= z1xkFbSB){|WK?5<@7~oOE?%JilWTzVisJ3VSM0g5&j92sXgKrEn9$IOY;@a-mc`wf z*GX^U>%Py^p;ZPm&*mshoh>sVse_)%g^${k)nCtZ;JqjKd`}FHgoovS`WyVVeCd>6 zvZehZH)T7ejlc}J{O(gT%q-~ktB?Gzl3JdazI?WhBm4kOL1Ye(dcmVFEw8U_e${6w zv2lO5NIHvQ?>lrml(W=>n;@I47e&x-N+Bt&@MjnqUv#UOWBdNNFtZ1l`>mZj#(i(H z%G*-pS`{5$6X+8#fV{#1vEftTT9KKJ9+6P`P-MZz;I0$Tw8|h08WA_~@V^wUaYtsY z3j1b|fX|y&g#AC&Lp$Dd0_g~X6rZKbL&E#Fv4s^cYhE{_f8|pdlv(t@z1puQ9RaVtEVX`T3MG)CeK$zihz> zdsZtSrz>5mD#^>-q#n|s!>y9HZ*v8#{J)1Sp21I2e60Y8WM1LZQtL8~7#}n+!Vo45 z=gEZR!V3{Lq~ns=5dD&+o5fNw69uk}2I;Xh!3)`!BbAAt3Vl91qwBQR zh|#nrr5-(Tm`g)o*dhdpe7Yi!Fyj|@X*~6g3ST;TJnVrJfw!LWuLh!esEGz}CgKHy zVk(Voe!PpBu3#ZSeds56UOI@(NO@;stEb850;}qc5sHWrqRZ4qKt7wJpk?;h)?&<8I<*24rVLK= zB53H-o}Y;A_8^=KGPGLm#P4(KW^89imN;bKYddkeHF`&g&Pj7e71)xAhM-M-(PX8w zbAEF*FHO)f^6Wpwhxq{nQP&y7f7i;i6#7%4pj1!)y0GQQfjvt%ZaU3=58=1{joUxi zOiGXE-gAA)H_+s~dAF>RW6`>F(opfd?gp>Oe{-FfC&||;isOshOXUkz^f&j^zrUNU z`C{Srh91;7Q%kcO=$O_H$J+((27>g(9M;1~n92^|J zI6Z^S{=xDN7yJPmQY)#CZ`e~};#xa8_L9BZzv@yA<->v2Cg|t9+wpy!doTu*4{5tC z*Z=?%yVT39pB9gj1m4Y*!9jpy+HddFdLMkzQzm7IHO=cWh4fynJFi^Dc1mcaD1FgT zr4p%{FXKa)v-Pd|Sy-G~I3uwWrLap}Tfb)<8>|FiGNzk){!-!v&lu&4);=aK4!zK( z^BAR`cNfdQeQ~17k#cD29Jq_?RDg&7ysQYwYjGkIB#@E|KgfaCLIc(g2z{L%SC&NG zKrzJI3XWOHOko-vj2CEf9DL1|FjKSlL?$8BT&tRr3gJn_Z{>@94q2j7u*g<80?o@$ zD5;{rfc*ETOeP&fi&_>uHg*IPk4ssoM@+$(rll+-NzJbXL_{NBv0eW4Bmc0R&H5?_ zXgkVe>QZpUN>B&Dx3G}F5`>I(&W`(j>=7wtz9IU4yjv=SaN#PVg}@RQ7yLW6OspYf zTql-fcy?Zib9JOuhDk05V;#+(ETiTfd=xpv6~m42=qw}OVy~@)ne1?bI5r(JHr1ZD($2tmXYt_BwvVOC*-8v^N}o{BCL3Pvp|XwS>F0$rOZmY~Ppv|>8F7A`k663yOAHF|x(P7)^0dfFPGFswpi`y- zSvd+E^=>Y?w+-8-NWi+**>%7{MOf+0o$l4{pKR+!Xgla-rDWh8!Ud?{R1JSkv`$c# zrri317NJagw1S{Vud;XmUj!GC_J8}?NPKi!1^1`n1X)fJ62B)RAdISb>F)nlg7>BbJ92$@y{> zb>gMWWOs7Mk5$lJzuB!dBpAtv!n!O){*UgCWq99}V5>9s&HL$FPD)Kp*D;ji&Hdw> z7o~bz3QBl0$$X)mJahn&va0QK? znF00bOr8Sdf!6#^)W3lJJs}sF^Xze{&=X5#UFvlczEF;E7Ia1`I<-~3 zWTyZ}&ZI(Hb~ZUElB*3Hn3+ZC}KAv12s zu<`i*G*XSg+OsFc@40uy1Xp^R+VLlL;O`q2STvJUJo{3>%}!0?fv{Q4Z>z@-j^RaQ zsOgU4qg%Dsd~~M_bTkBYuhskd%K7>4d``Y|Sf*9Mk*|zA(uEo7=LBRNyLqJc?~j5q zMg~Tl0#?*qE*dZaG1BV~;Zjm(GNkg2p#gX7Y*SjtZeOY70ecIgdTMKHAa+1t^nt({ z)7oVH7cEQT9l6sFS{fmD1ebK8LqD z37J(x{7;t{6n~JS;&$L+k5j~Zlp@#Zh^>f2qC%)RxHyxusIM)EFH>{)_xM_r;zt6AwRnl;yYW+RZ4cqS+Oh&Ju@oDl8 zkui?=_&U5v8et>O!4vvVUR?~(k5;Z9a6;KPGE{i3J}-0;L%2$InI${sqzUqf(5yeP zw4|7|An1aY%Yb%@_%+GrS&|V^swV7h=C$8HQ}W72S}|U4bV3_kr-fLo$A>~kkeaymy`z1t z(ZJ@$vfri0a#-rP$}vG)&AwJRWMlCusbTDk^KMOQ5qd2BZ7fH%K zIy!o0GuUFNDQ1?JpKlWSoaM|s@3EiG-_6~(1xz3-GNK|)Y-CVQ3IY%{Sx~qd&t%D~ z`_aLnaD8@D7p-&6;K0vcUhW`#cFu=if0MVljPG%Z>!Als`NE*&r_ZK@tN(Wmi|uRG z^eQ%&>@G<%dgK2$EGQoa?nT51x99mvBYTV^ntWHC>#42(&DW&(d%ii&$Y%M|;&Ar2Zy>atChyU2p_=z)@12gkDz$E89 zAc9s~N@4;|PFbV~6kjFPNtHO398GjD+d{hs%hpTM9otxXL_D{4v~|Q@AKAaPHhwg) zbu`=CGBd6>cE*SN*k!y?fNq5&rzdXaj>Wii)f{bu$V`L&(mTw5J0K!PCQEuiC=_Tg^soD3!A{VO#44!1!0(H@iY_4y zuJ+l+j+1aN=|_yOuhn(fu>yaiw>S6T8;*6Ce^*cXk$8SJJyR*UTD&@gOJY_E2HDY0 zb+gaB(N4vq3>{yjW(HIj&KrECRfd!MIy3nLJ=~Ta*@Y}?5k@I>AYUpC3-&XCaEDm* z;5Ay0jhsGn!*dN_R~HAX{&m`ATi@D}&UDhd3_pI%G`v5uxg45RplCwFVmn%*LsqW~(Q?ic#yatJr%G1LVn zA&z!-QPC(&SB*~{ahqSLO5+zo;No$*TZj=6EO6lkAKRe8Ss*;8ssq0ls%}=S4;TzG zmu(ZgHQv7@6PJ@#@FoEuAkkKHa_`)a{+6`s>d6~u{#HOcL3Dr)+}N$Ir;dwAS(j`G zyu8^wHR!sJUD%@Ibf#FV(XHjYCw7nN$w8AG!F=fY$00M9eH!&B-BXCe`;=)}q2E1T;emj*vC_`RD)Rqe5<+VG` zSsv(mGihG)8v{b8ypyf`alB%I1Zj=Zf-u zSD`kLEL?Ck^CEo$%zqV0vS?Jd|lKK*B^3m-G`$S{I4@$hzAMggs|8~~vx z{-9%xri5Otaijxg=^P%@F7J+ZQj2e#R)UoE%ksXLH&9gq5WHx)c!GCx_`Xd;khuGA zT9l6%;G;p<FpAPVAnpB{cw@fP>#L38iAm`=+(H4wI z^Z4Ad+$2qs>~d!Or?-;1q_N~TyQc;iS7rojIdL3~k;fBIB1Yxbe_CF!(rhMf;M;?m!IQ#b-b&^%-$&k2Jv0%yi)IDpmF&Zg-l!R>p9;G z#9ZSNgn-{T4lQdT9;ssUx8rFWUwkO*fqf(H>W7D!CAGq3q&g*AHcH7aDqRGu|7Bml z{i#LfHr5O?qT+nu9h%9mySswUv!|kZ`@gqlyO!j=%SRosg1T|$-=t-NX5H>w%3r*L z0XyFRLQ+uU^=CAZz1P@+VSnYdn)V{Nn+gFD{oDrRK3oXNdTpFHD=+jU6l>~)(rI&- zKU^N149^RWCMGs@cN&KQ#+?t@wi?iIh!{Jo-+B15zqikXgS}uTvq8?ySN`%1h7pv{ z2OVS%X7zaC8qM|1jfM_znU82uQd--t`OhDP^G~3H(kFz^5yq*mJoH>AHB1$#KHqCW zDWlHdcX#F^MpfSraJlPVbj*1t*_P$NquXBhCo@{X%SS{!9j|QF;VAX_vVYhC6Fr(u z7;WK$HXopevf1+CP#xpghm>?&>0+$G%w}|9kF5+nbh!jGFK_y1b4Rpg*SkB|ob^z@ zuf^4rhDnf{?{YtUSa)OKY&pE&IR0P|-XoMEsO4kcz7HR1_0 zyKPuwfR^Xm+No&V#$gOs9d$Kt67VgjKJ|6YR9jo4LDS-Rzj3{nS-46`%lglT!{1Ng zWyu;p^CC(`HTi(J%%oW@G-6s@1V1e!XWvrP^!wbM^5FHb;Eng)?(F-n%^Z75gG1t9 z6&)M4LM%xj@GpRkD-P?$4NIGdDCr+$Ci5|dtVhN4oad6m=JRG;ESMs^2>WKebh?Ab zTNbxIzB=jZQ-90qltrJ);b)}K?Hvy0_zXJ;s5#?=y7=soGhh7B0omcasWm)-dY@B; zxa)*gQLa>zIL40l>67Z1{i8;$j_xBbSp~ZCx~I9w zcdY^zyXJ-#tmX=C8BLBmy&ke>_ZsJ$!(=Mt*vZ6W|8zFY{-11_;9pv(f`nh0j>c~C zxM?E=U*v$||4Np@`;l_ND+ZJZ8$!vlZ=b_~cx_~e`;MZI+bVLz>23J?|BM^+hDOhLCcJYTOA#Z#@@2dH|kl?%->UUOl+c^ohAIfJA z=_-CMP=?C58b6}}n##j%6yOSQKg#qLgSe3_)_sHDY6PL#1SCp5a%tP7F;G4*uAzPj zj0jx>3jbAer|65)mC&VR1yaRHH+0Q{Xusz0Eocl9e2WVo2LE{sjugZ3)hjTlbQ6hA z@f+PY7!;%#4)_wR$B5aed*eHF_4*u+&zvq_MWGqo4G3W=&QcXySxNp?8lER`zQD!< z&=ALuPTN9MtNX`T9>DJXi$C10t*zOmVhV@$XEyqr&_CR90PYuCg~$6r0q9(}zTfiu zICxSin#nM{S2O2P)MkqB?^gVhadU8~;r~wdt_$rt`VW@*&Y_f8{x|4BGIxuPCVGru zYPi2(uR3YE#Hn(Y0n>TAE(*$Ldb`K?mL(Rq`Fk26l!-R`h|M09w-9vScByq==UY7= zy#isW2Bs5|QzV4g%G#!A{<@TsUAi9$Kv4UT@fb}`ws%;Kt*_Y*{2(`yzs-Qu!JT3a zdM`M@i1x)kjkozT>&qMPN0)T2%R_ZPb%h)61E9V5@Fz%&k}4^-uoD2p69E&KB^?ry z6LEP$#_pMlN=WJYve>k+xRnQ@=KQf&3?L+9)oCN9vwiWV`OLsB(BD*O-flh<*(^X` zaTVbLY-f?Q)fni~`=cT$y1z`D%O8O;#N+5~r#|f$+@oueN?6a)?_`Xypu2nK4lp#oP9%5d$^>9iN8fXRnDP-N)xjvOiI|sdwuyH)K*y2_D z(O&tVZY25SjB}lT5aRXOG93^MluFq0ea5e^-MS-F_5_~kwO6B1yiy;!9UCw-sE?=! zzXhU_0Lljhs0hbgd@C3cSeAu9Q@nVgZX|(>TP($sLMB@K(45p(Lqv3xNm3&Qsv#)V z1X5K=tWcJmhD7J2$ygc+^smtla6`Oxqcylx6^3L?8r@O5VQ3P`A3Qq9^A! zr6SUlcY1NKF0NiSvbfG>=%8k zta_wBK^v`crpl2KaQ^KjN{9%<0oC+FwJmNB9yvyHmf9WK4u`^k46~=PdCDwkl__ODu?XR&h~GpoZb=H!_hy$iS1j znt3=*+tUjVh1eWU5qxsMH)o_lYD3C%j*E#J=nFDn`0K2nGDV5sJ1t)oeJ7>+Lx<4{#i+T?<3&PC_TkyoZwVSPwI7V0Y8Ab5 zi$y+D4}$#@{79jL0U_EJ6D~h&ugvzYYlH1==h5Cxp>b08p1?nVBQViiRjw?>0_C>N z`AN~2+^FDW_9yqkiNZl&6*{NByTuhX)5wT{qgHKgNa?Je>e6i)$p$BcLTX!S-T}=5YLPl73pxdvlP5jDw2%_~6Q2(Q{`pkSzZpxCEvvyUJK?TX^u^m2;&W{0@nT2>Azi*jEdrpFBRX#?-2={V~`Pv<9xG^P}o*n(w00s{#VmC#;NtT%X1RRI5C z|N2oUaqT)o%EpYF)UTdf8u(3yUxv4x{wmFp#(K0-RY~RU6JuQe!sn))e)olc<0x^Q zsgeKT!B+H_F@V@feuv02)yY|)k1;qaC);1~GW_@p9jfjvkzj9ea<*=m{4>zP#YB9XO-G@ zEPokjp602`7`LJJVo5uzF4wiODV~|4wzeukBNP5bE$ddu zTZ8``?E^E2NyhT&P(FGz8s)iPu%DP}FzP+*VcR;lDYHLuF*~OxnJaKoY%>WwmIQwL z5!&bko!3ozRUwMqcKqao{u&3}J9)}&_)y?1{79;`3RVhBN>KaH4p0WNf;@W?U^380 z!()Goaee~VY^(Ho9-(1Q2mC>baMjHxJ?=u+;pN6I%TPUn=bQ7_Q41PK{iDUpza1o} z(Ar$77eT)Nc7P8l%))+z;v!HYJb$inu-==?z0!1fAjGYs_=o8aZ7yr(>{^RvlL0KJ z{5to~O1;ExY9!I{!L*bHGYXztNO|Z6%^p=q@E?wi?HC`X0UGSWVwt8+En`(=Ue2DA zciYm41IDdUCmj><1imN;&zDZ$B^re5eo{;Ku0TAS2aYm+C3*YQR*i}?kfDI>$d}W3 zZ2cSUcp`}ItJ>$tYN#0_Tm;l8O@8lHky_O&66qFo>~(MaFSP2b^JT$b#<#|aXmCV% zD*kAF&<6DOUGDbRLX29N0Scmv+YjKKZ>Xp)lmshQp7=Qk#K4)G`9mpUb~wkeU-#{78|8nkwbIK!gqz_0^psd7_Kg*_3}AV(miCJ=Bqqn@h^OSW#|WpGeMuR^f%9`$9_I~8N=g|TB=hJ_c1k7!Fe-YdW8QgMfEcl1-}ibGFYFQ*OWd+G7hzy&pH~ z2m5F2Qk8GCC-^1XLFq@o=hn9IL1jX@S*G&~vDUl};+^1rj#^xTD<`11%GZ}ipFoJ7 zU|Ox4^QJ^mc2z=lvD125=C$mjRW+%;R}Z`1E?dcsG)pD1 z1h-FD4oMi@+D}~0BTyZ;gs5Pg$Q|^)6)k?s(tnTn%AX%blX>`YFPEE`h$U!4@Y2g} zUha(ea8pbUu1}O%UD10#RxnNYDGg{3Q9CqRJUeC>zgucj=J8G}!~XqHPyc20r;$%V zNwmdq3Xc>RHC9NHZSC)OIhJhRp^mqDQ5w-)UM>|75GQ)n^nMutwWrkpEJmNBfDTMxgirc8fn z*(*Odl}uF3;UFHdVVq9!J09R!U;nC@G+6$n4}8&S5`fR+j+)SXdbFe?XT#Gis@7oA zrRny8dA{gDjwzINdk?R%yRZ(y>pnUS7Zl~?h>48AD36VsI!u0jj-n4Uh>t$;t(ax| zJQq_Qr!HV^=SxnS$c!lQAw}dzm5f3~%cedujnEs+)b`YjV82R=sze4iT8S)R+@^%Hr1W7jWH@3T0hL4sa3?#ZhksNWlj=eqE5 zsN%G6fO}A%M}Hg$FrYs95q>E1G`K(9!$yqYq*vfZEO#Q>fT|dm%k$pQxnN(0`rGLT zOl;`(C&vML8|5VDOvn^G^>4Xcg9yqc^M$x7Q!skQAer{?d9*t#Kec~Zn)UR0QsZkz znYtrywYgdUmfTFA^v2ou7I$JTJWrSv%q6r+h7*3yUAoE?G7SrEa$ZrCyQSAJ42(x> zi-0fao(6wV|73EwW}Bl)d&=j#xcbT@D;fFa{?054Q?OYxGigB$fAO`X&ui>{=L$~n zf;$58&G8N1hH0ER;`8e|4PY*xT$TPBPoFy4m&Y!L$DX{K>l3T5qb)B^*)GgVVxEp5{LVe{GW3AQ+38D>y9vZM{U@p?hN%G7$zG54v|RPs%+{<3*=e+Vz+PLDDxp715<>U1$z|1-=`9Ve2SW zn|M;pNj=U~`;47eHS|_Rcg?K*O|5J~2Ym*{J>+Y_UEcxFi;(7!>ooc)9jSc?1a+)P zhMUtdLcWpK9fS+#jHD9e|M0?59;dQZ%sXP6J&aT=oRlu@C-7w$UQI+YW)R+p22{WX zk+dLq$K46`MNB;cHMlzVUsh@9YL^~HY^5w`uF$}Y!LJRB`W^Hikdg|hWT#C4Q-M#n=e;YiAV1>~#;)K4498}gnyzg7OL^YA)yI=S^NTqdr zll%dbWYnSAD)qb1%=OB+Pew{S4U=pcBguGU#hRBW4wBV`7)VET8<9O;58mcU=W|?) zvdP#A%_6wh06sUdO%fb|S!F;>F^OT@?V1t}>seIMBPFMyE*|ugdwD_>Bz)hmKFsu0 zU9!HiU}RHFfZu84u^4HLBR%qVIt*49S3WtOzB_g4ojeR^75Kdp_5!e>Rykp+-n4hz z-R;_KUnte&9p-twPd)o_PP#eyye1d`umP@~Hy^*h_Af)n@sbGYLtGO)hr)4qk{N-b z9}ZGhOjR)iWUxO$-*)T$^ZZgFkA6zRapsFeE4K4NVC{v*@bC`c*Ln^~G_44lmgSE! zhBQldfoV8kS(J1t?C151fi77XZmo4UXxV;?w)m$wmFOq;={rMCEn&6CzPna~mrrU# zTy(7l2?>a-y7Hw7{}vDr2mE(D^THvz|9Shjcb&J|RU+Zx$`fCH28v(sh_ogsZ)V8_ ze|_@9NXt&hv6$ZWNiejxy32$2P?LjZXQuf!a9P~1)Pug1r#RTwQtltnZWtUV7nZd( zlr&d=@H=GCh*Pw({$x1(JKS{FhL`}GW3#z)G&TN{mOGZqngA}!g;PmCf7 zQ=>`mVI+3sE zfTX~%iVh05feK$c^0;W$-@c5|wzJrF68sjKT}K`2v>gI7=wa-mRjrKHd5teUc?BY> zHfE@mQy(;HS+aiVrl{Y^vK5UV_ABsHX&Rl&W|WddxTuAG+;^k&#wHW(&0gL&f;}6B zFV6hfxIDf;d$w@nm(VQ5GUAx0D@W^xiLBP=j}TMH96`z*tSFA%(4dFwOQOVp}9hf$-G`owC1v9klEC}!Y znDm*KiO+xaoA5zOdKB!zC$4LMj(fsi%bQ}q>Ur{5i9EdK8fBQiNqZZff zl|spie0G239EM95HilKD>bhqDmcDQqGYk!e^ES`mO1_u&=1Qx>6+# z)1UJNGa>oSi%7{y81rPv{@uO(HAWVp_oy<<(G%6bR80O(K)$o1gKg23BLt=79Q4!r zURTb#(DkI`c*qrcld~{!A{6N{XKp?_anN-AgN8FIDM;$D0&RJ(zFRrh%u=ZScC=Vp z4Ig-sjr_hGP;X99DpAt0Jsb^trqbEY9sH&0kE_#_$*j^&pmS{h;ZhdCuf@(=R_h`f zyoin4iVSye-&(R#?MfhK+bRCy;_BEVuL_{Q>N#X7vGQqx5EJrpZ+NhFIO1{YL>?N( z3MAbAA-VpG1WI#kUKDq~V5eM3(SIY?g0_E}F!yt;==;Ta(A_^dqB!D^>F^lD3s576 z9YJ>Rd!sL-v83WBH1NA<3|17UM~vMes1$_bOxk$t|1Lmg*v`w=$8pP4qf{T;jd7xL z_!!eD=A$qAYVmSz<1kWz4CNFM24Q^#R;+qFl&;YcIExVy@_LzTCS?o2jePvHo6rk& z@(W4+VYd;WS+jI|Z%)NEr~B*vT?}<)nG-gfPM|Er0L$>S8_P_4`7cdEoRLi6@U3Yt zHRn540GcY;3sIq5T=$z$DqW=TMzV^wYfaKyg>HQ%7K8u*$fbAA$bijh-vX26tEXMB zc{}P%({mZy%&m#Q;j{*$g4b#%W}nslP4cHZvrI5lFDrc<@i@+UYki*y-YHyeK&@^T zi%J*;Dz&Swl<_ftY((+(pG8fya!PR7?E)L8c)^NXZ-%)_pZ}nb%Aob-tA`V%;}5C) zM1&5r-oVL%|BkLCN2%q?epU<{ETVr&?auR&jxICRGz+$``MM!)f>5J%f2{&qtgKpO zoxu}%@i#8P?J4&$iEDx;5>~>29&UR_C(NuXw4BYx&zx58Dn82hxY-|sI zk8nSCJiGp!%wVL7%X6q9^DbLe`0Sr1J{Mj6`JQS59wllJCjULgfx!Vvr^1{2Ey)#m zVYF>n1Ch~7Ok{aR?G8|3DCKK&frkhTRCrZHad~ldWn0QhXqUXA*=)L8irUv2t;Bc^|O{cqre#Pio+bc%+z|+2+*ddz__VVkuLp$Q?&rQt>9mB`{R| z3?GB{lQ;~~QCoIE#MMkMO6F->re*id<6x81Tin%eXYpF0@V&orjl2t8Uj93Rr0-sS zRZ3nH26ltKJJ^8tHSyFvkchD9laYtCsL&y_jMb6sRA4`0D{SergpNFRh);QF{ z_K`uD2oJBIGyO3`c6lb(&c??h&se*rgd8KF&9D2FrO!Dn0mO(Zj`y(oe@V&8vi+Y5 z-qhCwxKir+n)uOQt&K|NClVu*l20DPaYmk|yKX3mIwumPhh)RZ$IsKx70dop{m1!H zubAsv`C0-seNu`j4C7sN^KYM5u|=xv4Y-BF6Nq&9+i%a+D2GSsr@ym4CW<|IPmf1L z%=>D#YtYm*D$KjxLfgW!!Y8qo{^MXlD_|BaJGzkp`IUvUb$PdaB}tPxt=it1J0$qg zFxG$EY(+{&Gx2@v@?%Ixt`-c-zSuMI3>JWjF5Bmc=K~S!k2srrzh0Xq}3R zNE_gM$DLtkhFOqfF?y>jD6K#hM{;S@$R)Fpv%NTnhPvI~wcaAJehBvo)eIp<7WOYH zXS_+NcR2i2c3Tq*QM_#Oi}-eCH+)Qcc6mbmM1{sjAEI@-CA~R*JFY(Ej z_FsI(YEhSe)LMp&I0WEYMOXQ=cA9D-Z&w^R7E)j+v4eo zmBtBbv@d70W1P0tA1`+oqDpQ3MWm9xKHTu>jfvrR^onisIH>NOc}oq z!*JpQO3DSvuW5`A$hA0uVQgFZr2mH54BXb9>7cpLFE?@HJSY$qM08diorZEe;R-KI zmlt$tKQQQmo=<1!rZh`Y&>={_5nRYk)?UXH5=L zP9w$C7y4h6PR}zfUX~gLJPqM(N0`Y_-YNKf4owE2N9jRQiLN!3yAq?8j8hP@s&-|& zJ{;^C^jQ&>&x{z4{KJQxUnE6ut#(7@V~VH06Q!R8Dat@^uE4<7gR>g#;SH}_hb zZP8MiLGku>W;y8I&h(baYRw6|k$XzWKBf@SO*u&E3C=CBdMapCZ}ddmR2)8La{qu` zE~pAz_fXO~Vl7_+o@RJtHt`QYE%ksDDtPEEGabhGk2VEe(q+&LC6l$sEBP|zl)4D| z>gSkh;j1ZR#$Yipocml@bf?yVP6#Rr_!hja7^~8#P22Ky0`-wi(YErAgUBIMnSCLrvgyQoO`Mo{S&DWC7XTJ*@2Ia|ygPmr-Oyd9Mmw#0m z*UPHJc+wym^u>xYeEJ=&L70aJvsTyx&1kaSt3ViDZr^IY38tF#Do-tsBf4dQMo;-> zK)!H9=V}kiv6O?Vo~f#x=w-FC2^vg?v~P~9P}BUAS=IQWebTtlDN)+7ji3JT-V_|A zyx6wUp1Kyjo)Yd7KKQ;a^And(D5U5+9@g|10T({dx#v4yu_44;t2aO9k9roE7^hR2 z@Us$P{-ZXcGxwjN+eIJSF4d+Y6JH2zyq3bePBj$@fTDY%ahCL+QG+t@a1DYeTK_}e_7KAWS!4`89tVTHSOY}?8CA)}h@yPwC;E|f zGD9Bw*G}nI>Tp{JTKEH9(kERf@*HVM5Q4cO+ z+KY#9TI<0-`h>=i{kSJjzYdb5XnYs+6G=NrNzbD% zLc$TKSiQehA8J5lQj4H+vneViu@v#a@ z0m2yOz4?FMYxU;2GwEQ_yl|$GN|l*J{}9U7N~nWwP{{<^cFr=-POn*)*)8BWabIaIzz z1ptH?VBJh-)q53VN=5T2qhh~5_`ytp8p?d|6J|MD@t#di;LAy`CT$X;5EivXUg+g> z(ZY!H^JsIhuC-}|*56iBTA=dWKRk!3)cTh8JKg$-(k=&ss&}!3b=93ug}S^js4|v9 zNQfbCbmYopW5e4dK%AAOYi+KBTW+%w6>O5HTOB#RzPr~sS=z;8O3OlQ@VSC5Q8qS| zq_8ehvFbahps8wMr|KlLSx8N5SxfD9XW>^5;sF+i>g7$RaV?ULrLbBfZ8&@X$ZoiI<1{Ez(!3R(|RY-+sAar?~J2hYEPXyzgjn^tXmzUeER!%}xq6k%z zywf_x&}Q^r%*zZy)8W}DilLMc&B*+F=FsV&M_*A8zyNa@I74RHQWT0Q&5n@kIG{pb|KhD{ zj0h0;S8G596_9oQh4DkEJRy*fFv;Vk>W|d1RfVdFO5Hw7hR_u%{CQ|fPy!M*s#-Ta z+-a@pOZV_T#NC}XS28bhLhH2Ko8${MR$e^y;I8G*p+d5`9}!{zjO%8KtG<(ncr2WW z*cVe;5^6(4g2Gy8BIX$EfDwSC%X}t=*b}wTbK*IKQO2dj-dZI)J9QliAy6c1Lx{j! ztG5sI=>lqm`jQ~#DQBY81w4mHAf}u*k6T+zsi&+j5@NwX4I`o?D@s|Fs5QqW1w6n8(zt)+lHr?Kv1yp#@?+1ENyU z2eMi-!mKHrYk>+$q?C}8zQ!bC6##++hEnee1ImBdI|JUfc^nLrFSWaWu-njmyRDm( zuMs6m|NqaOD7k6cwcTzz9FT$!7TBg41#R$*vMO6?oQ9Ot1!k!N+S@-`dY2NH+L~fY z(EmB!|1L=p6cI_>tf0Re^xm5!No)2NnbAuKzRtUwXIRj2oXK#>OVxVwhDi9cw)XMvR8%em#pG`ZwE(^fu1m9x_ z+6WQ=)`AXR%Zt-%QgPzjVU=seu{>$;h~Ce8Yc&q14(N5f$G9>tV*7F#^pwY~**bdq zZdH1obJo5%0o{Mbir0Cfdh8K(aQPFKO3Reh$R69yk=hfr23TV?Y2i z`1baeKoZ@*Aox?j!e9nL0FDR11i>F80D+i@lOP5vg5b~L{njdGVu3`Z3W7fc(<&E> zQ%tA`fz_ z@T>H`KTc8|dO~@`eeA#Vl6vcei#Fr89=v(ZcltedrYt;VvW_0*ywK=*$C!u#+6k$G zw@2Bj%O>9#b?3=Vv;7g|JXl8O$uSi9pLdqb=ETjtF9(F->s7}gGr6*QhR4TjV=Uqytf(cS^{_yw)f;Z+8DaTH=hPKp;PeI zFgC2qn;kH~ssM;*84{O@mt)lG zXOsumU8$Ifxw;Qh02Wbzi3@54I0?WYelP>DB)$<;c2g!`E`Zy{Ts-&`I|pH@-G2Rc zmP%FW3^O=^L#p6fF-uH|Sph>bW+M5U3#*JW76$Mn$nJBST zSasbj^^T+pB|z^-^(5&a=d7ZM(EF0A6edsgJhmoA&m&3jVJP+WeR8Qjo9Waxm7Ah~)GDd9-c?7`!#bcT6+u_-%oZ?pa*C?tb2eL}7hr-7sXnD+Lb7eUNZDx$US;>g^?XCc(v80oVO_0;D9 zv3>k@W0f9BWtZzzfB76v1y_pIfxzW)dzMx?CvMH1+GccVb;`wBo3+c8T2T)#+3L)` zKe2iAB^dVpy%{T?rJ5ykkv{(0xecp=>qE)RXkG~or<~()I;nV)X~GU4SEe5_-0B)kNGsEx(TU*Yn4h%LO%J*@mn5jUT02{nuyMd z~9YwwUZ-}mV3?v1cQL2?>luUo^#<7gu*{S-S()jQo&ZdRp=FDSS^R9B@E z%5H&cQgR+{+#RxXNjeIZM<>&h(ppD8c-3-wRCHK%ETo*Ehmql7DyxlOvFbUgD0!*+ zD@OlI%+WKlk zAhnj&hW=iqBBb;oR?-cw5~W(nrP7lNp~`HG?6sZ>E_%HGCrS1M)##bUa_by6yk8L3}LWhJX%W6fEnODSpI(LALR2uk+sZ3IhE zO;UupP@7_U%srg_zteA5Dk0_+bN_;CM9Z4VH>FauR7+w*5minC6Cb!Z>`aruwPe@F z2miJ?hM@%j+ic@B*-oc}cNTxUQV}KMkSe%JN|{n+zhKhV<}~$W2JXERSM@=^yUE|q zmYIMRb+HDAEh~58@tH zB?~yAWS=0B9ZBLt4_>KUs-}72*G?lv0n^z=PV1Du)1t3QMFhvC`ut<}PY{dg23JZo zA}Xw#4~L5?bK+@50gL*$_?A_anx!Sxs#K<_6jhd--Ks1J4W4k4-V~~W&P84;R74k* zikW(URI0!fl`6PO%!pJ;PcBs!Booft@pvo@%;Ad>O^{^!->E=UOUYSaW^;C+=M?3x z+1pTS0@iyE;CiJ}ths**6RdfA+MDnB zZ6FGQtU0nq~C&upby ztBy82eDu?9oj!8~N9s|NkKdl~-OS>Cs^Be1RZ6ua`;G9<^g)tHDOo(Y$Gk82etLrJ zR_)2l9<8-n$ro)LJ^GAPI)K2Qkt!K2Zl+Z4W27RuPD-uT0L}SyymPz<2j%XkbPvv+ z;n@63g-qs1xImhQKe5{rZHdEBb3m`Xi5O=*Qm5HbUqkfWMMXE`QuNIN)=tH z5SE)6)vO8vQ2{Wj!r&|XUN)5;wj{?iB3ijGUzq1!mD;kGl{fj4^XW5ERr3l}fdw}+ z?SMX36%oM8Shnb^=`ed!I9XkK)TnHYs?&>QEapBI{k%st;AhfgRDaC^D$7IR$7CP> zyho%@uce@rb1Cy|PXg9;lY2x<0G|J~{dxNG3g7Zso#`erqe590QGBldz|qKcTF zW>b4cmF`A#p3IqP=wn}xC|;dL^O@m@{IZ;>(j8bp z3B*QfJT6y3L{wOaMFRp6TlnBn?d^Ttn!~+)CTFVjznLm(R3I3G2xi7$2C1s>clOS- zxpC!I!vK1bGZMA3Es;JmNv0;BZg2Sif9?X^lr10ICpW3Or;?IhEhfQb#3?-mG=Qea zz#=5VEc&nUR0@$iZfv^x@Kg`|c~B7=Bx1&dO+ZOZM736KyAc^m8UN#<>g>Gd>8yr_ zr+Vm5Qc8^}Kq6pvRl)M!Gm|lt3sn(AP6jg)0{v%0b^aY%A%wo5x;)Fu!&5!Y+bD4XTuYoL>*y{cgYC?Y6`0EF!|Sb&1%m zM)^|K{{~Ohhf!f3w!`;VOIQ!Xun7-O_0Xrv0K8O~-gQQ#ls>IQ^>@}k?>6MObOmK1 z7N~}8!%Cp?j20=S*v^XV-D%jKJp38@x64uI+oXCp?zYFU^i^EKxE+T10o6kvl!-WF zGPSDr;EEOrBVo$ae2Q!%LySy-m~1U%5>m;fU}dh|_n0q{yVApHw;$$ZzYvc5?IDEAxkq-FSDmNx^m+6rQ1Rm{cL&8<E}5U9Do zE^6uOE26%4+pv-ASchxU;;`SHLeLXjXOH zHlbnx*7-(KifAKaDT!iaHd(PV(XykMa#qZkkz6&F&?;1r+53vo*vhU}_w))?L^L_u zlyWhv(|&jKIWJIPCWNm=(4fILtWZgUu7(%UM^9C%!vEYTcq=b0fc1rDRp|Po5pxq2 z_Gi#dvs}j*`boliyW4Kw7k{T|!DxC<*|e;kA5h(cauTSj;Nv_P@~iOVy<;X!iLiR- zo@8IfYCy;`MCA3zh!7)L=U2{I6Mw}(-{qHGEx{yH2+7YQS= zoAi84CIS%)RND?!8&nZEe>$l4k{3KI3ZBShH1LIxNPcGcZ{H1oA!`7YGkB*4*~bo# z!pwrfjXZm5`@e zvKD&g^AzUwNm4THKWYw_MK6cp@G^}Du@7RO9#GwhOpMHa9(KEL<5n<{*D!hw?8w;a zN6Fo7`&TY7fwO25`jeQ%Chxmp?ORos__*DUjxa{UUX#yHY-|Jr<#$lYW_MIj_pjQv zT^+q&oV zPQ$P{>tCT^)TmL88=qUqCxfa>PX!)!+fxvudZby9l2hpa-*8x8ncj^}tBl%lnZ)|67*Y1r)#$MJO7$v3V!C2PoUDSI*y_co0}JC;x63BE z(330(U4we8Fv}Io76o$BA(aBB0p7S3$+-`*eRrIC{5Ng3viGnRvz%N1$;Zs!yO5BB zgd7GLEF8Xh?^m0h#AH6AEma-Pc3gSUW+%apwSv(cULu7$;{Z z3eQ%qYZybA=W)<1-jdhbi2XE&=MYA{@*sOYZ{(_km-(~%rt65JYrdo?JI<5tt_ z-BY~`g3dV4VOk&6(@%=kbA#$Aai3@ukPi<}bss9VYEDj}5>Mn}WIyir+bMFb-pj!0 zv~o<QKmyW4k*9kvDWdJ|D#H!(%y5Nlh5yD13&)C_JC~kk8m98)gC$fhar>&sV zIw&MTshA!1hoDd?cpar6MYdiDmRRrmFbwNie3MXh&{63{HEo8ic(^I(@@X&Uo*tg+ z9>fY&R!_AXoyKv7S2}KRjMZz@_GHN9QvFH*8$Bjqw-Eq+w6y}(RdX^(R6A6q2&34c zN-5U{Relc@6j>0fLZvBnF-0+m{eLq}_1$B5Br5Jin2Vn~NCYY4>Y#BP1Gu$BI4;>_5!j!$;#O=*6vb%`Pcbs4NC=jZ zVg!Y1JJ!;u;#a8Zt*3$pRb*8u&`$|siT@m`Ui~!$iwFVr1=N)+5*kCFG$JnHpN^@N zo+XMqbf`ANeo&4?7acJAhkm*NzH;29BfbuuhCIiTb>5(Rlc=bd$alyJvaQ?k`B)=7s{ z)*8x&$XMo&Q2lJ98Kngls2074Dl1ee{Zpt6S^|4BbJzkPSiBJtd;%5b0_s{cYY=*6 zO8bp=p+Pck6)!QV)XS(@7uG=-JI*_e6D2bvhpNQ3Z9Yy+Jq|o~Xu{MrYxMjE)oyb| zPAU_>!UL+iP)q_<57%6bgvPq#F#P5*C*f#+_!j1G-{yJ#c9Q66!m1*J;-YJGb$F~RBC2jlRHTdm*dYY~l4n_<@}OeA-VhL4qN3^&G@C-j@P!bN$lR* zVn``9sCKW}@bhzn>byX;m&+S=dNuMf#oSVY+Sa$*{sW-kwrOxt=2o(*Yq1K)hOA)AAA!$&kT2WY_Vn$>i zj%rY{T6&PM)+c6oLyQsLLshHL)Ar&9l?SdOh9m<18Y(0}OZcw9W^UV*zJ*!wb>%{^u_KNq!P8(`5kjO?$oRsgr?^3CQZtB&>B-pR6mVY zyRJ}4PW9!rEig<9)#FE$?|>;5sFG_C)RGGk=4@(=Na%IEv1xHp*Tl?`&^qs*Bvv}^ zgeoNoGb8lkZ;Fu_dickc34xiHI#mK-u2pbtP`N8q{C|Rq@~$%0>Nq|P0+maVoiJ5v62%z%e5x2hh5Dqga}~?@2|HfK0)qYP z?{xX1zMV_2Q|$$+t`3zbv|*Ie)pYLuNQYBHkNoCg*v!MV0izA7)OTrvedtZ^JWT#i&qqFJ2SlQ$K(R*vzf6oY1K5(-lts%$8_(^jA&z?PyQ09}MHgvNGHWf5C? zo##f$Nx+F4`f^InWlQpa+*?Bi# zXM6PQ-zQK_k9$%rv0la&8&`p>Yo**6 z4MB2JGaVe*WSUQ+pOWU7t1U)DKgN`>TF36V(~gQ_GG$;<6u}p=fTTi1D=$DK{P9lT ze>{HyRnAwa7Bs>eRGRh<=kq^WTqp~jDy=qc4(gwRpfxH+VpjF4?<}r&y-+66pLn}j zv1y)a|K3wQe)Z!Xg|wv9D>J0rF%ziRKMgzeUrjDd(=$;i#r^p8>xZuubB@s;_QU9_ zN$9m{aK%K3 zM#Iv{G_1X&WLgGs^bEZ6v-V`Ov4&D2Amg>cPRC_2I>#Wy7Oc*VTfwkeVzS6Zl_`IT zKK%B#zy9rqAvDSoDx!dZi*!++pIjd#cn)7d)#n|Cv-+u7hD$##%`BPoRscSSQ5ce) z)rWPBdYyXE5;2N%(uVb^IjSHa38jxQ)!pCxa`9CB1{Gw=P~BSaIkk55`JlZ?-sX&c ztrH@iyf@B2N#rADjwzv+9N4h&qWQ3wotbKdXfhM}Qya=ZHF=X0B_i@`?c!dq)cDhu zrVL-nF7v4Xnr9X=l+It= zc;{>`Ug+7W^>orXt*sF^QX+9?Tb+_6*8O(7_N7#$7!w()PlIIN<*CJ-7e*sSYpk4T zzZ1Kd#r0uI3BK0*`BVU?4}#kkB}MFWsMJ%*r+f2MOFz;wgLfE?$3wfuaX~F88;2nK zOoJ@-1G|DYlyv%(&u|Izsm+2uo#Z6LxPR;Y8y=qOPNB+Fd}uRu3E&MXLK06TRJEFD zcS05**Xo}XCdEM^IeJSVLKY9D)lY#$cdohAN+t?C8NGTs72tUz8yAjr@nw31e|IM|7LkOW6_c@r;07vScCzK$dj8AGJD`*- z<(v|+^Q*ti>-lNrz028@%8t-htq0HRCo#sj+=-UCmaJ5H=XGy+f+iCgi%F!`CTFwy z%s+ri9zQRZ;9pcJ9jfKm1r|-ZyxfpX6y~+I2dkS>byJv^rJDmAlA%ct?Zscwd79Q6 zImM)!rv;&)H&=RufA=Q~r63V|M0095YZdDaR&ak&}m5un=M-E$gxq z3M*4gz_J%`Rh6tBOL?j+ylGsh%h{yJ^?LSF5QrJRkZofr!hanqhMaqw#QE*Mnc?l; zn*G_A->^F`*y&Q=)~#x~-gL7YuX8(EACk1rhDp~Iv`Yxn8bvYb#)5MyJ7p@@XN*3gu4@1Q6kM`0Byz{wQrM3qvCR*b|d zISwesKlq>oi2sJCf)15{a9PN>{UNt2EgiQv=>f0XWXsLsdD(ff_8xS_sY{r8*0)Q4 zd(^4!P?Sr_WEd$Ws`bNWBvJcQFeM~FWJ@LrGsYkzmMR-$4O_ZT!O29}dt^)LGdrT9 z$ZP>gtY{FB5OYLDjYY)rm*8ut(1IZZ{CA*&yrA>}p<8#=VYyY058pN{9P0Dt1h@Bm z?n{p!D7bUQsI=r%F(qRKiQoN>2U;>F0+23~{a^O(Zncdh2*dDK)icV0vn(5ycp;~I zw)K1eH@E$hu`(pG6N4eP>ya=$qd^9Xmu?A}Mgu!J10sZt6Ns48k1)u=oWxs32kW#$ zrpQc*hzYuxZalBV#(O3aGi3*;;s$QScve&-z?e{01Vp(`HN*!R`zK$N=h?iJUhDgLq@wMU-;JY3?Fw z$Ign4Hx_A|G-hqwz|7tN8`{I~yMdU9z>HsH5D^?-(;N5m1_UdVqqiTf5091JQRQ*@ z4<@Snb5(s!SnsLc9}yWPHI9I)a-O1s8INv^o0<|h(}^%j0+Dq9Q!+Vaj#Dg~h|y@u z3=R<>V;qhXO3WfM5;ZdhnX&0$tSU<8j+dzt=Er;w*&GjCFFUUe z|GCb0wLNLM!SFaU!>`EWDFt1Q!|n&qXMjz3Da4Jjy13>3_F%bv`pKwjrYdg_F>Uz# za_(!--}25dh(LWQ_qfm9`9!~;kB_tG^EFeIcZUcYV?^^J>OEC?kBAz5e%dp;yT7lQ zs=P=1++?0k@4jZL^4<^uXiWGirlvZ6{Pd@wM9dgBQyw>CUUy}dF<3V?fO#XTSERgp z3=ji^m-56HJ#2C?gNdnDf2EXCem7Qsf>KH;rIb=iDW#P1RwcgwpO3{lOy8Wt`6_p; zW5tzS2WKKc=6AoPK7T83N=CT310sN^nd%s4rm4D{ncFb)gQ|+8yQ$7YbN9@I%?E&S zAfg@#z@fy1OeWeAa1%jBawB%9O_hRDRn7e<%e`Kb^6I7AIV#KiCMsm&8WmI}kEjx2 z-mR#lGs9>~BLJp|%ze-OvV$`LcNJuiFg0gq5pKayGk343%G)s_P$0($Lq@8sgd%dm zgUpPyE@Q+8Q3&Aft3J#!!&QYY54I#0n^C#9CK=Hp8-ty4ax7V!!R5j8VJie%rBu5XbrHqQU!?|npNGpZmF z$^EX!c8O$_Ow6c6q`os$-UP+$$X8T@&!{>9bP#klc$lgkQT?ZCD~8#Ws@XAViR>Tx zz6tZz_m{imiV6{tBdW{CzSY#_LOL0+o=3Gl3M{Xm=ZMN?M}kauUkA`{nAr+TJ7gCL zU`=KUauU73$UI^wW2Doow<)d zR7FM?fUR<7Kz42l^ASO&tmzHN4vJh+jiyGUP*vLY2)|rD{55AP0A?Z?!OGftRDbrU zh;;#w2~f$#t24y2qk*}M2=Z+0?%;IC;aL5lLw`3*>bGGh^oDLbZG zOQ@~=!{PA;1P*|-bvMf zh#yHMAtqLfJY6o6C5@roA0(J2Zov&Rt9g`&FhKMufA@PirKV)W5{;ciffT6_GaH4q ztz7ITRjs#LgeGn@sU~LbX9);JMnQe>poC@=62c86h!6-qg7|bgZTY&i-9Jw|P7yP$ z`^Ig~r$gIs_sP8?fKrf%Q;W8(gy-{xL#%z@gm0(Q4-Qg^a_-MdWKNahr-v?;_3}l5 zv^zO{+tbrZ|D{qy>Zq*`9+LRi4Xh!c2N6CX^L{?;w)=TL&aTk1VarqqjCW0* z`|UdY36xUX>HTGM?I*U-3`}h|Q8ucWb7X(YHdQcZm1=%U^;Ig~?T;_a{-|Sr41^)o z;9)_G-~Rmi=PQ2rC1QYkQXO~uzW@7Sb^(|v5E(an_RG_Gnf>2uAEKe9tGnmn^LgL* z?(PjJ;wQIp(m+kT$s1E!ttIDdRod|H_#zdQ0&b-XeA~`@zi+84UoG=#x7w0_4o z1cDE+oDRo%@m$0cUr+O4ze$GGlDjc4zj^Q$KskV!jgtD{At8k4FYozR_;^lLm3<_(u+~~b zWG`2onW`F}x?aW6?hMC@rWYUeZ4y=W6TVz8-;uCM)gF-uEErEdu-o!WGniMYK)|ss z6-kI|pUQ%&Ql%1zMxSc%un-~v1OlP;Pl5!I@gspY4I#ZM-WUJ{jFo$$0W zvuU!pajCW(160D8I4Ly`)TKJH6)>m$q)TNWO`*hV^S3vYO{+B7iuDy0Eh>Go)hN#R z?;AWM6yH|V0iE_8J^)>+d6%jxP)<*W!zmF~y?9w};uI;VrK=a}rmUL#@Ne0$qsfdS zU`t4Arm{l6q{;x*fz+#it5jkpt5onyDzFAX8Bz@%6%2?#h;JNQv)6s8sA|rE*V;H{ zdiLbx^@Pji>g?wEFl91I>iQfG%lT=0ojBiKk5|5Bs!U)y%`R2)OHu{0^*$A=I6WP; zc&)2cYN{1(45tQ<3K1Y8;MQbrtRIFtxaY~<4snpt}g0=a}RVqlg>aA2c*DA$<#!zbT zpiua4eJX^HC|#-qga9O9Rcp-IuE$=eVCIx^*2K9`wTNb^MJ-L+Q%gy#rY_ZdJaGai z=PniBUStGa=TuMtnm!^@t3tMQ_y?-B0V`#c)CZ3V{)bcn=&n@9T_OMi3Q(&mAnE0J z+)puNL=_^`T1tp!s+^2MDFu0&+ggccMVD$~Yf}B}Ql+}S<6Cu|Q$cfOb?Q~BnG;AI zQVkws=Rt%IA)qf`zrEq>w?AT_I}2*vjV_e|NS_szVmck>!^NmbtwO5FN=6G{%xsi% zE+z6Z&p+6t1pIQC=PA{Q)$DTgpG;IMv!%+i+6rJ8A>nysq%6>p4rIEVn8G78O*-8R8yi-vKe3r0A{8-KKF0% zS>P|$^LtX!yKOcxK!m$}s=4W70J%%0nzO0$xv#Bd%b8uU{W+0^s@MHte@TiFi}BLx zdaA)f%WDg3h{(M?%(*x@LsdR|@o?g#nlwfvG-y&?`^+oloRSe0Auv;CNHzF0=)Gd_ zAu%+q!n?i|+##mEh?W4F15#^~%BpVm?#YFn&Ef;PYswa1qb>L>1 z!EZ=RR)X?9u8YysV= z;!@Sfe&_68t>bl$K_m!h;-_1%Ep_Ka2-z7+l?I;#zUO|aA^;#^48NozxHtTxE>%)_ zkxH^7ru@{~zV1%f#Df8;FS+&5VQ#9OHj0HTLgL?+-V%1>4(ClGj0S!DCm1)UcEug? z=On7Kz7aAlhr?~r#+5b1GNc-OE<~?K0CaCi7n?zE93n)x3wy5EX|1J8rCK4EQney) z&in4wa+$DXR8@?bucsDUKhVP514&j2CElHSbh)wxQKyP!C{ok3Tl`w%%qT+Q>Jszw z`Lyrh=VTrR7|q|oXJHm2Pw!yXj|$L;5dq(x6Cn`72cU9$T$Lsjbg4>{io_C6o9lJs zmn($=su}~KF?+Oy6P2I2h{Y0v)X39idtqin5^PdcGblw&6HnY5$x|XiK&n`Bh&|FS z8ITB=sSd3Mp8!VX%f6?KmANH~J+p#H`A3{hW*~5*0zi4alGwOkF7Qf=`X4ob+%i>@ zdv$`7C2c0jYu4#kR@Nu2coedkntIG&e2DtsGg0hP>(u(!U>WQjH17VDPsQk!Y76 z%X>}>CzJ7M{)55)fl$F{+?n`=)SW6KV-7MH{9PnO3Bh7A=5;3T$0;U);*6L227|wi zNT5Oh5dZ;2ghC*~f3tVTD~iKF7{KS7DD^Wg=a1 z&)F;Et(=Iqxysb^lry=B?lLFJs^vwR@slCi&TO=vDoM@AP!VlrXTXRyF_SA(sCXAb zqVEfpSg$ucFHCfIsM0u>XPj+8bg$IdM1-Ltx?ieBtEA$*K%&jeE};@LHxt z>#$u`pf`{HG{oR>x9?sDchgZ8F$gp$Lq*R3kk25Wn-40%T*RfgT7G7gKt*Hzy}$Sq z-EEW(3JKgB^aLQP0{lnbAfnnHt*o-pIcC~B*{x8i6!%{(OD{u+FNfBv+)X;DB64@o zGf-5bvIc3e?nu>j*6{D!CC)>CTJq3-P37nw!_>2WWQBB!01i{oQ^5RK=LsrdT?8bm zuEMqiDhlvrs0#AW8l)k+1dZMTwsTFgP#}Wi6!h39VqH=?pU?4hs>_sQVL&UNmU6E{ z+q+{gOJ7l%%R_9{WVpG-;(1pam4_HKg`5xd_%9+!hd4xzQ_v$S#jM3CdiENfxA)`m z`0@UBIwvU9-AvQ@?fv6;{L9{%CC81!02B-73Qkgq6OU)qa*H4U-v4q#kdl|FDF1Tt z+3sdR5Pwv!AaRlJ_jSoxfJp@0F)xvOgez!KMU6g2xb?wg3crWg{KwPNqhshv=8x_1 z$_x(DkEdTxKc`fai%O*+!e*LpF9-J}3n3*`lI1=^?Q7j~A|rt+X^n6YVL_r&kRRW_~l|;6dvi9(@w(v%93K^pzp#lP?7^wKp zNnn7ZQa#K{HMy!(0K_>;Q66lePZny&ws1-)6{Z}XGBDg)qNT7+pPWt!Pucyc9)a1fa70&nmB*g$}c+%Qh%JXtt1l>?2 zFHwAQDa6Aba&y8M8GIJ(Qr(+KBE+P_yHlx{2ml#4aYDC;KKYwiV22=mNpqrVa#g7W z%u0WD+60q(m3{-5g}8(%LJ3JY=WUEWC}FwX!x(d94UC z3H|x+Sf+$P1r88GxM|hoic*PmsltJmOyuUCBsZ8aagiW*4ynwHZ=0;)7 zw#cbe1B@S1<%E`EmD0Cbsi?j?oN!K5O)e@GR5Kk80Acco5$_wQLYw8b)1?A5lhEhB zuD7L+VSt;Pr9S$;Y&+56b|w`eAjSt_?Q4|2`(GsbDitvxO{peVq}GtiU!?+cq*4mH z8v#`6&sX;`PZcbg5G{U$jlA4*z(i0C(r3#3U5iz;>V?0o~Cr+#iJ4irtozmo* zQpJZEjN3m@1tclzZbpigyHf{4DgaZ;%lf9;Etg_eW$B*1@h7RmD+2c6RPtI8RN-JM zHMuIai)Dr~q$-6#gp^Y<1g|M7(z@i%_9~T;koiIiMO zMzzbW5r||VIE4s}%)iI}k7S8aRgpgI)=JZ=$puk02q>hw52@;~f)ikA(I`$%n6&It zA(&AS0n_iRQ6%{>OxW|j7V@wH6yd`l&8v+%nS$)5a<2hJ85K_Rs z%CfF&7N9Ow&dEds%C?WA1C-pLzp9pkvh{~2M3fYLFng^PQHv162?WMw>07T;jzp|# z3Gn@XD#j_*Pp$!oVRxtnzHvH&LD?*z%Q`?5dnv2vYSESZ( zN_F1}b*wP&H*`Xn^H{nbZ0q_m3XzX#s$0$?!>KM6NZwwekCEM?E%~H4R&;;B2^-fL5hz&xZB)MHTeWcNJY@C+LuX$Q(4HYbk#<%#d_5uK$4uOqS)Hkm&}lyB_I0q zY!NaxGwta|e#Xv2EG9IAcN= zAti((x%)?igh&Wg__Yr~vlFQ_G_5GeN`mB1ok*!prw-0|{wvQk+~5vv*BZtyRJacMGSg*KvQS7DtN|GXn`gyEt7g8>+Q- zgy?=jM;gN_ zfHSR**8XKS|KacClVGq@f-Y4Sflx`hRBxJzyyXrex}OLK#~IRFaB9^Dsclf}ydaa$ z!(qu#=uN6&lhh&A5KDuW9ht|8f%G2Yq<-X3(nLkWR*%OPU-F}RYH^5 z-%?rO+^{c%`xE*1{eyM0t7+h039qw>DN6S>k69}0_rK&*F z6)G%K8MDCzZR|6u6_=se;nbc|wVz#{$e zwA<}YY1y6jO-&W}&8IX;pL84F7B-GfbAIhp_?gb*co-wMPbc=v+3Qrs1tCT-qZ{92 zA6O{;Bw@tJ9Y{I_LQv%dF;t-JN?zkJ<(+iuh5`}W5s zYa1gxcfZ*?v*oyPB@H7JOVu>D;sUcswS8g~o~wiP{aV)JY0?zLdcH-Boo8j3gv zP-nZX>-)vNB&r&^vi741wHtjNP<>gbgcBYZD(NspR6tN6pakMcfRauGluAi2y#fgs z6nbi&fuVv#R5_~gRHAC6ii}=HsQ{H`sD{29ZUw3sg@6dejdLM_nfrb=1Sea;^b@E+ zC=dV&4!r&hD(1izZrXtH;>scAG4f>+W*9b(>|SdP~-J{+8{f zVm+XGEU5YdCX3AEtWyHTh{za2)Cs*RkBN~X#6!&-N>GB@LQql$#4G?}ObJndR1hRJ zm$XC2Q44{fo}0EIYgwssC{Q758f#fL({P(j?LQvj!GIsfJphyxKqjb&|9X>*R+0<|#O7?Z9HRXQG`3y@SM zdJm|`lgWeyLdv^%YDy%n_AGmKj$%Zwe%<5A8sTsvxFyeIPqH7A%lV6;mhpC_rGS zWJbql2>__H(K#THN5llze(3fbLgWsa3K2m_0&b?eGJ99?6#{Z*K;Jh&#rh-#%iMUFP>u#;Jwz#;&Y}xMCFX#NfrW-}J zGv2;{d50NM=A6Mfb+K1NI4H?tlXX&>cAqVKO^P0o1q`IhT3^U}F^0(sCEQ{7NG#(q z)Vza13ILTrYQKk`SbS!vYWEMpLzIdeT;|&_nXIX-wE{9s=_9C6qEO$2kbgMYDOae- zEE!RKMUTiE?9)L%>5I@tryr5lFbt^`$8sl932h7j7e zbv=37ciN|lCw6a-K*d)v=1JRe9IvJs`@ZX@#+c|Cj+C_7=dtVierhioy<-VuBKE24 zZ^O`!%SDslml4u9E;>dDnDtKQduBEPSeLFnkEsMhB@uHr-$%CF?KX^uS%a)!AL0V_ zefZytUj0D_Fp9JLH+JJ<+mYjuRIpXI3NY<7l9RkU(RL?Hevac4*Z-hn8gBM9j^FPD z;WFHYt#%Cwuzs>ssQffDRo(h-Z1)$zdg8^S>B74&D;|XH@2Z`j21p7eIX(jQ-T_3b^`I5fp!o@%GVlF z=b$|*>5QJJo=-q0F4lKDs~m#*5Gs7C@55J8{E<|hP+7Xfg)VX6|N6jsbJ#w2Jzo#Q z)>K~RzHbQ~`WG(j*-)6N5(mVq${0Ti*;5A%f}F-_O^ zlL6&1J$uR6s;|wf3+5uZi^UFDlVyFA##KI`NT( z<9+z@SO5vA{_~q{0^YkoVwGiw?(4B@`5#`oo*}7Wi?)b}wU*ueXc@G&ABZIuqwzKs zx`uAI-|U&Gs>hM9uBYD`KC*50ZEr`q)MaC=Dpcdx?qu^o#r*-*m$1m@3sl|J=%lk* z`k~)-W|TN+Y&2?ZSe=GlOGI!RHTWNs$g6eR_1%TMUK~p0z02u+eF=*x5mcEVxGhEr6@0$%tz}Y1eWm-5M^Y)3-rcZVvXCkhU!BRUa1IrVOvw`K zvA?}S)fK3O|1VSJD^wz8Auyna;1MAcRKuhLK+XaJ3)Lr6B~S|Wyw)%U0=ENr`purj zyHJG~zt!#^lW|{*1f8R*rW^W0w8%}AbJ-Fk)~;>WwYPp-S>tuw)UP&~XU(;uYB zx*doZjWHq+lRANO7(#l1iby@6%APHTH&B6-R1X-1D0wRFiur&5L40gAM+Jg6d=al# zLj~Lj-Z_$?`o>TVbD`(?Zl?+u@zs*_*qWIt?x{dEcHPc`Ha30#w32e&W~PpDt1MaW z@iq6_`@5I!UbU@EUMi)H&fPDyV%>@3dAmNK`U>V;E>I1nrBw3xk6QfB2?V{+e&)ZGFt@I(C?KmhN|7DinCZ_-~F_Y85Li`7=fZxoz+?@ z3CaBIy1%mzSuaCB{#!O?A3EwL_5ML#h-Y%8H(lOcz$RP9q2N`u?QabSTwgk2!#ap0y5* zZe!cDZQ15qKU(&d5IX7AypJSrv^z8eP^~GMDm&LK)p|ekRLeZg^qD4}AGob2R1Fn3 z;*Q1dCw2ey9ER4?FGj16OjUILDlb zr84L;BENx(g^Vnv0#z#HBnFrJdx)IwnoJ^ld54zzB>5{O*CI#(iZ*1;lK4`u0N~vO zmJcbFKm|c>kNHYfsa6h_lbbHD@5|TFlbh4Q9SPLl_3b_rJJe`6^I8pqvhwhYC5)Yn z&o=SF^&|vULoRYNR8My{Rg;{vX#=#YDqfQvS zbH+~OsEOO2L+%NqGCXp>WI^@7P!XgqLyRHk8dA?5v(9|HXQ%|!VH$&0i2B?BiW&iz z5#S&6!3PUMqVP^+;>Y%kLD4DJCzd3Z9){|;#CnY-pSyGTui-@0(skBOLvgd&u?XJA zY3~E7^}dh1z@-|Wud%iJH{5O&ssi3)_=*J4?Mn)%^|?IcxWCd1F7giM1VJ)DG0qYrC%5$9_7Ys?+~$ zTcoZS@iOrrm$uoPeQy>j@7oDg|MYl9#TQj7&Qleo!UL)pBq&WvH5pFwYTiaP)%vA9Sro&anPQ$$0t=LUkZ;&0)+gI_bHl+u@)qMvRb!{) zWaPeY^Dqp=(YkHlwz811IiTu#f@*sx)z_0M5bz4s%L{K5Xw%SrXcPp`cwo+2BMAC2 zS}PGyLe>|Oq*gnRC6P7h5T*BMxOZd}7b807NU3gr8Sja)lwAms(aO3kQjAfC03aAB zYWn%J*#QLqLUsK3&A!1q*T+eN_$E-X{;E_ZPsK3R$5h&#ke?0{N%*>508}W^L(*)>6}coQKYy zP}TWKR9%l>*Y!>whKjSmYay)P?a}>vjH$k+IUk~_W2zWlp<;SCpf?%A(F+2s?^>fI zfLXeJyqLrS#vQw%p%z~0y^xa-l=+JyV2kpIS*HZfaS&rNI+pY3RLRH3q*Sol%-+KBg_<9n9a zn)>kts+D*fM$S^bJ`9kW^ercVD@eCfsW|%g7*l<5sKOhlghXwcuIuJ99lZpNuO@mQ z4Ua13YYAUmDegsXAimON8g5;CA@4rYjdgWiWHL}?^wbaYer3BT^gd<;NW36@YKr%n znPRBIM@r?lV?7m!qZe4$fSmSG=2wWE4ycBIDpj3DJMEV6;u+@MM%DK+9cd(eBHCDh z`}tL=?mJ_6EURa#?%PvGoDo&qwlCc{aK`r~q~1Q1>gyQ_hRXJY3_?Je>nr6WQrVcP zBh8uSsVseJP4Z-s>0$3&{QY8BwL%fIei)~D>HzPDbuor_o#9tXAlulVm23E zBwp`(W-53x(ASaiDVPkbWI8MFF`1qG)Sjxk)@bygGN1$Gn8*0S&yz+3im!W2*OA(@ z_1#4?RN-S-)UlqbCV~H86(&Q)EOdQQmtr$#dDkj6`%G7IteKqc(O{hkf7Yj!j^lN} zuV%S@VX_7_%7lt~9n9@Q2fmD{hR2xdE1D8gC2hN|dzQ*W&XIFhr6-0CjoGG-tnZeq z0jWR$0%Cd^*~inAc9W&b0;GqeFAICSZn|DFB1Dt{0*BSLxhxaaus!9>3Z}eF=F(1M zb*t>la0h% z9Rqh?Yv=D5UvwfUA!p}Yz-){mHxIW!5lTp$NG?RK)25n}n34uSf%5bj zt%PTm<0q5U)$?5mNhJjM1E_$YDkSaJo?skV-ZR!vpM=D|(^hWHT2@Qh(cq z$I_0bUD}4nRknQUsLI;y@!03DIHSU0OsI{?-h;qg{L3xRpGrcNnofT50W6YFP z8C1a`X#_7NBKO@;dSOh~)HsL8`UIW~L4*K7K~fww*V3u1xs;MrDyN)zC*#4+XYV^z zf<7!%e+E^IiB+XSQc8jt0F=X4?O5i_Km0a2nPA2XK}L!$udBv|QvATJ;v7BCCIfFLnMm6$0f zBnqxYKq)bza^5pW3U!JSAx6X?L6y^emZw62`~&!>V=9O#t=vzu$BS^7gi>5jhE6YU zr&+E%KX0KrAISN#dnR`+fBp6(_3iP3f-ee{ir#~gP5~g?eyJ$xBuJLw`e_->gz!T$V%lM zI46;Hz%f)T8yEl*;QzCCMmdVZFc`L-FjwFZ8{6^yFSl{phyvP5%si|H{!ge%9XEM^ zPfmGpsZoT4&5Cz7O^>)XX0k!4mmVzcMTA|n3At%&5z?AOWh*Qk^S0$)-AzLDkG5$Q zPdPWUPGKp+HRYBZzIyyiG191I#nG5$%ZeP6j{2>%^_lmFegru{e=0yWFRCw;HlsTt z_GOaixd*~$ifYTX{zoUp)Zv-ON_3uidU-0o# z9sg)Jm*;wV3_J$V^A~)sRM+p+rIQCysQ@a~y)oZqb=yXz0+4Fyuz2P8he`#&d8N9( z`mY4usQ~yHrlw~4?>W7jG!wNOy5AiVM5RfBLInT-0000000000007{WAZmHtunFBT zQ>C4VTlARWxrRPGx2mjt24p&D10v6)nc^9x zoSiax&owe^?jDJ=QCva_n+cPew#;B*X`*IaBUG2Cxh1Ru?;@3^5UR1H8rXn#r-_6y~YS0IJ%`vz2nlvFwWA?&C?oM0La;FT$Iy2U?^>_Tr%O(D@ zcScQ)+cp3OKoWA#mVCC?)2=Uf?PT&6f&~8mpDRG=lD(#TdB{xaX7p)ouOY4c;Qa<9 zNQnS2q_UP8b+AM=<%YdW0D(EXR6BnKsWeou4zLOnuj&|VPC4MLUeyZF98+E2KntlL zauYZP9vo`ebh}=!x1ZwaQx0E;umDITkk}~^lVJZIcK%9emyvRsBhE-mtwD86S8VG} z#gVdA{WM$}#}65uRVt5+q-E1Q77-cudFMhPGCn9<6{-2?u6eYk&Dx;ue(n4f*i`Y? z@Mv{v*cDMT4b0*IM`V>M_L$n%djdzCwn-)9ROK+o0wd0Od0|Bmr%E*gsaQ^~8#71+ z-KE-jawtKfg!Ii#F5kbod2577h#jC(CF~v$r0q7&NvH~iL%rv)ts;;Su3LjdwT;r= zaHd7nGEzbWosOT5$K&bfYuLC{v`Hm^IpxA3RYU>J02|>}q}U69JI@CKXg$ZIL9Kq8zJxR=jWqHLCnF&sQc%f=1K4EJr4= z3?j+aOhpZ>f+`rF{PTQs;v{i;mkQG^)y~tBh`xOO{KF5Q2jjO-nIOSCQ1S7k)7h=K zUdHn8QyFD(K8+=VUv5`_Js;V`$^1Biwmd}{JQ>ZZi|Gs)IavrYLawsCw%He!I zUk_{4^*Iz0fx_31AHA{2g{Q}5ndiyYOtrXF1#2ZV&wR^}%1FctNA<5@TUTKe>E2Cy z+#fIQ)Q4D`*B=M7bu#VVsoHr;5a2(h`T|G@?;s_T#)DOj`M!9nD$)}1%{x;Qn+N$Y zdjpXKb1E@S!i_=I2ru(1nW?T)S#`jskg9+ww4vc;Szfrd3IG+>S%X&i^zq}&K`Ex% zov^M--M_(|r-OiAKYh#J;XB~uGas%~&zPu8o``Na^<1OAa4HBu7S4RU6zPij?me%A ziL|bTJB7L)?mH#(SgA}_`CCjP)?Kp2{%$gghcQjHmZNz zI{{G{c4W)t?rI#EjcU#1;cuqiiAMA9dMKr^Z)V-4`Z)>}=W|E}&_v!y)d03}D($~Y zWnlVMDydHV9R#)y{_Z>@h$$nax0V5YM=IpyJf!LX$xicpF{zjzUfg>`CE?*!1vlV) z(B7q%m#7e4ZZF5j#Dx;VnyFkhwg%KhcqFsUDcHuTtcf%Tf4-HfR)e5At5kcc+Ic=O zBYr#e4>Ne^9lA@koS1qy0_17pDz%o!Ifjvzd7hUsg0&osu-10)*4(z|dYV`b8iZ8Q zr)s9X2`^F02&cLM=#Z*_Y*LwpM#iH>X;jS#sRFRwshwveV*-L-NtrNt7~Vm786^o- zB|+tqnl#KVRSZb^k3YP+KL1!766SKa&EZ=Fm&?6$N4HD`s%l@Q3W?0XM)j|Zx}H_r zq%mDD{V+3ieo0mPZ7O!25hVQd~~jVVkClWs>vvc zX)z?sEgMxtc6(eG%#=n+eJYBS!6t7Q9+^aBlPXH;IrXlHsWp$2Ss8sQj=UA%NR$S3 zmulw;A%Jh2f1kg+;`gjtr4r~iq%t$C(n5_7+9XK=%SAOK5Sb}6B9T#3zAekGP$DZw z?{rP2H%XQ6OH6gbZA@yLP}_TJy-^hh&B}I>ViO@r{%BpDeUj47Q-awy2nALEBY6S* zo>UD&s`gc?XtkXl-om}Qp~v2 ziXo|4(Z`r}Tez(KHQBA&d0q&JLMhn5?fG}5s%9dfs?q?B53bDh&d%NEF3qn>NXT)E zq|2R)6`pSACA`3_$xh3%+$Ju3xSl;}DN?O4q_UIib3GmgKPCeYk=f+Y%V~|WQ3|X2 z?$pjxfY3-``NoioA*tsbzxd;JySY3r%cQEQ z3r!c7`69A;QmLYzx`B&y;S*40I8;FQ$(K4OpB}|F!Hd*Y8WO5sZEb+Wt4%!>_Cc=Na z`f(8*8B05Sl}gHoVbzezb<^HSL~Oc-QqDZTa;YTFzDB{$pF*dOlxT?59Y9i51956d z@CV6dp8xsD3^ulfa?A?fZ}Z^#;9}51w_SWBROq+QKm z##mxr+MeGYFQGF7;`B6m&T-VTMylmrq~va(yvj=IA5L;hK<)|p?E#+>6-P%@fy=7$ zksMGW8)55?$AEnq(k`-z7+rCVR4ABmFjggs7`LgaB8alZad{GIES|gXiP7^>8 z!ctTeamtn$6dV*4wLn$Z+4ReO5as0{j!z}iLydXEr;lOOS5FOQB`aoHwPPMlC3hk- z?Ft?HmI5$M%tk0+u3T_XR@DrsuoTuA73pzngqjaAo2{yrJ8|cN$|bs%qP2(Po@}2I z6%}U26(XxTSY|=k1&xu37$El2+T3Dzs8j#~R6~2UmiKXtIv%=xGXy;KIgc%$N_F zsug23Rb>Mc+zo)NsFu5lYmpf9OgVRWAvKiH< zvW&Hh3r7%|%)6sNv^j=K!VSl(ol(tJ2k&xbb+z1s;9#&0lj9eQ2`85P1ZLh^B+RUE zbL`S|Hc(x>VO)nPEq5d`w*+{L?w4O8`FuD*nmv08>~eCzE#q}hW9GJXn9_1TW~Y_Y zXG-4T^F;?cL7Fp>S^zR!h3%bTI*;+XJlkQAb;+0IS24o{_qlEk)~V|3>yp`LMr8o( z1hE5T2RI-&@q|~Sis9-J)fLt9E~w>h) zyJ-g?ZbUW57`c8|WUBZWQ_ZME5F@H}7melnj8rkBy5>H&i&>|g;hkc*`KLa!49uw3 zHtOYDn5P`wjB1cf$u6Q2yv2tR=HL<6`?W*`0j$p{%eP@}H{brvJ*Aq=JRB)Hyv=5c z`!ZLzbQ0O0J0c(}s^zT0me$M zKifnu9jtRd+vk()?WiodpO1W&FlBbFTWn`awrvw(7%rJXI+WH05fd?#3jugXR5C=OLMl@72Z_$8T7z{|n3>#Y z{YI8Aua?%LmaUV@giB^B-S|Edk!>d;Rf@3S4blM+mhC^HY%?l1wvn4u;&tZV^5t2{ zsAPM5diqlYuSF#tP+Mc_Vf_90)ctt+v1L-ic!Rl{S;qM1)1fab0vOT}RoyzqI-Pd; z`b@b-l{=-9=OcCWyTBufA+dE2`zo zGqu(pwmDMqtDDq;J&ebH**nACxN#f+la%rbZ4SL_x53#nHc3%@|Cd`)l4rB&?qYvV z0DaRG8hNY)us=|u#pGxqYTp{KUxf;qA^aQMLDJjTE!gi}DuF-+fD|NjZBhx)x+IIw zh{B`*h$=eCLn^d+B+vpEMoF1(_v6Nah!(VrI1&yMfs0wZ^gjJZAVk8vT~e8KsZf+e zA_j(3EBm+je7LKIRg?@>MU+wo30-!UuqTlSl>!vvn4x6%Jc@a_g_Dg%2tg?oLO^N_ zg7_#ok!bwGO3Z@Q5L7Tk60lO-K{TYgA1re1)j&$*bV((d$UUPOQc`Ik0RqyJZSlO+ zDV149V&?NaSyGou1OcpyaP+^O95xUp_auN+^bDz#(2-ElFjErIF-Yb(k5Ck;CT31n zjRbSFIU<@l6xAu!yA4nrocEBbBa(p3N}=!@@)u~0H7#5`FSBf^firm!6Tc?aedjo0 zeTsHFg4@PIWM%|_gu*SHY)S-3s+4QO%);kwr1g6CE*C(ud^>Jmiy2TZy5ElPf~upi z{THd?^ji!NL-f~oPN|q#P8r{R{`m3pKY0bJ#S>#CoT}AHcspj6`!=O2r6g^ZL}x#= zp9#&1CTVb&YP47>)tn@BoP?Z|kRU^DXKz{v6P6J7Ci?eM9rugJPs0RYo&Wu4{6=f~ zw|I7`YONkV^l)^GB*l;_{E6-sGxpZixG|Na#ErAh(Y9y=LNC>II2D704jU67B8|lt zAv$PCb?`q)b^I!o45^TQ`w_gY>$Z4)soaJ49*US_0(VJeLxPPP@qwNbR6dVC-TFs^ z#ffw~VvHDM3$0Ei$|&6JQzhzBg+-TC@@;tG(JcL zD8iywqC%K6ix6T#RU!QHvpMw*a3v}h&x>2>QW4KAcCAEd>rx52%j?k`K%-PBoim5t z8o|S;fH_Qh-L_K_WvejOWk5)eNCi&Pr5ce6K1Qm5kkDv6{MB6D$vsie{GkxS+bb@o z7EeueC;%YJTbD|$m?;mb6hyiMR7o|_e0-${IWu2tsytRzDI*jiRTUAeG((ahgj7dJ zRRFqFM;FXNi}DAl+PNQ5rB^Yb^);C{^Gf1!zhIW@SmW_++?usdP#Opz(H0 z-K4;1ofo4U`&RQyD)bizBn8SKByw*1;QnW+WJo3Z(Ym47UrS}A(zv7oRW0jJsx3a7 zR3)S;T`H*#B*Z-JahW;tPHzpVvK8gCyFy;86A)sW&u;INODcFs1>jRE`#Y&hNJa0Z zQn2wGm$b3!>laVYERcty+dZVJFYYuW6YO6LWGb+c|*OX!9uD#*IM0uN>!#*w{35)t$)34 z(oxliRN?@Jxu)hq#Ikcd5bpMf13eNI=nU9i&VARkV?X-GSYlf9#WZs2%7c8x&jc^TB%E=T831K;iAr;u=097kW zm{C-C-rknZkV?qW3Kgp~4MekSCetvl)uXwwWUO>`gF_(GWiktaklY2yW$dW%+VI?y z6olaQr8*!IuHwbT6QdBgC!X6SD4Fot(|m*|ymbc>pca&E`!nZD!s*c>l&Ux-AKaMvMp$JsKBT|W1LZbZQV@<^Zm?hey*xn3!dt-9sUSAU7 z4F)*IXG+2>LfQZj9=(BxK*54YQBU>%sHdW|F52R`Q3ZG8y>Fcj_PI-4SwZ%Dw1X|Q zlSG1)su4e?e^6ARx{Obp*BC=8LgDjhY@_>Vz4G|$Q_4s9b8>r~973v^k4fTwM(3G@ z01=RY(x|7(%c{lmO9j~_Ztu92Z^to2q9Rb8qc^(mjpIy`GJ;(zuT6juC@IvrU^;s7 zRs7#0pHhObtud>tj#J!0r&J;0RRkGFs#&eh+kMbQ7tG*P%2iMGWnHtylcTEOx!?KY zHol#a{Y&WX)w#Wy9Ni(I1e8l+j_{+2VuTVkiizXIDapByqFt;mBSKwca87xAQz#mT zdiVXERC&xEA5w+Lgj#geQ?0_^#j~Rg^ej=G*ze*qih#dSjr|qamq#Oz>{%os5dtD< zF97*U1dw6?tPXnF6JvC#q}E)W`q-VFIVVDGfP1l$_>92Tc>^acJyh{_^?u_dnGlPT zj(Vz9q_}u?imK+{**llr#$gzWUOD-d*^Dn=|NnDil5)mqP@tOvHL9}+1X89pJ|TiY z(uiPg=lJt?Z}@P3j!nlVtoV@#k0%~u%dpDMI_r606S7WMmoAYtD6&(yg_oOWq6$Z# zor0P9R;%sF@H#`rJjh4J3Ub3pcSr4~+SUS2S-ZGE2S35G)pTX5=F5NtzFzkDuKI` zWVky>%B1XpyQxS{EvXEMjFZytwNzG;1heYASCJ)&8LBp_en?9NATv4FB&ml*R5O?+ zCP>!xZ;Kld(d_}=HmRDayZ}Ion9a^3f_ADvQ}bfph|MHZ!bDC;QH^poMayNu0%0mW z@{EcmRkw{Z)mnUQQe51FaEI(7;oU>jE>;0S?*FBt0I-%Z+~fUXd!9gKCqbDoOZ!|z zN*|JYH%ApAK(06JpIl5Q{rV-U)+Dafj z)##pcn(OW;D7Bzw3R;0g)vTAFQekzf#a)mT2HiW_lp;!zKugtfr5hE#D3tUZVMY|x z%MT?j<1*rW1o~~3499_X z!!XM%yCa>~BhF_@(hf*g&r_Y=l$9cL8Fa%!B~v33l~2RkBovuIj`d)PwYUc&D5-i( zl6YaJ0lU<_l7haa?$0*xJzS0Hfqp`tLaK@fo&)R8@x`4PW8}xTNhKRF zCYZx3T8wRsl<6^^|JXab-NtPojLwW?Z2+%juN|6_ixz0ny(5R5_kX#HLn;umcI_DJ z3&T7?V*W@Mx;XhLB^))>KvVxhUU^Aa)praU8~L*yG<5NLXLsPHX4y7JUeGRxYBI&~|9N`(aVo~rWHV3O+iFm89MBo!jm3T~C>1|Piq8;7q+ z1=XoamFj=7hiBrrTYCzwH~i=s!3I;Qr(6fYf@FJ zR1Zk1)76|(YEr!nBJ&=Gkb1!E;R8Nf-1Fj&q0%adqAbs6kj1(1NZ3D4Dr>%QPj#wE z^)h%6$u%&Tb(_7GobY)oBZxz!)_K4HoaA!}KY_pq6LTL5spUY#p`drG?gI%(03KZ4 ztWO-uR^!D!B-Q%@2uKa!9d$_EQYv$_M>~;w+9(*KBRaYeXa2Byh?#q7z?hS<_L4y5 zvrv=jbztwE#0bzb2S_c7QKfPsT6qZ(og)ZPs#k#1{q;nQm@V@OP(+wZ%_So6G#(E7 z{r)h0{cB>BhIp0=xox^tCu-phQV~)^ME6{u14%L|S)@;{s7A{HTMjETri}bCUCU@c z&N5T?-P-d`4MV-BdRe$su0RMPLV_-YQmm76aS9>lJqF!k&wiRs2&M=ikt{?uW1iDe zOo+g^-t@cecH3`vo6{-^Qp1{NB81qz@AvQGVIkFJ5L-mRJETHLQZ2EcqRMFB8Xa4( zlq!idZZ?}gt;tf^VY;}@U*zGQNa+XOS3}}M zk)=wdsf{wIN6h_Sq%uFY{odGlE%@GVH)EFSG+A?rQ%$N@tSP8LLm?otPckuy_*|be zi_((TmexBjaFQTm0?f6|qROaN=@ODX>**x_td;NEU9VChse#}pnw3f=8MsPAEf9Q_ z5Jduf%ASPD^8D2Hasl{jQk7wA4*hOpN>UlK@B1H9Zye@qs{c_@QBuw@YZNf0m`V|Z zDiuo%*%?F;fm|XDoP%UogP3eAQl%-cuDBRkQ!F%r(u0b2)xGKRPaNf%xk>At<<|Bv={VlXP?PFK$km=f$a!*zZMQ=9 zsF5I|Rv~KPXB8|Rts>2j0a;I;SiGGivUd}0K$4VOKyQ6o{=qaBqblee60Q!r-JvUs zKGx66b|JLTw0Kt~dgk%~Tr(!4Z95NGyBN2Newi-#Q@x1dv4hkG*r-ZW~9|Fsg8nc1Qp`!Ls0VW>!}ARTHQ8f4M;c zl%sC9Gm~rSk0gUdkTJFN`3Fz{rBn^NlTt)gWR0YhbB&&BNe3s!%Pe>%W>6as=@r*l&xBDiRT{>-sia-2uyP<*k|a*J$cvi@@CRKqw9-ut_rl&`8UZO1cD^*9Ppa?Wm^=ksZpwKit) zN){0ScZ8z8EEKczs7eS}B)N=KZk^3EO=jNCvQotXvs~tRlbDcUEOfr_F~(d4tW>B> zb1Ies7fh;kuCjKT?0m?nTp%Ju_K84z{rA8A{f$A}=np`6-wiba_|Ic8fnb?uy}5BV zmafLR8tD(`#$~R6n0fQA^YUY!-w3L0p6B7UR(h+~<_M%|vNxz!GtI6ifBoQxMcaw4 zXCr*NMy==3Z`$_wbM)_VR3Iy_t@*MUk~Ml$1(5H77q!u+%~X8!e8wH5l7$PkYN|L* zcCvbqB8U*PTC~~7&j4cf*6QypG^k>QY9grmaAM$4)Y^`x6OgRYnn=bN;%87Hy!G$s z1`tr63>g=9pH4tPs`W9s9b?$5Q#ozywrSn}-^F*TsytoIM3-phfuh8V866Ew*j{+4 z$2F)%JK0KE)zPK8{69f8__dPL-w-0zqY_X+18{ zPG)nLo^B$7YILpPS{NKv-OSV&S}G-LjWo*W06)`_t<5;p>W#t1l$|DH=XQ^oG` zRB_Zx<*(wl`KMDo7F3g6W`9!ZM1PEDYU^>7WMG?8QmKL3g(^qNN}Y_I7OE@HM;HOK zTCCkv2Hf{3y`AhC2qG3kC_kZMSPEb{JLmit>Y;pbU8h`r{b}QeQz0;D^$=|8#8ai;D@1BFx#zk`BMuNZ^eLBe^vKom15dvm4)9{=s znW(blNq{K}R|)(-C6$n}R<6h8#92{`sQ>~GJI3tEsgSi{3t+NC73(G|QgDbl(>Ygb zR&@vp0w9B5jQ;(oUwr=+;MSiK;v-Za58wBc+UOraWm}`pxv^PQH>!G#i>LiW)nrCO z=BmwHS@PPft>7wMJv~JUU*Ee_)+{Yn@maOegYP8G6IqqNIh7r#1uzw*=FUvwVl>lyQl(^$<>bFOQ3SN+-?XVV%_4QE`pm!r zrQAVBWQ+cw`*QGT7K*|&{> zpj!Q5Tg36xsUAd-5-NgVkP<=&@j-fLD)Io zntu_o5L8qJa>jjUF&e_WkdXR7+DXycYicoiRXen{-J+lrB_;K> z%&c-k*qyd^Jt<0EiE{f^;L@!uFxH^5)v3sVSd8I-N~OdCDFTpzF}2!hRiO)F6#N&> zKjeZlLWu!KK`=3Bk1pB;gw#i z_2w#hX6uFRo!PghR)g8n2-Koag?pf>Q3Du)O6|kt@TtkR~I!9W6 zEj!Dqf5yCX-hcVB()dNrY_ApCp!7Np?xf_tV?_$0TAIN{jx3Z0RjOffGd!TmIo-Z2 zxRkn)+l-17DM&E3U*;E91@}&NIMw}bWB~tgeJQ2Voyu(PmdfC(>RVpd#<(- zMyS=gZnkTCy3Lv^nbIv&RpDBVUHaJ$fVOpANOSK;k?x@Ke$o2JvrqLPB90EISg6~O zPf8WscS%r9eZ>1nRjCXJQu&sYv6RwU2UV(&1vO8$CAboV($1F|>&qSqD(hv+xlz-h zN(WShb*OGj7TIU|n~ed(_Be!OTY`NML0rnq%7=`gTS6I9lGtMDw& zuSQ>wxwV6_)a-Nfakk5)wfh!h=^d)C^z)}vS%Ru>`DdQ$VUz-64Jy~55|HIdNfx0r zsH`=_Rby*WQiOf{w#yP~DuW7LM$0rH4uls@nzDDt%0S&}Ma4N&73l zu5MZ%@>CT3ASgefx-FHzcd8>z)m4MXazyP{Jv%pOJ$kLT+v5&9{Mz;LY3LKcLSut=q3ktIVb(j)|lAhM#r`6VP$9*vn# zL{17JM1pD>BqTrL*mA zvDUpFUo>^J4jXIJNVD20WwmTZ53L40Yrt;w&QOSIUp-~L{I!b+JD~Cns^@yD$5Tlm zw1JB0%woWT5cWXyFi>Y*Q4@fXm~sBHbm>;H;)n=zz6_%37Ev+l} z5JY^3YE(r4gMKqKR`Lz1QrL~95I%sdrY87o{+!2$(afjm8Lz#C=BqNGVaK_%o=E^;FQGrV5hX6yRCNs?q;U_;#o2Gb+aCeg7U$ zzygBucCxPUea9N=Ofex(gEo3SD=ANYw$`3itWe3pn5jl{QPM4x<&{zJEY)HvRVS&G zpQlMvWzI^0zJ!FPf}c<4Dv=T=r{ZO((PgNi)9Jg&4XVgKQ+)jw={pDUTlcDnRn({Q zeG)A()t&0vTXaOk;$789zxMSQIoH$Nr_K^Xdg)MgJJS_IV>YVR=l+eF);)SkMQwV1 zcPhW#LFJ!L^*BP4<+Yu6=JkM<{qM_$o5pf5I0Z)su6t6)|GjxCDKmhmaseTWt)caJn zEuwnQQ{84)(8ZZ$nKgOL`$Q&UV|M*k6jpC{P_xMxRdg zfQk%uA)Pkb6^1+9y7nAdk?OP_3v`XqqmlwSV5x{`Q)L?`>q&+X0LspQ!C8lFB zRJ2X|?Wn>*&+A%)YoA<8*WN7dfQoj};r;jv<#p%VLTIyX1l%o8W%c;H@89D|04oSi zYyG_lj&MvEVt^c_P|7!ewBF7tLkNKv#H>b&Qh4#I2rhyUEbQg9X$n%4ao-`OT#Cem zLG1FhEpwj?^adz)h%p3^r;(zhQ-+ihWr07F_)(eq%K6bx`W>oD{rtabt-rZr*qoLC zzxLvV+I@YN(sI32_4eP_8v28(JKA}D`6>5JSN*tN`nkThnSI-A$ZzM(Z$=+b`LWh} zyEYBa(Z9!00a#{sNnhi zr1Tl7l9cLaEqls)swAblTC57Gp7Wk6`EE)vk*jbcrc@ub>Ul*fCIWHJOmbKlM5wn@ zDztL1p6Bv!QvEfhB4TjHs^qv30Vqtk5vnjVW`i|u)?Q;4b#}6N89XX6rBlhlrK$|v zQYwc5*g3qG1v8t~YUXwq6x5QJf61{g{|M!lQn@-_A|f-;Io2>C|5yRBa%2I@d#dEX z5Wrw!x)n+UM^*WU;wc!l7B0-CR@8j{mmC=;E=0IBO(p>J6{|)>$c0i?s)Y(l&522_ zg5YE5J53_kQGHoo)|$N>jw%6!MZ>jW<`=2t4XHGwVlWXGW%5!jc{U{f83P2cF$^++ zh-!C+8QKD{m9Gj=Sws&^T7#ZR6X)j|LxWg|J4BcYFN-wVwc9XjO+?Ik*GcSd4g4Qa z)xDHwL~;d0WJ#qGgfkbXxtXoay@#uSkP2RkZkW{~u{B07tYlS+fQ&Ds8hf&<9#ZM% zXv_IXzJ^o^GpKr@O+?heCCw42v)QL-O#Dp zFF@N*Z(T|>=OSc;v(w2S0=QI#3ws4aYp841ZQ@eJ(coL{Z0|WE z$>C`RT^D`Udmn+J$?{5puDUs8TXO*P2`=zH5Lbq(jXKQkCI&7#Sq9l@m&&)+(H614 zoRQ@4xKkmG=&n^a1UA`=t3_3PQ!6zc zr0Dpn;>B{U`w6RT=rS#aUbcK;A* zXYB**o7Jw|yG`laxqjO>Cd@XIRsE+1htb=wzk*PcYdeaN+X&zqEskR2|yK-fg&Lh z0)`AoSV}5|5Le9Exb=?T%p&c1(P67EQuQ|%K21;Kz&R0>LIjl7=Ip({JHG+d0i>K- zvdjh+5U46)NyNRFi@c(z>ol)S3)EQ$Yw-4OCq> zGn3O4nJPhM=1?g@MbzK=G%c4K8zn8s@?}~6AuN8RDf{`30$R}uQR~gW zMhZ@s>XZL}USieLWf^^oZx229diu_9LNOVq>2x2*agGxBdC1%NR+iJ^M$L1$c4XOx z`n4$Ag;UNvUd2GQWVw#xS%i^PX&C3JOGU;-p-aW}St@{b8soE1!8G^!pi4!ldp&*U zQK6JS{q?hN8?pNd0pUk*^e3I%slNVuFDeu)@mfD)J-NUKzeCdhJ zby%x{$<_0j7!&|&!}K&A`DGz3>&-v0s?ag^@0$D^U8=G3McAnBPVGD@i1_!vz2!3i zA^ZRo|9zjwqX_pU>c@is0k(r@uJfM;kA8^g5FNota`ye>pd91gOD2Mt$cIL8Q000w;YhQ9%)x;3~u!F}ocu z*jf|08uJICL`W&0{6L_T!iQdk@Q_t3)}?zR6?~HlRNrK(I8s=hOw^+DS6Txog$h9J z>{CB>9uq?NUaBxG{(c07R3}DStCC#DY2lhO-eylp!e%VScb96gl1*fE>ki^@wvs5R zf|-4j3UrgI8N6ny=~=3XtZhw@u=PyURzOW!ln{2Qb{?3NGa|lORpTA03WroVA=QL@ z9mj<;p?&mr-u;7@67Kig{pc;kgE6-JYSsD$;O{(%N)t0GBmkOF;B9qhnv6H`Sq zmufzBj;G*L)@-ZOWVoNM=jD0)Mae)YSI;}bx#vUKG8Mc^6(cGd5g4G>S^|^PG`Um- z2?GE#DyxP^#u^=ze#1KXrG0PA(h;p`hZs!=}+8LOHwjyjfq)!I4*PV zkRrtAOl1Uwd5EyA058qIUj6IdK!6#rNzYWAv5~z{_M2($JSK?gKXm@$yP0b4nW{iY z%Q{7q(s|>2iGS88zh^!Gnty))VymkIUs$fL>e2<+6 zCuKrFpib;k0)qcisHhd3)c{>9Ad|(TrbC!}NQso}(1$viWw5BZFHGug zZc<&I=5gSVsu3UpnW5Remouy=f(KEn_9VGaQr!7f)IZRJg9HSCFMw|me0P}AX&Yh` zQbBQ$+F_igqcxw~LE5>i30^PP`} zU>LG>>xp9!;c_}0zJC2WWWuVtkEq!BRg^@ixu!K}&2lOMsRLjJKM8HszwIuy-_*4} z8*yAN=Xsh!7;ZV`)UJ~sFPF>ZJccYHMrJI-;)nD3a-RJ4BHT}809sAX)9hRPjTbi1 z;;>xf1M`yy$Gcd@_`u!>-1#L?A%H}A4a@)w`cbMc%g?~i(r5k(hE$;6NflO2bMFEU zr!pE^w&Ah`pJtCQ2Vtf}P58Eqy+^nUCRTI^`rd&JrzsOYMIG(twntivRs2R)Q(kJPT=ew{0RZWmN?q=a( zfAkw#G$YK2O=9+agwID2gG5`Vs#=o_r^_;SK1bzn?WdRFc<#|@JTiq&`!J=QUqmKr zJbZ`5mRtNd*PqW+RZ#{JtEwTvw|rrZMdWb5_xmP=CP@j^JUDpte(-QJLsHdRu|@oL zyom^l@!H(~<|@*^_vtKwM>+wdfN*3F zd_vPd<%78q5c7m$im+Xi&{nFM(=;NZL&e9cYA|k6(GBrvYvjiQSk|(N4Kcv@)!Nic zs`-Ml$vqHjN%gb%kxiB}-%2VzFO{{32jG-bDo>zlp@?WIFmLY7O)z=_5(v`(=nCZ0 zC?`}As}Sxyq=G9X6O^iS6|8GHMWsr!-qS3HaY{A03m?Sqzi;pP_4fAX`?qx|o_1CZ z=nl%V91~-E0&Cg~AWT7{sy3MTzyu03F+dRpIx-}HI|y^99gaX@AcsjQs%=5ZKx*4m zRNP_nM%u}3c(NBC2ajG=&TFpgK+~b_QiJt=PLxf!(Fr5DltnRs(4E_LFTl2#0iuBB zP#kzW5|!kVZn>p|dj|KLX0bGFN)qY=%B-m-H^IR+mF^=3BGDrr(Nnknic{(lKIjrv z>hyk{Rrg}sfP)Vb$BBqk!;R%UmSe`ZnN34{^wEPT&e(!_l zrIH*dQYzt*GcK>*>vMels@17?IVh)7E>SYA193m3I;NtJ_a4oQzmuDYrC_pGBdpF7 zk(Wr7?ZVF%$rt=cLA((1%3r)>+YO5}^^nSIjLY2gZD+otVsaB7533}i9IG>Er4?Ty zRka-LCDln!r0Avb?v(RCe054H`&Hy9xC$2g>UMwU`!px_(0BGdaalK__SP32{*5NQ z)M9o?B-vi8=$>%doO%Z@KK&EOpxn<$c_@chNAI=x%u|#5i0E$jeDMV|@Muc7*g&iD81{c|dJ*4XnWAMbIWc{_J7k}3QVzhAu{epI${Fe0;{-~o1aQJ!n z2-RP|7Jxy|x7>a{_l|#t>gk!6AE(cV{KIEb^qWxW4ApVq_wbpikH5!y3V*=Abj1GF zTpyL<@A>uh-|@K@0000000000U&uzdswyK+D zLIn)7Vp(g|LZ*NTY|GCU;47m6ObV5xZ&kHRqErFnELqp8>M@}L#>I}cRIO}M0%ox6 zIJc??kpgD0r8tkO8=(T`h-7V5x6n}sCa|rvzErKfJC2)dv0VxHy4do*R;}09%bRbV zb5+0qCrxqdx3x|ew$%ayEW2CD%dJkAP^o|cO|k8z-mKg4Z*QSi0b}f!s=D{|W~X)2 z2L!&Z+g-X59HF9<4$NRlvTs!z1qztKI(VsC zIZXx35KE3;tEw~m115+SN0+L)@No*5!HVNvRadsr0&~Q&*Q$l?A25aG#B0^fY)=B_ zM9RuuRrjNR5i2Mp_NU)MTpU0hKMjB9dPHaau?*;(VGIdZA?mGe|h|R24;bgzao?Ba zb?3wrFoPw>*Lt(wcFA#=1p*_YmVT{w>u&RQJTSycEMJ!8zJ6TJCvFl0zU)j;i`4t0 zsxIcrOJGbaN0#l&T6Jaq2Mmg2CF(7`2o*5QisVDISJgL(2d{x4mL*Hl_vgdBG%A28 zTAokHJLVO6V1~rGRc%gWcVY#MvYNK4dt_O?F(SYyD{IvvrL#>5n4q`l*->}1=~Mv2 z?Dz;(5~owDfMKmikE%x+%|Bp@*t%5Jc73@V7!hEQdyDr+omNH!7-UDub*mF20t~Y3 zJnGH5ZEyb>5nxd3)>2j1-a4HMV1l&nwd(E`_R|7WSkLcNjvTQ~2^e;sQEc7rt#t+j z802oPRg2U&kaG|6<-fpM{Q-uvf-&%eMhM|rKP*B zFsj?Jul4Rmi2_DB&CwC6b-TZCi6$`4lI8ufcPlg~fN@S*+$=ijz!bLRD6QL_Ryr_2 zmu06nhldG(SxYL#a-1~ge*gdg000000002+f9$^nO{KngKrN8~0000 1 { + start, end, err := req.pgf.NodeOffsets(exprs[0]) + if err != nil { + return err + } + desc := string(req.pgf.Src[start:end]) + if len(desc) >= 40 || strings.Contains(desc, "\n") { + desc = astutil.NodeDescription(exprs[0]) + } + constant := info.Types[exprs[0]].Value != nil + if (req.kind == settings.RefactorExtractConstantAll) == constant { + var title string + if constant { + title = fmt.Sprintf("Extract %d occurrences of const expression: %s", len(exprs), desc) + } else { + title = fmt.Sprintf("Extract %d occurrences of %s", len(exprs), desc) + } + req.addApplyFixAction(title, fixExtractVariableAll, req.loc) + } + } + return nil +} + // refactorExtractToNewFile produces "Extract declarations to new file" code actions. // See [server.commandHandler.ExtractToNewFile] for command implementation. func refactorExtractToNewFile(ctx context.Context, req *codeActionsRequest) error { diff --git a/gopls/internal/golang/extract.go b/gopls/internal/golang/extract.go index 72d718c2faf..4e57bfcfd6c 100644 --- a/gopls/internal/golang/extract.go +++ b/gopls/internal/golang/extract.go @@ -20,6 +20,7 @@ import ( "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/ast/astutil" + goplsastutil "golang.org/x/tools/gopls/internal/util/astutil" "golang.org/x/tools/gopls/internal/util/bug" "golang.org/x/tools/gopls/internal/util/safetoken" "golang.org/x/tools/internal/analysisinternal" @@ -27,24 +28,54 @@ import ( ) // extractVariable implements the refactor.extract.{variable,constant} CodeAction command. -func extractVariable(fset *token.FileSet, start, end token.Pos, src []byte, file *ast.File, pkg *types.Package, info *types.Info) (*token.FileSet, *analysis.SuggestedFix, error) { +func extractVariable(fset *token.FileSet, start, end token.Pos, src []byte, file *ast.File, _ *types.Package, info *types.Info) (*token.FileSet, *analysis.SuggestedFix, error) { + return extractExprs(fset, start, end, src, file, info, false) +} + +// extractVariableAll implements the refactor.extract.{variable,constant}-all CodeAction command. +func extractVariableAll(fset *token.FileSet, start, end token.Pos, src []byte, file *ast.File, _ *types.Package, info *types.Info) (*token.FileSet, *analysis.SuggestedFix, error) { + return extractExprs(fset, start, end, src, file, info, true) +} + +// extractExprs replaces occurrence(s) of a specified expression within the same function +// with newVar. If 'all' is true, it replaces all occurrences of the same expression; +// otherwise, it only replaces the selected expression. +// +// The new variable/constant is declared as close as possible to the first found expression +// within the deepest common scope accessible to all candidate occurrences. +func extractExprs(fset *token.FileSet, start, end token.Pos, src []byte, file *ast.File, info *types.Info, all bool) (*token.FileSet, *analysis.SuggestedFix, error) { tokFile := fset.File(file.FileStart) - expr, path, err := canExtractVariable(info, file, start, end) + exprs, err := canExtractVariable(info, file, start, end, all) if err != nil { - return nil, nil, fmt.Errorf("cannot extract %s: %v", safetoken.StartPosition(fset, start), err) + return nil, nil, fmt.Errorf("cannot extract: %v", err) + } + + // innermost scope enclosing ith expression + exprScopes := make([]*types.Scope, len(exprs)) + for i, e := range exprs { + exprScopes[i] = info.Scopes[file].Innermost(e.Pos()) } - constant := info.Types[expr].Value != nil + + hasCollision := func(name string) bool { + for _, scope := range exprScopes { + if s, _ := scope.LookupParent(name, token.NoPos); s != nil { + return true + } + } + return false + } + constant := info.Types[exprs[0]].Value != nil // Generate name(s) for new declaration. - baseName := cond(constant, "k", "x") + baseName := cond(constant, "newConst", "newVar") var lhsNames []string - switch expr := expr.(type) { + switch expr := exprs[0].(type) { case *ast.CallExpr: tup, ok := info.TypeOf(expr).(*types.Tuple) if !ok { // conversion or single-valued call: // treat it the same as our standard extract variable case. - name, _ := freshName(info, file, expr.Pos(), baseName, 0) + name, _ := generateName(0, baseName, hasCollision) lhsNames = append(lhsNames, name) } else { @@ -53,17 +84,55 @@ func extractVariable(fset *token.FileSet, start, end token.Pos, src []byte, file for range tup.Len() { // Generate a unique variable for each result. var name string - name, idx = freshName(info, file, expr.Pos(), baseName, idx) + name, idx = generateName(idx, baseName, hasCollision) lhsNames = append(lhsNames, name) } } default: // TODO: stricter rules for selectorExpr. - name, _ := freshName(info, file, expr.Pos(), baseName, 0) + name, _ := generateName(0, baseName, hasCollision) lhsNames = append(lhsNames, name) } + // Where all the extractable positions can see variable being declared. + var commonScope *types.Scope + counter := make(map[*types.Scope]int) +Outer: + for _, scope := range exprScopes { + for s := scope; s != nil; s = s.Parent() { + counter[s]++ + if counter[s] == len(exprScopes) { + // A scope whose count is len(scopes) is common to all ancestor paths. + // Stop at the first (innermost) one. + commonScope = s + break Outer + } + } + } + + var visiblePath []ast.Node + if commonScope != exprScopes[0] { + // This means the first expr within function body is not the largest scope, + // we need to find the scope immediately follow the common + // scope where we will insert the statement before. + child := exprScopes[0] + for p := child; p != nil; p = p.Parent() { + if p == commonScope { + break + } + child = p + } + visiblePath, _ = astutil.PathEnclosingInterval(file, child.Pos(), child.End()) + } else { + // Insert newVar inside commonScope before the first occurrence of the expression. + visiblePath, _ = astutil.PathEnclosingInterval(file, exprs[0].Pos(), exprs[0].End()) + } + variables, err := collectFreeVars(info, file, exprs[0].Pos(), exprs[0].End(), exprs[0]) + if err != nil { + return nil, nil, err + } + // TODO: There is a bug here: for a variable declared in a labeled // switch/for statement it returns the for/switch statement itself // which produces the below code which is a compiler error. e.g. @@ -74,26 +143,16 @@ func extractVariable(fset *token.FileSet, start, end token.Pos, src []byte, file // x := r() // switch r1 := x { ... break label ... } // compiler error // - // TODO(golang/go#70563): Another bug: extracting the - // expression to the recommended place may cause it to migrate - // across one or more declarations that it references. - // - // Before: - // if x := 1; cond { - // } else if y := «x + 2»; cond { - // } - // - // After: - // x1 := x + 2 // error: undefined x - // if x := 1; cond { - // } else if y := x1; cond { - // } var ( insertPos token.Pos indentation string stmtOK bool // ok to use ":=" instead of var/const decl? ) - if before := analysisinternal.StmtToInsertVarBefore(path); before != nil { + if funcDecl, ok := visiblePath[len(visiblePath)-2].(*ast.FuncDecl); ok && goplsastutil.NodeContains(funcDecl.Body, start) { + before, err := stmtToInsertVarBefore(visiblePath, variables) + if err != nil { + return nil, nil, fmt.Errorf("cannot find location to insert extraction: %v", err) + } // Within function: compute appropriate statement indentation. indent, err := calculateIndentation(src, tokFile, before) if err != nil { @@ -116,7 +175,7 @@ func extractVariable(fset *token.FileSet, start, end token.Pos, src []byte, file } else { // Outside any statement: insert before the current // declaration, without indentation. - currentDecl := path[len(path)-2] + currentDecl := visiblePath[len(visiblePath)-2] insertPos = currentDecl.Pos() indentation = "\n" } @@ -152,7 +211,7 @@ func extractVariable(fset *token.FileSet, start, end token.Pos, src []byte, file Specs: []ast.Spec{ &ast.ValueSpec{ Names: names, - Values: []ast.Expr{expr}, + Values: []ast.Expr{exprs[0]}, }, }, } @@ -166,7 +225,7 @@ func extractVariable(fset *token.FileSet, start, end token.Pos, src []byte, file newNode = &ast.AssignStmt{ Tok: token.DEFINE, Lhs: lhs, - Rhs: []ast.Expr{expr}, + Rhs: []ast.Expr{exprs[0]}, } } @@ -177,50 +236,264 @@ func extractVariable(fset *token.FileSet, start, end token.Pos, src []byte, file } // TODO(adonovan): not sound for `...` string literals containing newlines. assignment := strings.ReplaceAll(buf.String(), "\n", indentation) + indentation - + textEdits := []analysis.TextEdit{{ + Pos: insertPos, + End: insertPos, + NewText: []byte(assignment), + }} + for _, e := range exprs { + textEdits = append(textEdits, analysis.TextEdit{ + Pos: e.Pos(), + End: e.End(), + NewText: []byte(strings.Join(lhsNames, ", ")), + }) + } return fset, &analysis.SuggestedFix{ - TextEdits: []analysis.TextEdit{ - { - Pos: insertPos, - End: insertPos, - NewText: []byte(assignment), - }, - { - Pos: start, - End: end, - NewText: []byte(strings.Join(lhsNames, ", ")), - }, - }, + TextEdits: textEdits, }, nil } +// stmtToInsertVarBefore returns the ast.Stmt before which we can safely insert a new variable, +// and ensures that the new declaration is inserted at a point where all free variables are declared before. +// Some examples: +// +// Basic Example: +// +// z := 1 +// y := z + x +// +// If x is undeclared, then this function would return `y := z + x`, so that we +// can insert `x := ` on the line before `y := z + x`. +// +// valid IfStmt example: +// +// if z == 1 { +// } else if z == y {} +// +// If y is undeclared, then this function would return `if z == 1 {`, because we cannot +// insert a statement between an if and an else if statement. As a result, we need to find +// the top of the if chain to insert `y := ` before. +// +// invalid IfStmt example: +// +// if x := 1; true { +// } else if y := x + 1; true { //apply refactor.extract.variable to x +// } +// +// `x` is a free variable defined in the IfStmt, we should not insert +// the extracted expression outside the IfStmt scope, instead, return an error. +func stmtToInsertVarBefore(path []ast.Node, variables []*variable) (ast.Stmt, error) { + enclosingIndex := -1 // index in path of enclosing stmt + for i, p := range path { + if _, ok := p.(ast.Stmt); ok { + enclosingIndex = i + break + } + } + if enclosingIndex == -1 { + return nil, fmt.Errorf("no enclosing statement") + } + enclosingStmt := path[enclosingIndex].(ast.Stmt) + + // hasFreeVar reports if any free variables is defined inside stmt (which may be nil). + // If true, indicates that the insertion point will sit before the variable declaration. + hasFreeVar := func(stmt ast.Stmt) bool { + if stmt == nil { + return false + } + for _, v := range variables { + if goplsastutil.NodeContains(stmt, v.obj.Pos()) { + return true + } + } + return false + } + + // baseIfStmt walks up the if/else-if chain until we get to + // the top of the current if chain. + baseIfStmt := func(index int) (ast.Stmt, error) { + stmt := path[index] + for _, node := range path[index+1:] { + ifStmt, ok := node.(*ast.IfStmt) + if !ok || ifStmt.Else != stmt { + break + } + if hasFreeVar(ifStmt.Init) { + return nil, fmt.Errorf("Else's init statement has free variable declaration") + } + stmt = ifStmt + } + return stmt.(ast.Stmt), nil + } + + switch enclosingStmt := enclosingStmt.(type) { + case *ast.IfStmt: + if hasFreeVar(enclosingStmt.Init) { + return nil, fmt.Errorf("IfStmt's init statement has free variable declaration") + } + // The enclosingStmt is inside of the if declaration, + // We need to check if we are in an else-if stmt and + // get the base if statement. + return baseIfStmt(enclosingIndex) + case *ast.CaseClause: + // Get the enclosing switch stmt if the enclosingStmt is + // inside of the case statement. + for _, node := range path[enclosingIndex+1:] { + switch stmt := node.(type) { + case *ast.SwitchStmt: + if hasFreeVar(stmt.Init) { + return nil, fmt.Errorf("SwitchStmt's init statement has free variable declaration") + } + return stmt, nil + case *ast.TypeSwitchStmt: + if hasFreeVar(stmt.Init) { + return nil, fmt.Errorf("TypeSwitchStmt's init statement has free variable declaration") + } + return stmt, nil + } + } + } + // Check if the enclosing statement is inside another node. + switch parent := path[enclosingIndex+1].(type) { + case *ast.IfStmt: + if hasFreeVar(parent.Init) { + return nil, fmt.Errorf("IfStmt's init statement has free variable declaration") + } + return baseIfStmt(enclosingIndex + 1) + case *ast.ForStmt: + if parent.Init == enclosingStmt || parent.Post == enclosingStmt { + return parent, nil + } + case *ast.SwitchStmt: + if hasFreeVar(parent.Init) { + return nil, fmt.Errorf("SwitchStmt's init statement has free variable declaration") + } + return parent, nil + case *ast.TypeSwitchStmt: + if hasFreeVar(parent.Init) { + return nil, fmt.Errorf("TypeSwitchStmt's init statement has free variable declaration") + } + return parent, nil + } + return enclosingStmt.(ast.Stmt), nil +} + // canExtractVariable reports whether the code in the given range can be -// extracted to a variable (or constant). -func canExtractVariable(info *types.Info, file *ast.File, start, end token.Pos) (ast.Expr, []ast.Node, error) { +// extracted to a variable (or constant). It returns the selected expression or, if 'all', +// all structurally equivalent expressions within the same function body, in lexical order. +func canExtractVariable(info *types.Info, file *ast.File, start, end token.Pos, all bool) ([]ast.Expr, error) { if start == end { - return nil, nil, fmt.Errorf("empty selection") + return nil, fmt.Errorf("empty selection") } path, exact := astutil.PathEnclosingInterval(file, start, end) if !exact { - return nil, nil, fmt.Errorf("selection is not an expression") + return nil, fmt.Errorf("selection is not an expression") } if len(path) == 0 { - return nil, nil, bug.Errorf("no path enclosing interval") + return nil, bug.Errorf("no path enclosing interval") } for _, n := range path { if _, ok := n.(*ast.ImportSpec); ok { - return nil, nil, fmt.Errorf("cannot extract variable or constant in an import block") + return nil, fmt.Errorf("cannot extract variable or constant in an import block") } } expr, ok := path[0].(ast.Expr) if !ok { - return nil, nil, fmt.Errorf("selection is not an expression") // e.g. statement + return nil, fmt.Errorf("selection is not an expression") // e.g. statement } if tv, ok := info.Types[expr]; !ok || !tv.IsValue() || tv.Type == nil || tv.HasOk() { // e.g. type, builtin, x.(type), 2-valued m[k], or ill-typed - return nil, nil, fmt.Errorf("selection is not a single-valued expression") + return nil, fmt.Errorf("selection is not a single-valued expression") + } + + var exprs []ast.Expr + if !all { + exprs = append(exprs, expr) + } else if funcDecl, ok := path[len(path)-2].(*ast.FuncDecl); ok { + // Find all expressions in the same function body that + // are equal to the selected expression. + ast.Inspect(funcDecl.Body, func(n ast.Node) bool { + if e, ok := n.(ast.Expr); ok { + if goplsastutil.Equal(e, expr, func(x, y *ast.Ident) bool { + xobj, yobj := info.ObjectOf(x), info.ObjectOf(y) + // The two identifiers must resolve to the same object, + // or to a declaration within the candidate expression. + // (This allows two copies of "func (x int) { print(x) }" + // to match.) + if xobj != nil && goplsastutil.NodeContains(e, xobj.Pos()) && + yobj != nil && goplsastutil.NodeContains(expr, yobj.Pos()) { + return x.Name == y.Name + } + // Use info.Uses to avoid including declaration, for example, + // when extractnig x: + // + // x := 1 // should not include x + // y := x // include x + // z := x // include xxuse := info.Uses[x] + xuse := info.Uses[x] + return xuse != nil && xuse == info.Uses[y] + }) { + exprs = append(exprs, e) + } + } + return true + }) + } else { + return nil, fmt.Errorf("node %T is not inside a function", expr) } - return expr, path, nil + + // Disallow any expr that sits in lhs of an AssignStmt or ValueSpec for now. + // + // TODO(golang/go#70784): In such cases, exprs are operated in "variable" mode (L-value mode in C). + // In contrast, exprs in the RHS operate in "value" mode (R-value mode in C). + // L-value mode refers to exprs that represent storage locations, + // while R-value mode refers to exprs that represent values. + // There are a number of expressions that may have L-value mode, given by: + // + // lvalue = ident -- Ident such that info.Uses[id] is a *Var + // | '(' lvalue ') ' -- ParenExpr + // | lvalue '[' expr ']' -- IndexExpr + // | lvalue '.' ident -- SelectorExpr. + // + // For example: + // + // type foo struct { + // bar int + // } + // f := foo{bar: 1} + // x := f.bar + 1 // f.bar operates in "value" mode. + // f.bar = 2 // f.bar operates in "variable" mode. + // + // When extracting exprs in variable mode, we must be cautious. Any such extraction + // may require capturing the address of the expression and replacing its uses with dereferenced access. + // The type checker records this information in info.Types[id].{IsValue,Addressable}(). + // The correct result should be: + // + // newVar := &f.bar + // x := *newVar + 1 + // *newVar = 2 + for _, e := range exprs { + path, _ := astutil.PathEnclosingInterval(file, e.Pos(), e.End()) + for _, n := range path { + if assignment, ok := n.(*ast.AssignStmt); ok { + for _, lhs := range assignment.Lhs { + if lhs == e { + return nil, fmt.Errorf("node %T is in LHS of an AssignStmt", expr) + } + } + break + } + if value, ok := n.(*ast.ValueSpec); ok { + for _, name := range value.Names { + if name == e { + return nil, fmt.Errorf("node %T is in LHS of a ValueSpec", expr) + } + } + break + } + } + } + return exprs, nil } // Calculate indentation for insertion. @@ -331,14 +604,6 @@ func extractFunctionMethod(fset *token.FileSet, start, end token.Pos, src []byte safetoken.StartPosition(fset, start), err) } tok, path, start, end, outer, node := p.tok, p.path, p.start, p.end, p.outer, p.node - fileScope := info.Scopes[file] - if fileScope == nil { - return nil, nil, fmt.Errorf("%s: file scope is empty", errorPrefix) - } - pkgScope := fileScope.Parent() - if pkgScope == nil { - return nil, nil, fmt.Errorf("%s: package scope is empty", errorPrefix) - } // A return statement is non-nested if its parent node is equal to the parent node // of the first node in the selection. These cases must be handled separately because @@ -373,7 +638,7 @@ func extractFunctionMethod(fset *token.FileSet, start, end token.Pos, src []byte // we must determine the signature of the extracted function. We will then replace // the block with an assignment statement that calls the extracted function with // the appropriate parameters and return values. - variables, err := collectFreeVars(info, file, fileScope, pkgScope, start, end, path[0]) + variables, err := collectFreeVars(info, file, start, end, path[0]) if err != nil { return nil, nil, err } @@ -922,7 +1187,15 @@ type variable struct { // variables will be used as arguments in the extracted function. It also returns a // list of identifiers that may need to be returned by the extracted function. // Some of the code in this function has been adapted from tools/cmd/guru/freevars.go. -func collectFreeVars(info *types.Info, file *ast.File, fileScope, pkgScope *types.Scope, start, end token.Pos, node ast.Node) ([]*variable, error) { +func collectFreeVars(info *types.Info, file *ast.File, start, end token.Pos, node ast.Node) ([]*variable, error) { + fileScope := info.Scopes[file] + if fileScope == nil { + return nil, bug.Errorf("file scope is empty") + } + pkgScope := fileScope.Parent() + if pkgScope == nil { + return nil, bug.Errorf("package scope is empty") + } // id returns non-nil if n denotes an object that is referenced by the span // and defined either within the span or in the lexical environment. The bool // return value acts as an indicator for where it was defined. diff --git a/gopls/internal/golang/fix.go b/gopls/internal/golang/fix.go index f88343f029c..7e83c1d6700 100644 --- a/gopls/internal/golang/fix.go +++ b/gopls/internal/golang/fix.go @@ -59,6 +59,7 @@ func singleFile(fixer1 singleFileFixer) fixer { // Names of ApplyFix.Fix created directly by the CodeAction handler. const ( fixExtractVariable = "extract_variable" // (or constant) + fixExtractVariableAll = "extract_variable_all" fixExtractFunction = "extract_function" fixExtractMethod = "extract_method" fixInlineCall = "inline_call" @@ -106,6 +107,7 @@ func ApplyFix(ctx context.Context, fix string, snapshot *cache.Snapshot, fh file fixExtractFunction: singleFile(extractFunction), fixExtractMethod: singleFile(extractMethod), fixExtractVariable: singleFile(extractVariable), + fixExtractVariableAll: singleFile(extractVariableAll), fixInlineCall: inlineCall, fixInvertIfCondition: singleFile(invertIfCondition), fixSplitLines: singleFile(splitLines), diff --git a/gopls/internal/golang/undeclared.go b/gopls/internal/golang/undeclared.go index 3d9954639b4..ef32e949588 100644 --- a/gopls/internal/golang/undeclared.go +++ b/gopls/internal/golang/undeclared.go @@ -17,7 +17,6 @@ import ( "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/ast/astutil" "golang.org/x/tools/gopls/internal/util/typesutil" - "golang.org/x/tools/internal/analysisinternal" "golang.org/x/tools/internal/typesinternal" ) @@ -126,9 +125,9 @@ func CreateUndeclared(fset *token.FileSet, start, end token.Pos, content []byte, return nil, nil, fmt.Errorf("no identifier found") } p, _ := astutil.PathEnclosingInterval(file, firstRef.Pos(), firstRef.Pos()) - insertBeforeStmt := analysisinternal.StmtToInsertVarBefore(p) - if insertBeforeStmt == nil { - return nil, nil, fmt.Errorf("could not locate insertion point") + insertBeforeStmt, err := stmtToInsertVarBefore(p, nil) + if err != nil { + return nil, nil, fmt.Errorf("could not locate insertion point: %v", err) } indent, err := calculateIndentation(content, fset.File(file.FileStart), insertBeforeStmt) if err != nil { diff --git a/gopls/internal/settings/codeactionkind.go b/gopls/internal/settings/codeactionkind.go index 7bc4f4e4d66..0daf3cb5999 100644 --- a/gopls/internal/settings/codeactionkind.go +++ b/gopls/internal/settings/codeactionkind.go @@ -99,11 +99,13 @@ const ( RefactorInlineCall protocol.CodeActionKind = "refactor.inline.call" // refactor.extract - RefactorExtractConstant protocol.CodeActionKind = "refactor.extract.constant" - RefactorExtractFunction protocol.CodeActionKind = "refactor.extract.function" - RefactorExtractMethod protocol.CodeActionKind = "refactor.extract.method" - RefactorExtractVariable protocol.CodeActionKind = "refactor.extract.variable" - RefactorExtractToNewFile protocol.CodeActionKind = "refactor.extract.toNewFile" + RefactorExtractConstant protocol.CodeActionKind = "refactor.extract.constant" + RefactorExtractConstantAll protocol.CodeActionKind = "refactor.extract.constant-all" + RefactorExtractFunction protocol.CodeActionKind = "refactor.extract.function" + RefactorExtractMethod protocol.CodeActionKind = "refactor.extract.method" + RefactorExtractVariable protocol.CodeActionKind = "refactor.extract.variable" + RefactorExtractVariableAll protocol.CodeActionKind = "refactor.extract.variable-all" + RefactorExtractToNewFile protocol.CodeActionKind = "refactor.extract.toNewFile" // Note: add new kinds to: // - the SupportedCodeActions map in default.go diff --git a/gopls/internal/settings/default.go b/gopls/internal/settings/default.go index 0354101f045..3048f90bd3b 100644 --- a/gopls/internal/settings/default.go +++ b/gopls/internal/settings/default.go @@ -62,9 +62,11 @@ func DefaultOptions(overrides ...func(*Options)) *Options { RefactorRewriteSplitLines: true, RefactorInlineCall: true, RefactorExtractConstant: true, + RefactorExtractConstantAll: true, RefactorExtractFunction: true, RefactorExtractMethod: true, RefactorExtractVariable: true, + RefactorExtractVariableAll: true, RefactorExtractToNewFile: true, // Not GoTest: it must be explicit in CodeActionParams.Context.Only }, diff --git a/gopls/internal/test/marker/testdata/codeaction/extract_variable-67905.txt b/gopls/internal/test/marker/testdata/codeaction/extract_variable-67905.txt index fabbbee99d3..96c09cd0246 100644 --- a/gopls/internal/test/marker/testdata/codeaction/extract_variable-67905.txt +++ b/gopls/internal/test/marker/testdata/codeaction/extract_variable-67905.txt @@ -25,5 +25,5 @@ func main() { -- @type_switch_func_call/extract_switch.go -- @@ -10 +10,2 @@ - switch r := f().(type) { //@codeaction("f()", "refactor.extract.variable", edit=type_switch_func_call) -+ x := f() -+ switch r := x.(type) { //@codeaction("f()", "refactor.extract.variable", edit=type_switch_func_call) ++ newVar := f() ++ switch r := newVar.(type) { //@codeaction("f()", "refactor.extract.variable", edit=type_switch_func_call) diff --git a/gopls/internal/test/marker/testdata/codeaction/extract_variable-70563.txt b/gopls/internal/test/marker/testdata/codeaction/extract_variable-70563.txt new file mode 100644 index 00000000000..1317815ea32 --- /dev/null +++ b/gopls/internal/test/marker/testdata/codeaction/extract_variable-70563.txt @@ -0,0 +1,50 @@ +This test verifies the fix for golang/go#70563: refactor.extract.variable +inserts new statement before the scope of its free symbols. + +-- flags -- +-ignore_extra_diags + +-- inside_else.go -- +package extract + +func _() { + if x := 1; true { + + } else if y := x + 1; true { //@codeaction("x + 1", "refactor.extract.variable", err=re"Else's init statement has free variable declaration") + + } +} +-- inside_case.go -- +package extract + +func _() { + switch x := 1; x { + case x + 1: //@codeaction("x + 1", "refactor.extract.variable-all", err=re"SwitchStmt's init statement has free variable declaration") + y := x + 1 //@codeaction("x + 1", "refactor.extract.variable-all", err=re"SwitchStmt's init statement has free variable declaration") + _ = y + case 3: + y := x + 1 //@codeaction("x + 1", "refactor.extract.variable-all", err=re"SwitchStmt's init statement has free variable declaration") + _ = y + } +} +-- parent_if.go -- +package extract + +func _() { + if x := 1; x > 0 { + y = x + 1 //@codeaction("x + 1", "refactor.extract.variable-all", err=re"IfStmt's init statement has free variable declaration") + } else { + y = x + 1 //@codeaction("x + 1", "refactor.extract.variable-all", err=re"IfStmt's init statement has free variable declaration") + } +} +-- parent_switch.go -- +package extract + +func _() { + switch x := 1; x { + case 1: + y = x + 1 //@codeaction("x + 1", "refactor.extract.variable-all", err=re"SwitchStmt's init statement has free variable declaration") + case 3: + y = x + 1 //@codeaction("x + 1", "refactor.extract.variable-all", err=re"SwitchStmt's init statement has free variable declaration") + } +} diff --git a/gopls/internal/test/marker/testdata/codeaction/extract_variable-if.txt b/gopls/internal/test/marker/testdata/codeaction/extract_variable-if.txt index ab9d76b8602..fdc00d3bf8f 100644 --- a/gopls/internal/test/marker/testdata/codeaction/extract_variable-if.txt +++ b/gopls/internal/test/marker/testdata/codeaction/extract_variable-if.txt @@ -29,13 +29,13 @@ func variable(y int) { -- @constant/a.go -- @@ -4 +4 @@ -+ const k = 1 + 2 ++ const newConst = 1 + 2 @@ -5 +6 @@ - } else if 1 + 2 > 0 { //@ codeaction("1 + 2", "refactor.extract.constant", edit=constant) -+ } else if k > 0 { //@ codeaction("1 + 2", "refactor.extract.constant", edit=constant) ++ } else if newConst > 0 { //@ codeaction("1 + 2", "refactor.extract.constant", edit=constant) -- @variable/a.go -- @@ -10 +10 @@ -+ x := y + y ++ newVar := y + y @@ -11 +12 @@ - } else if y + y > 0 { //@ codeaction("y + y", "refactor.extract.variable", edit=variable) -+ } else if x > 0 { //@ codeaction("y + y", "refactor.extract.variable", edit=variable) ++ } else if newVar > 0 { //@ codeaction("y + y", "refactor.extract.variable", edit=variable) diff --git a/gopls/internal/test/marker/testdata/codeaction/extract_variable-inexact.txt b/gopls/internal/test/marker/testdata/codeaction/extract_variable-inexact.txt index 1781b3ce6af..5ddff1182f6 100644 --- a/gopls/internal/test/marker/testdata/codeaction/extract_variable-inexact.txt +++ b/gopls/internal/test/marker/testdata/codeaction/extract_variable-inexact.txt @@ -17,20 +17,20 @@ func _(ptr *int) { -- @spaces/a.go -- @@ -4 +4,2 @@ - var _ = 1 + 2 + 3 //@codeaction("1 + 2 ", "refactor.extract.constant", edit=spaces) -+ const k = 1 + 2 -+ var _ = k+ 3 //@codeaction("1 + 2 ", "refactor.extract.constant", edit=spaces) ++ const newConst = 1 + 2 ++ var _ = newConst + 3 //@codeaction("1 + 2 ", "refactor.extract.constant", edit=spaces) -- @funclit/a.go -- @@ -5 +5,2 @@ - var _ = func() {} //@codeaction("func() {}", "refactor.extract.variable", edit=funclit) -+ x := func() {} -+ var _ = x //@codeaction("func() {}", "refactor.extract.variable", edit=funclit) ++ newVar := func() {} ++ var _ = newVar //@codeaction("func() {}", "refactor.extract.variable", edit=funclit) -- @ptr/a.go -- @@ -6 +6,2 @@ - var _ = *ptr //@codeaction("*ptr", "refactor.extract.variable", edit=ptr) -+ x := *ptr -+ var _ = x //@codeaction("*ptr", "refactor.extract.variable", edit=ptr) ++ newVar := *ptr ++ var _ = newVar //@codeaction("*ptr", "refactor.extract.variable", edit=ptr) -- @paren/a.go -- @@ -7 +7,2 @@ - var _ = (ptr) //@codeaction("(ptr)", "refactor.extract.variable", edit=paren) -+ x := (ptr) -+ var _ = x //@codeaction("(ptr)", "refactor.extract.variable", edit=paren) ++ newVar := (ptr) ++ var _ = newVar //@codeaction("(ptr)", "refactor.extract.variable", edit=paren) diff --git a/gopls/internal/test/marker/testdata/codeaction/extract_variable-toplevel.txt b/gopls/internal/test/marker/testdata/codeaction/extract_variable-toplevel.txt index b9166c6299d..d41fee42c9f 100644 --- a/gopls/internal/test/marker/testdata/codeaction/extract_variable-toplevel.txt +++ b/gopls/internal/test/marker/testdata/codeaction/extract_variable-toplevel.txt @@ -15,37 +15,37 @@ func f([2]int) {} //@codeaction("2", "refactor.extract.constant", edit=paramtype -- @lenhello/a.go -- @@ -3 +3,2 @@ -const length = len("hello") + 2 //@codeaction(`len("hello")`, "refactor.extract.constant", edit=lenhello) -+const k = len("hello") -+const length = k + 2 //@codeaction(`len("hello")`, "refactor.extract.constant", edit=lenhello) ++const newConst = len("hello") ++const length = newConst + 2 //@codeaction(`len("hello")`, "refactor.extract.constant", edit=lenhello) -- @sliceliteral/a.go -- @@ -5 +5,2 @@ -var slice = append([]int{}, 1, 2, 3) //@codeaction("[]int{}", "refactor.extract.variable", edit=sliceliteral) -+var x = []int{} -+var slice = append(x, 1, 2, 3) //@codeaction("[]int{}", "refactor.extract.variable", edit=sliceliteral) ++var newVar = []int{} ++var slice = append(newVar, 1, 2, 3) //@codeaction("[]int{}", "refactor.extract.variable", edit=sliceliteral) -- @arraylen/a.go -- @@ -7 +7,2 @@ -type SHA256 [32]byte //@codeaction("32", "refactor.extract.constant", edit=arraylen) -+const k = 32 -+type SHA256 [k]byte //@codeaction("32", "refactor.extract.constant", edit=arraylen) ++const newConst = 32 ++type SHA256 [newConst]byte //@codeaction("32", "refactor.extract.constant", edit=arraylen) -- @paramtypearraylen/a.go -- @@ -9 +9,2 @@ -func f([2]int) {} //@codeaction("2", "refactor.extract.constant", edit=paramtypearraylen) -+const k = 2 -+func f([k]int) {} //@codeaction("2", "refactor.extract.constant", edit=paramtypearraylen) ++const newConst = 2 ++func f([newConst]int) {} //@codeaction("2", "refactor.extract.constant", edit=paramtypearraylen) -- b/b.go -- package b // Check that package- and file-level name collisions are avoided. -import x3 "errors" +import newVar3 "errors" -var x, x1, x2 any // these names are taken already -var _ = x3.New("") +var newVar, newVar1, newVar2 any // these names are taken already +var _ = newVar3.New("") var a, b int var c = a + b //@codeaction("a + b", "refactor.extract.variable", edit=fresh) -- @fresh/b/b.go -- @@ -10 +10,2 @@ -var c = a + b //@codeaction("a + b", "refactor.extract.variable", edit=fresh) -+var x4 = a + b -+var c = x4 //@codeaction("a + b", "refactor.extract.variable", edit=fresh) ++var newVar4 = a + b ++var c = newVar4 //@codeaction("a + b", "refactor.extract.variable", edit=fresh) diff --git a/gopls/internal/test/marker/testdata/codeaction/extract_variable.txt b/gopls/internal/test/marker/testdata/codeaction/extract_variable.txt index c14fb732978..9dd0f766e05 100644 --- a/gopls/internal/test/marker/testdata/codeaction/extract_variable.txt +++ b/gopls/internal/test/marker/testdata/codeaction/extract_variable.txt @@ -15,13 +15,13 @@ func _() { -- @basic_lit1/basic_lit.go -- @@ -4 +4,2 @@ - var _ = 1 + 2 //@codeaction("1", "refactor.extract.constant", edit=basic_lit1) -+ const k = 1 -+ var _ = k + 2 //@codeaction("1", "refactor.extract.constant", edit=basic_lit1) ++ const newConst = 1 ++ var _ = newConst + 2 //@codeaction("1", "refactor.extract.constant", edit=basic_lit1) -- @basic_lit2/basic_lit.go -- @@ -5 +5,2 @@ - var _ = 3 + 4 //@codeaction("3 + 4", "refactor.extract.constant", edit=basic_lit2) -+ const k = 3 + 4 -+ var _ = k //@codeaction("3 + 4", "refactor.extract.constant", edit=basic_lit2) ++ const newConst = 3 + 4 ++ var _ = newConst //@codeaction("3 + 4", "refactor.extract.constant", edit=basic_lit2) -- func_call.go -- package extract @@ -36,13 +36,13 @@ func _() { -- @func_call1/func_call.go -- @@ -6 +6,2 @@ - x0 := append([]int{}, 1) //@codeaction("append([]int{}, 1)", "refactor.extract.variable", edit=func_call1) -+ x := append([]int{}, 1) -+ x0 := x //@codeaction("append([]int{}, 1)", "refactor.extract.variable", edit=func_call1) ++ newVar := append([]int{}, 1) ++ x0 := newVar //@codeaction("append([]int{}, 1)", "refactor.extract.variable", edit=func_call1) -- @func_call2/func_call.go -- @@ -8 +8,2 @@ - b, err := strconv.Atoi(str) //@codeaction("strconv.Atoi(str)", "refactor.extract.variable", edit=func_call2) -+ x, x1 := strconv.Atoi(str) -+ b, err := x, x1 //@codeaction("strconv.Atoi(str)", "refactor.extract.variable", edit=func_call2) ++ newVar, newVar1 := strconv.Atoi(str) ++ b, err := newVar, newVar1 //@codeaction("strconv.Atoi(str)", "refactor.extract.variable", edit=func_call2) -- scope.go -- package extract @@ -61,10 +61,10 @@ func _() { -- @scope1/scope.go -- @@ -8 +8,2 @@ - y := ast.CompositeLit{} //@codeaction("ast.CompositeLit{}", "refactor.extract.variable", edit=scope1) -+ x := ast.CompositeLit{} -+ y := x //@codeaction("ast.CompositeLit{}", "refactor.extract.variable", edit=scope1) ++ newVar := ast.CompositeLit{} ++ y := newVar //@codeaction("ast.CompositeLit{}", "refactor.extract.variable", edit=scope1) -- @scope2/scope.go -- @@ -11 +11,2 @@ - x := !false //@codeaction("!false", "refactor.extract.constant", edit=scope2) -+ const k = !false -+ x := k //@codeaction("!false", "refactor.extract.constant", edit=scope2) ++ const newConst = !false ++ x := newConst //@codeaction("!false", "refactor.extract.constant", edit=scope2) diff --git a/gopls/internal/test/marker/testdata/codeaction/extract_variable_all.txt b/gopls/internal/test/marker/testdata/codeaction/extract_variable_all.txt new file mode 100644 index 00000000000..050f29bfec7 --- /dev/null +++ b/gopls/internal/test/marker/testdata/codeaction/extract_variable_all.txt @@ -0,0 +1,238 @@ +This test checks the behavior of the 'replace all occurrences of expression' code action, with resolve support. +See extract_expressions.txt for the same test without resolve support. + +-- flags -- +-ignore_extra_diags + +-- basic_lit.go -- +package extract_all + +func _() { + var _ = 1 + 2 + 3 //@codeaction("1 + 2", "refactor.extract.constant-all", edit=basic_lit) + var _ = 1 + 2 + 3 //@codeaction("1 + 2", "refactor.extract.constant-all", edit=basic_lit) +} +-- @basic_lit/basic_lit.go -- +@@ -4,2 +4,3 @@ +- var _ = 1 + 2 + 3 //@codeaction("1 + 2", "refactor.extract.constant-all", edit=basic_lit) +- var _ = 1 + 2 + 3 //@codeaction("1 + 2", "refactor.extract.constant-all", edit=basic_lit) ++ const newConst = 1 + 2 ++ var _ = newConst + 3 //@codeaction("1 + 2", "refactor.extract.constant-all", edit=basic_lit) ++ var _ = newConst + 3 //@codeaction("1 + 2", "refactor.extract.constant-all", edit=basic_lit) +-- nested_scope.go -- +package extract_all + +func _() { + newConst1 := 0 + if true { + x := 1 + 2 + 3 //@codeaction("1 + 2 + 3", "refactor.extract.constant-all", edit=nested_scope) + } + if true { + newConst := 0 + if false { + y := 1 + 2 + 3 //@codeaction("1 + 2 + 3", "refactor.extract.constant-all", edit=nested_scope) + } + } + z := 1 + 2 + 3 //@codeaction("1 + 2 + 3", "refactor.extract.constant-all", edit=nested_scope) +} +-- @nested_scope/nested_scope.go -- +@@ -5 +5 @@ ++ const newConst2 = 1 + 2 + 3 +@@ -6 +7 @@ +- x := 1 + 2 + 3 //@codeaction("1 + 2 + 3", "refactor.extract.constant-all", edit=nested_scope) ++ x := newConst2 //@codeaction("1 + 2 + 3", "refactor.extract.constant-all", edit=nested_scope) +@@ -11 +12 @@ +- y := 1 + 2 + 3 //@codeaction("1 + 2 + 3", "refactor.extract.constant-all", edit=nested_scope) ++ y := newConst2 //@codeaction("1 + 2 + 3", "refactor.extract.constant-all", edit=nested_scope) +@@ -14 +15 @@ +- z := 1 + 2 + 3 //@codeaction("1 + 2 + 3", "refactor.extract.constant-all", edit=nested_scope) ++ z := newConst2 //@codeaction("1 + 2 + 3", "refactor.extract.constant-all", edit=nested_scope) +-- function_call.go -- +package extract_all + +import "fmt" + +func _() { + result := fmt.Sprintf("%d", 42) //@codeaction(`fmt.Sprintf("%d", 42)`, "refactor.extract.variable-all", edit=replace_func_call) + if result != "" { + anotherResult := fmt.Sprintf("%d", 42) //@codeaction(`fmt.Sprintf("%d", 42)`, "refactor.extract.variable-all", edit=replace_func_call) + _ = anotherResult + } +} +-- @replace_func_call/function_call.go -- +@@ -6 +6,2 @@ +- result := fmt.Sprintf("%d", 42) //@codeaction(`fmt.Sprintf("%d", 42)`, "refactor.extract.variable-all", edit=replace_func_call) ++ newVar := fmt.Sprintf("%d", 42) ++ result := newVar //@codeaction(`fmt.Sprintf("%d", 42)`, "refactor.extract.variable-all", edit=replace_func_call) +@@ -8 +9 @@ +- anotherResult := fmt.Sprintf("%d", 42) //@codeaction(`fmt.Sprintf("%d", 42)`, "refactor.extract.variable-all", edit=replace_func_call) ++ anotherResult := newVar //@codeaction(`fmt.Sprintf("%d", 42)`, "refactor.extract.variable-all", edit=replace_func_call) +-- composite_literals.go -- +package extract_all + +func _() { + data := []int{1, 2, 3} //@codeaction("[]int{1, 2, 3}", "refactor.extract.variable-all", edit=composite) + processData(data) + moreData := []int{1, 2, 3} //@codeaction("[]int{1, 2, 3}", "refactor.extract.variable-all", edit=composite) + processData(moreData) +} + +func processData(d []int) {} +-- @composite/composite_literals.go -- +@@ -4 +4,2 @@ +- data := []int{1, 2, 3} //@codeaction("[]int{1, 2, 3}", "refactor.extract.variable-all", edit=composite) ++ newVar := []int{1, 2, 3} ++ data := newVar //@codeaction("[]int{1, 2, 3}", "refactor.extract.variable-all", edit=composite) +@@ -6 +7 @@ +- moreData := []int{1, 2, 3} //@codeaction("[]int{1, 2, 3}", "refactor.extract.variable-all", edit=composite) ++ moreData := newVar //@codeaction("[]int{1, 2, 3}", "refactor.extract.variable-all", edit=composite) +-- selector.go -- +package extract_all + +type MyStruct struct { + Value int +} + +func _() { + s := MyStruct{Value: 10} + v := s.Value //@codeaction("s.Value", "refactor.extract.variable-all", edit=sel) + if v > 0 { + w := s.Value //@codeaction("s.Value", "refactor.extract.variable-all", edit=sel) + _ = w + } +} +-- @sel/selector.go -- +@@ -9 +9,2 @@ +- v := s.Value //@codeaction("s.Value", "refactor.extract.variable-all", edit=sel) ++ newVar := s.Value ++ v := newVar //@codeaction("s.Value", "refactor.extract.variable-all", edit=sel) +@@ -11 +12 @@ +- w := s.Value //@codeaction("s.Value", "refactor.extract.variable-all", edit=sel) ++ w := newVar //@codeaction("s.Value", "refactor.extract.variable-all", edit=sel) +-- index.go -- +package extract_all + +func _() { + arr := []int{1, 2, 3} + val := arr[0] //@codeaction("arr[0]", "refactor.extract.variable-all", edit=index) + val2 := arr[0] //@codeaction("arr[0]", "refactor.extract.variable-all", edit=index) +} +-- @index/index.go -- +@@ -5,2 +5,3 @@ +- val := arr[0] //@codeaction("arr[0]", "refactor.extract.variable-all", edit=index) +- val2 := arr[0] //@codeaction("arr[0]", "refactor.extract.variable-all", edit=index) ++ newVar := arr[0] ++ val := newVar //@codeaction("arr[0]", "refactor.extract.variable-all", edit=index) ++ val2 := newVar //@codeaction("arr[0]", "refactor.extract.variable-all", edit=index) +-- slice_expr.go -- +package extract_all + +func _() { + data := []int{1, 2, 3, 4, 5} + part := data[1:3] //@codeaction("data[1:3]", "refactor.extract.variable-all", edit=slice) + anotherPart := data[1:3] //@codeaction("data[1:3]", "refactor.extract.variable-all", edit=slice) +} +-- @slice/slice_expr.go -- +@@ -5,2 +5,3 @@ +- part := data[1:3] //@codeaction("data[1:3]", "refactor.extract.variable-all", edit=slice) +- anotherPart := data[1:3] //@codeaction("data[1:3]", "refactor.extract.variable-all", edit=slice) ++ newVar := data[1:3] ++ part := newVar //@codeaction("data[1:3]", "refactor.extract.variable-all", edit=slice) ++ anotherPart := newVar //@codeaction("data[1:3]", "refactor.extract.variable-all", edit=slice) +-- nested_func.go -- +package extract_all + +func outer() { + inner := func() { + val := 100 + 200 //@codeaction("100 + 200", "refactor.extract.constant-all", edit=nested) + _ = val + } + inner() + val := 100 + 200 //@codeaction("100 + 200", "refactor.extract.constant-all", edit=nested) + _ = val +} +-- @nested/nested_func.go -- +@@ -4 +4 @@ ++ const newConst = 100 + 200 +@@ -5 +6 @@ +- val := 100 + 200 //@codeaction("100 + 200", "refactor.extract.constant-all", edit=nested) ++ val := newConst //@codeaction("100 + 200", "refactor.extract.constant-all", edit=nested) +@@ -9 +10 @@ +- val := 100 + 200 //@codeaction("100 + 200", "refactor.extract.constant-all", edit=nested) ++ val := newConst //@codeaction("100 + 200", "refactor.extract.constant-all", edit=nested) +-- switch.go -- +package extract_all + +func _() { + value := 2 + switch value { + case 1: + result := value * 10 //@codeaction("value * 10", "refactor.extract.variable-all", edit=switch) + _ = result + case 2: + result := value * 10 //@codeaction("value * 10", "refactor.extract.variable-all", edit=switch) + _ = result + default: + result := value * 10 //@codeaction("value * 10", "refactor.extract.variable-all", edit=switch) + _ = result + } +} +-- @switch/switch.go -- +@@ -5 +5 @@ ++ newVar := value * 10 +@@ -7 +8 @@ +- result := value * 10 //@codeaction("value * 10", "refactor.extract.variable-all", edit=switch) ++ result := newVar //@codeaction("value * 10", "refactor.extract.variable-all", edit=switch) +@@ -10 +11 @@ +- result := value * 10 //@codeaction("value * 10", "refactor.extract.variable-all", edit=switch) ++ result := newVar //@codeaction("value * 10", "refactor.extract.variable-all", edit=switch) +@@ -13 +14 @@ +- result := value * 10 //@codeaction("value * 10", "refactor.extract.variable-all", edit=switch) ++ result := newVar //@codeaction("value * 10", "refactor.extract.variable-all", edit=switch) +-- switch_single.go -- +package extract_all + +func _() { + value := 2 + switch value { + case 1: + result := value * 10 + _ = result + case 2: + result := value * 10 + _ = result + default: + result := value * 10 //@codeaction("value * 10", "refactor.extract.variable", edit=switch_single) + _ = result + } +} +-- @switch_single/switch_single.go -- +@@ -13 +13,2 @@ +- result := value * 10 //@codeaction("value * 10", "refactor.extract.variable", edit=switch_single) ++ newVar := value * 10 ++ result := newVar //@codeaction("value * 10", "refactor.extract.variable", edit=switch_single) +-- func_list.go -- +package extract_all + +func _() { + x := func(a int) int { //@codeaction("func", "refactor.extract.variable-all", end=closeBracket1, edit=func_list) + b := 1 + return b + a + } //@loc(closeBracket1, "}") + y := func(a int) int { //@codeaction("func", "refactor.extract.variable-all", end=closeBracket2, edit=func_list) + b := 1 + return b + a + }//@loc(closeBracket2, "}") +} +-- @func_list/func_list.go -- +@@ -4 +4 @@ +- x := func(a int) int { //@codeaction("func", "refactor.extract.variable-all", end=closeBracket1, edit=func_list) ++ newVar := func(a int) int { +@@ -7,5 +7,3 @@ +- } //@loc(closeBracket1, "}") +- y := func(a int) int { //@codeaction("func", "refactor.extract.variable-all", end=closeBracket2, edit=func_list) +- b := 1 +- return b + a +- }//@loc(closeBracket2, "}") ++ } ++ x := newVar //@loc(closeBracket1, "}") ++ y := newVar//@loc(closeBracket2, "}") diff --git a/gopls/internal/test/marker/testdata/codeaction/extract_variable_all_resolve.txt b/gopls/internal/test/marker/testdata/codeaction/extract_variable_all_resolve.txt new file mode 100644 index 00000000000..02c03929567 --- /dev/null +++ b/gopls/internal/test/marker/testdata/codeaction/extract_variable_all_resolve.txt @@ -0,0 +1,249 @@ +This test checks the behavior of the 'replace all occurrences of expression' code action, with resolve support. +See extract_expressions.txt for the same test without resolve support. + +-- capabilities.json -- +{ + "textDocument": { + "codeAction": { + "dataSupport": true, + "resolveSupport": { + "properties": ["edit"] + } + } + } +} +-- flags -- +-ignore_extra_diags + +-- basic_lit.go -- +package extract_all + +func _() { + var _ = 1 + 2 + 3 //@codeaction("1 + 2", "refactor.extract.constant-all", edit=basic_lit) + var _ = 1 + 2 + 3 //@codeaction("1 + 2", "refactor.extract.constant-all", edit=basic_lit) +} +-- @basic_lit/basic_lit.go -- +@@ -4,2 +4,3 @@ +- var _ = 1 + 2 + 3 //@codeaction("1 + 2", "refactor.extract.constant-all", edit=basic_lit) +- var _ = 1 + 2 + 3 //@codeaction("1 + 2", "refactor.extract.constant-all", edit=basic_lit) ++ const newConst = 1 + 2 ++ var _ = newConst + 3 //@codeaction("1 + 2", "refactor.extract.constant-all", edit=basic_lit) ++ var _ = newConst + 3 //@codeaction("1 + 2", "refactor.extract.constant-all", edit=basic_lit) +-- nested_scope.go -- +package extract_all + +func _() { + newConst1 := 0 + if true { + x := 1 + 2 + 3 //@codeaction("1 + 2 + 3", "refactor.extract.constant-all", edit=nested_scope) + } + if true { + newConst := 0 + if false { + y := 1 + 2 + 3 //@codeaction("1 + 2 + 3", "refactor.extract.constant-all", edit=nested_scope) + } + } + z := 1 + 2 + 3 //@codeaction("1 + 2 + 3", "refactor.extract.constant-all", edit=nested_scope) +} +-- @nested_scope/nested_scope.go -- +@@ -5 +5 @@ ++ const newConst2 = 1 + 2 + 3 +@@ -6 +7 @@ +- x := 1 + 2 + 3 //@codeaction("1 + 2 + 3", "refactor.extract.constant-all", edit=nested_scope) ++ x := newConst2 //@codeaction("1 + 2 + 3", "refactor.extract.constant-all", edit=nested_scope) +@@ -11 +12 @@ +- y := 1 + 2 + 3 //@codeaction("1 + 2 + 3", "refactor.extract.constant-all", edit=nested_scope) ++ y := newConst2 //@codeaction("1 + 2 + 3", "refactor.extract.constant-all", edit=nested_scope) +@@ -14 +15 @@ +- z := 1 + 2 + 3 //@codeaction("1 + 2 + 3", "refactor.extract.constant-all", edit=nested_scope) ++ z := newConst2 //@codeaction("1 + 2 + 3", "refactor.extract.constant-all", edit=nested_scope) +-- function_call.go -- +package extract_all + +import "fmt" + +func _() { + result := fmt.Sprintf("%d", 42) //@codeaction(`fmt.Sprintf("%d", 42)`, "refactor.extract.variable-all", edit=replace_func_call) + if result != "" { + anotherResult := fmt.Sprintf("%d", 42) //@codeaction(`fmt.Sprintf("%d", 42)`, "refactor.extract.variable-all", edit=replace_func_call) + _ = anotherResult + } +} +-- @replace_func_call/function_call.go -- +@@ -6 +6,2 @@ +- result := fmt.Sprintf("%d", 42) //@codeaction(`fmt.Sprintf("%d", 42)`, "refactor.extract.variable-all", edit=replace_func_call) ++ newVar := fmt.Sprintf("%d", 42) ++ result := newVar //@codeaction(`fmt.Sprintf("%d", 42)`, "refactor.extract.variable-all", edit=replace_func_call) +@@ -8 +9 @@ +- anotherResult := fmt.Sprintf("%d", 42) //@codeaction(`fmt.Sprintf("%d", 42)`, "refactor.extract.variable-all", edit=replace_func_call) ++ anotherResult := newVar //@codeaction(`fmt.Sprintf("%d", 42)`, "refactor.extract.variable-all", edit=replace_func_call) +-- composite_literals.go -- +package extract_all + +func _() { + data := []int{1, 2, 3} //@codeaction("[]int{1, 2, 3}", "refactor.extract.variable-all", edit=composite) + processData(data) + moreData := []int{1, 2, 3} //@codeaction("[]int{1, 2, 3}", "refactor.extract.variable-all", edit=composite) + processData(moreData) +} + +func processData(d []int) {} +-- @composite/composite_literals.go -- +@@ -4 +4,2 @@ +- data := []int{1, 2, 3} //@codeaction("[]int{1, 2, 3}", "refactor.extract.variable-all", edit=composite) ++ newVar := []int{1, 2, 3} ++ data := newVar //@codeaction("[]int{1, 2, 3}", "refactor.extract.variable-all", edit=composite) +@@ -6 +7 @@ +- moreData := []int{1, 2, 3} //@codeaction("[]int{1, 2, 3}", "refactor.extract.variable-all", edit=composite) ++ moreData := newVar //@codeaction("[]int{1, 2, 3}", "refactor.extract.variable-all", edit=composite) +-- selector.go -- +package extract_all + +type MyStruct struct { + Value int +} + +func _() { + s := MyStruct{Value: 10} + v := s.Value //@codeaction("s.Value", "refactor.extract.variable-all", edit=sel) + if v > 0 { + w := s.Value //@codeaction("s.Value", "refactor.extract.variable-all", edit=sel) + _ = w + } +} +-- @sel/selector.go -- +@@ -9 +9,2 @@ +- v := s.Value //@codeaction("s.Value", "refactor.extract.variable-all", edit=sel) ++ newVar := s.Value ++ v := newVar //@codeaction("s.Value", "refactor.extract.variable-all", edit=sel) +@@ -11 +12 @@ +- w := s.Value //@codeaction("s.Value", "refactor.extract.variable-all", edit=sel) ++ w := newVar //@codeaction("s.Value", "refactor.extract.variable-all", edit=sel) +-- index.go -- +package extract_all + +func _() { + arr := []int{1, 2, 3} + val := arr[0] //@codeaction("arr[0]", "refactor.extract.variable-all", edit=index) + val2 := arr[0] //@codeaction("arr[0]", "refactor.extract.variable-all", edit=index) +} +-- @index/index.go -- +@@ -5,2 +5,3 @@ +- val := arr[0] //@codeaction("arr[0]", "refactor.extract.variable-all", edit=index) +- val2 := arr[0] //@codeaction("arr[0]", "refactor.extract.variable-all", edit=index) ++ newVar := arr[0] ++ val := newVar //@codeaction("arr[0]", "refactor.extract.variable-all", edit=index) ++ val2 := newVar //@codeaction("arr[0]", "refactor.extract.variable-all", edit=index) +-- slice_expr.go -- +package extract_all + +func _() { + data := []int{1, 2, 3, 4, 5} + part := data[1:3] //@codeaction("data[1:3]", "refactor.extract.variable-all", edit=slice) + anotherPart := data[1:3] //@codeaction("data[1:3]", "refactor.extract.variable-all", edit=slice) +} +-- @slice/slice_expr.go -- +@@ -5,2 +5,3 @@ +- part := data[1:3] //@codeaction("data[1:3]", "refactor.extract.variable-all", edit=slice) +- anotherPart := data[1:3] //@codeaction("data[1:3]", "refactor.extract.variable-all", edit=slice) ++ newVar := data[1:3] ++ part := newVar //@codeaction("data[1:3]", "refactor.extract.variable-all", edit=slice) ++ anotherPart := newVar //@codeaction("data[1:3]", "refactor.extract.variable-all", edit=slice) +-- nested_func.go -- +package extract_all + +func outer() { + inner := func() { + val := 100 + 200 //@codeaction("100 + 200", "refactor.extract.constant-all", edit=nested) + _ = val + } + inner() + val := 100 + 200 //@codeaction("100 + 200", "refactor.extract.constant-all", edit=nested) + _ = val +} +-- @nested/nested_func.go -- +@@ -4 +4 @@ ++ const newConst = 100 + 200 +@@ -5 +6 @@ +- val := 100 + 200 //@codeaction("100 + 200", "refactor.extract.constant-all", edit=nested) ++ val := newConst //@codeaction("100 + 200", "refactor.extract.constant-all", edit=nested) +@@ -9 +10 @@ +- val := 100 + 200 //@codeaction("100 + 200", "refactor.extract.constant-all", edit=nested) ++ val := newConst //@codeaction("100 + 200", "refactor.extract.constant-all", edit=nested) +-- switch.go -- +package extract_all + +func _() { + value := 2 + switch value { + case 1: + result := value * 10 //@codeaction("value * 10", "refactor.extract.variable-all", edit=switch) + _ = result + case 2: + result := value * 10 //@codeaction("value * 10", "refactor.extract.variable-all", edit=switch) + _ = result + default: + result := value * 10 //@codeaction("value * 10", "refactor.extract.variable-all", edit=switch) + _ = result + } +} +-- @switch/switch.go -- +@@ -5 +5 @@ ++ newVar := value * 10 +@@ -7 +8 @@ +- result := value * 10 //@codeaction("value * 10", "refactor.extract.variable-all", edit=switch) ++ result := newVar //@codeaction("value * 10", "refactor.extract.variable-all", edit=switch) +@@ -10 +11 @@ +- result := value * 10 //@codeaction("value * 10", "refactor.extract.variable-all", edit=switch) ++ result := newVar //@codeaction("value * 10", "refactor.extract.variable-all", edit=switch) +@@ -13 +14 @@ +- result := value * 10 //@codeaction("value * 10", "refactor.extract.variable-all", edit=switch) ++ result := newVar //@codeaction("value * 10", "refactor.extract.variable-all", edit=switch) +-- switch_single.go -- +package extract_all + +func _() { + value := 2 + switch value { + case 1: + result := value * 10 + _ = result + case 2: + result := value * 10 + _ = result + default: + result := value * 10 //@codeaction("value * 10", "refactor.extract.variable", edit=switch_single) + _ = result + } +} +-- @switch_single/switch_single.go -- +@@ -13 +13,2 @@ +- result := value * 10 //@codeaction("value * 10", "refactor.extract.variable", edit=switch_single) ++ newVar := value * 10 ++ result := newVar //@codeaction("value * 10", "refactor.extract.variable", edit=switch_single) +-- func_list.go -- +package extract_all + +func _() { + x := func(a int) int { //@codeaction("func", "refactor.extract.variable-all", end=closeBracket1, edit=func_list) + b := 1 + return b + a + } //@loc(closeBracket1, "}") + y := func(a int) int { //@codeaction("func", "refactor.extract.variable-all", end=closeBracket2, edit=func_list) + b := 1 + return b + a + }//@loc(closeBracket2, "}") +} +-- @func_list/func_list.go -- +@@ -4 +4 @@ +- x := func(a int) int { //@codeaction("func", "refactor.extract.variable-all", end=closeBracket1, edit=func_list) ++ newVar := func(a int) int { +@@ -7,5 +7,3 @@ +- } //@loc(closeBracket1, "}") +- y := func(a int) int { //@codeaction("func", "refactor.extract.variable-all", end=closeBracket2, edit=func_list) +- b := 1 +- return b + a +- }//@loc(closeBracket2, "}") ++ } ++ x := newVar //@loc(closeBracket1, "}") ++ y := newVar//@loc(closeBracket2, "}") diff --git a/gopls/internal/test/marker/testdata/codeaction/extract_variable_resolve.txt b/gopls/internal/test/marker/testdata/codeaction/extract_variable_resolve.txt index 2bf1803a7d8..203b6d1eadc 100644 --- a/gopls/internal/test/marker/testdata/codeaction/extract_variable_resolve.txt +++ b/gopls/internal/test/marker/testdata/codeaction/extract_variable_resolve.txt @@ -26,13 +26,13 @@ func _() { -- @basic_lit1/basic_lit.go -- @@ -4 +4,2 @@ - var _ = 1 + 2 //@codeaction("1", "refactor.extract.constant", edit=basic_lit1) -+ const k = 1 -+ var _ = k + 2 //@codeaction("1", "refactor.extract.constant", edit=basic_lit1) ++ const newConst = 1 ++ var _ = newConst + 2 //@codeaction("1", "refactor.extract.constant", edit=basic_lit1) -- @basic_lit2/basic_lit.go -- @@ -5 +5,2 @@ - var _ = 3 + 4 //@codeaction("3 + 4", "refactor.extract.constant", edit=basic_lit2) -+ const k = 3 + 4 -+ var _ = k //@codeaction("3 + 4", "refactor.extract.constant", edit=basic_lit2) ++ const newConst = 3 + 4 ++ var _ = newConst //@codeaction("3 + 4", "refactor.extract.constant", edit=basic_lit2) -- func_call.go -- package extract @@ -47,13 +47,13 @@ func _() { -- @func_call1/func_call.go -- @@ -6 +6,2 @@ - x0 := append([]int{}, 1) //@codeaction("append([]int{}, 1)", "refactor.extract.variable", edit=func_call1) -+ x := append([]int{}, 1) -+ x0 := x //@codeaction("append([]int{}, 1)", "refactor.extract.variable", edit=func_call1) ++ newVar := append([]int{}, 1) ++ x0 := newVar //@codeaction("append([]int{}, 1)", "refactor.extract.variable", edit=func_call1) -- @func_call2/func_call.go -- @@ -8 +8,2 @@ - b, err := strconv.Atoi(str) //@codeaction("strconv.Atoi(str)", "refactor.extract.variable", edit=func_call2) -+ x, x1 := strconv.Atoi(str) -+ b, err := x, x1 //@codeaction("strconv.Atoi(str)", "refactor.extract.variable", edit=func_call2) ++ newVar, newVar1 := strconv.Atoi(str) ++ b, err := newVar, newVar1 //@codeaction("strconv.Atoi(str)", "refactor.extract.variable", edit=func_call2) -- scope.go -- package extract @@ -72,10 +72,10 @@ func _() { -- @scope1/scope.go -- @@ -8 +8,2 @@ - y := ast.CompositeLit{} //@codeaction("ast.CompositeLit{}", "refactor.extract.variable", edit=scope1) -+ x := ast.CompositeLit{} -+ y := x //@codeaction("ast.CompositeLit{}", "refactor.extract.variable", edit=scope1) ++ newVar := ast.CompositeLit{} ++ y := newVar //@codeaction("ast.CompositeLit{}", "refactor.extract.variable", edit=scope1) -- @scope2/scope.go -- @@ -11 +11,2 @@ - x := !false //@codeaction("!false", "refactor.extract.constant", edit=scope2) -+ const k = !false -+ x := k //@codeaction("!false", "refactor.extract.constant", edit=scope2) ++ const newConst = !false ++ x := newConst //@codeaction("!false", "refactor.extract.constant", edit=scope2) diff --git a/gopls/internal/util/astutil/util.go b/gopls/internal/util/astutil/util.go index ac7515d1daf..5a9f993449a 100644 --- a/gopls/internal/util/astutil/util.go +++ b/gopls/internal/util/astutil/util.go @@ -7,6 +7,7 @@ package astutil import ( "go/ast" "go/token" + "reflect" "golang.org/x/tools/internal/typeparams" ) @@ -69,3 +70,86 @@ L: // unpack receiver type func NodeContains(n ast.Node, pos token.Pos) bool { return n.Pos() <= pos && pos <= n.End() } + +// Equal recursively compares two nodes for structural equality, +// ignoring fields of type [token.Pos] and [ast.Object]. +// The operands x and y may be nil. A nil slice is not equal to an empty slice. +// The provided identical function reports whether two identifiers should be considered identical. +func Equal(x, y ast.Node, identical func(x, y *ast.Ident) bool) bool { + if x == nil || y == nil { + return x == y + } + return equal(reflect.ValueOf(x), reflect.ValueOf(y), identical) +} + +func equal(x, y reflect.Value, identical func(x, y *ast.Ident) bool) bool { + // Ensure types are the same + if x.Type() != y.Type() { + return false + } + switch x.Kind() { + case reflect.Pointer: + if x.IsNil() || y.IsNil() { + return x.IsNil() == y.IsNil() + } + switch t := x.Interface().(type) { + // Skip fields of types potentially involved in cycles. + case *ast.Object, *ast.Scope, *ast.CommentGroup: + return true + case *ast.Ident: + return identical(t, y.Interface().(*ast.Ident)) + default: + return equal(x.Elem(), y.Elem(), identical) + } + + case reflect.Interface: + if x.IsNil() || y.IsNil() { + return x.IsNil() == y.IsNil() + } + return equal(x.Elem(), y.Elem(), identical) + + case reflect.Struct: + for i := range x.NumField() { + xf := x.Field(i) + yf := y.Field(i) + // Skip position fields. + if xpos, ok := xf.Interface().(token.Pos); ok { + ypos := yf.Interface().(token.Pos) + // Numeric value of a Pos is not significant but its "zeroness" is, + // because it is often significant, e.g. CallExpr.Variadic(Ellipsis), ChanType.Arrow. + if xpos.IsValid() != ypos.IsValid() { + return false + } + } else if !equal(xf, yf, identical) { + return false + } + } + return true + + case reflect.Slice: + if x.IsNil() || y.IsNil() { + return x.IsNil() == y.IsNil() + } + if x.Len() != y.Len() { + return false + } + for i := range x.Len() { + if !equal(x.Index(i), y.Index(i), identical) { + return false + } + } + return true + + case reflect.String: + return x.String() == y.String() + + case reflect.Bool: + return x.Bool() == y.Bool() + + case reflect.Int: + return x.Int() == y.Int() + + default: + panic(x) + } +} diff --git a/internal/analysisinternal/analysis.go b/internal/analysisinternal/analysis.go index fe67b0fa27a..58615232ff9 100644 --- a/internal/analysisinternal/analysis.go +++ b/internal/analysisinternal/analysis.go @@ -65,90 +65,6 @@ func TypeErrorEndPos(fset *token.FileSet, src []byte, start token.Pos) token.Pos return end } -// StmtToInsertVarBefore returns the ast.Stmt before which we can -// safely insert a new var declaration, or nil if the path denotes a -// node outside any statement. -// -// Basic Example: -// -// z := 1 -// y := z + x -// -// If x is undeclared, then this function would return `y := z + x`, so that we -// can insert `x := ` on the line before `y := z + x`. -// -// If stmt example: -// -// if z == 1 { -// } else if z == y {} -// -// If y is undeclared, then this function would return `if z == 1 {`, because we cannot -// insert a statement between an if and an else if statement. As a result, we need to find -// the top of the if chain to insert `y := ` before. -func StmtToInsertVarBefore(path []ast.Node) ast.Stmt { - enclosingIndex := -1 - for i, p := range path { - if _, ok := p.(ast.Stmt); ok { - enclosingIndex = i - break - } - } - if enclosingIndex == -1 { - return nil // no enclosing statement: outside function - } - enclosingStmt := path[enclosingIndex] - switch enclosingStmt.(type) { - case *ast.IfStmt: - // The enclosingStmt is inside of the if declaration, - // We need to check if we are in an else-if stmt and - // get the base if statement. - // TODO(adonovan): for non-constants, it may be preferable - // to add the decl as the Init field of the innermost - // enclosing ast.IfStmt. - return baseIfStmt(path, enclosingIndex) - case *ast.CaseClause: - // Get the enclosing switch stmt if the enclosingStmt is - // inside of the case statement. - for i := enclosingIndex + 1; i < len(path); i++ { - if node, ok := path[i].(*ast.SwitchStmt); ok { - return node - } else if node, ok := path[i].(*ast.TypeSwitchStmt); ok { - return node - } - } - } - if len(path) <= enclosingIndex+1 { - return enclosingStmt.(ast.Stmt) - } - // Check if the enclosing statement is inside another node. - switch expr := path[enclosingIndex+1].(type) { - case *ast.IfStmt: - // Get the base if statement. - return baseIfStmt(path, enclosingIndex+1) - case *ast.ForStmt: - if expr.Init == enclosingStmt || expr.Post == enclosingStmt { - return expr - } - case *ast.SwitchStmt, *ast.TypeSwitchStmt: - return expr.(ast.Stmt) - } - return enclosingStmt.(ast.Stmt) -} - -// baseIfStmt walks up the if/else-if chain until we get to -// the top of the current if chain. -func baseIfStmt(path []ast.Node, index int) ast.Stmt { - stmt := path[index] - for i := index + 1; i < len(path); i++ { - if node, ok := path[i].(*ast.IfStmt); ok && node.Else == stmt { - stmt = node - continue - } - break - } - return stmt.(ast.Stmt) -} - // WalkASTWithParent walks the AST rooted at n. The semantics are // similar to ast.Inspect except it does not call f(nil). func WalkASTWithParent(n ast.Node, f func(n ast.Node, parent ast.Node) bool) {