From 826ebac80ed61b520f70f4476cbed4fbce3a29d5 Mon Sep 17 00:00:00 2001 From: Daniel Date: Sun, 1 Jul 2018 18:50:16 +0200 Subject: [PATCH] Added check for bracket notation & duplicate goog.require/provide statements (v. 1.1.0). Closes #5 --- closure-inspections-plugin.jar | Bin 37091 -> 38263 bytes resources/META-INF/plugin.xml | 10 +- .../ClosureDependenciesExtractor.java | 13 +- .../ClosureInspectionsProvider.java | 5 +- .../ConvertToES6ClassInspection.java | 111 ------------------ ...ssingOrObsoleteGoogRequiresInspection.java | 15 ++- .../UseOfBracketNotationInspection.java | 62 ++++++++++ .../GoogRequireOrProvideRecognizer.java | 25 +++- .../fixes/BracketNotationFix.java | 56 +++++++++ ....java => ObsoleteRequireOrProvideFix.java} | 8 +- 10 files changed, 174 insertions(+), 131 deletions(-) delete mode 100644 src/de/veihelmann/closureplugin/ConvertToES6ClassInspection.java create mode 100644 src/de/veihelmann/closureplugin/UseOfBracketNotationInspection.java create mode 100644 src/de/veihelmann/closureplugin/fixes/BracketNotationFix.java rename src/de/veihelmann/closureplugin/fixes/{ObsoleteRequireFix.java => ObsoleteRequireOrProvideFix.java} (78%) diff --git a/closure-inspections-plugin.jar b/closure-inspections-plugin.jar index 3e9c6af883b94bda0ba16800a9c1f2246fb68125..d88b7b1705c5df350ec86477305b733f938e0c35 100644 GIT binary patch delta 17644 zcmagGV{|56w*{IGI@S}rW81cECmq}7)3I&awr$%^IyO4S?f3o0xZgSF$G!DuSFKTF z)StC$t~J-3`ydbWsT>quK^hDk6$A34ptks zmw@!m3W&;x`Uyh~Hu38s{0Rs2teyhQy=Tt^Ley>Uhaf5T0$zF%$HtnBS=cj%H~THd zv&{ZS-}A-wjXGvQHbO&0dT6*Y)8*;k>nSTc+xPwTiuYGR>zqHEalE;BjzzuX!+`=d zf>ACS!gpC_V*`#bQ(VUH;!%BdB+&O?3<{1vTO z;NI`_zCWL)u=}?3n2c)7&L(%&`mTjALC0erCHX~8$`kHK=fe^Mv#9Y>e_S3@%7mW;t2Rw8dt>y;+$H3KL zlgM?<0kq)rb4+m@bw=9)9A38Sz4oBaC{RyK+iJI0jnrJ+n}B#``hLUSqIvLU4ca7; zpZ*vbr+P426rg2Nh3`u%HdnlbX`b_DUqc)=LYFGSr<@0kq2lAik(`?eRwmNoz$smI z^K$9{70tUZWt2PW=R2hg7RxV9;T6ecKfAH_)?BgC%?QqF^1%XzeKz4FVbOr;^sW)r zu{Om_4BJLgZ^5rurI|_ve5S;lcZ@^ULPzfjH72fOuk6qYCj(tPCg+ZcyG6r8as(qk z{c81qD}FQ9_LCROl9Wgn=hO)~pc3&1Wno`!SRpdYEF?+82Yp|C&0MWW!FOk+4H33p z5;o-yleO^IO92uryGTAN+`5_)~%LJc? z2G>D)K}%wcv0?Z8urb(~o(T*~<3cf_8T3~EZsdq%L`_(yZr&mu%_&F$5PgDtEqgVk zd;q|St%J?A2ds+uq!+Szezl0{$?eJHA95>5LqcWmJ!vU}fq+Otfq?vXOa9$fjL_u4$?A$Zxx zhlsN{?~1jyQv3u<-bipWmQntKG_g&seU8 z9joxv5C%u^bSj8{*Z;joibh}IF51^_5I5eIoeAhlPDO3zr{X>3t_JOzX%5=3Ny{eZ z0TMAsCt#r;JIXelCHG2nzKM?Cv0>^%Z#L@hvM=vTAQNjW${_p z)%ZOWLsOAB*^G*g{@fT9OjLqJ1mNuob*Tk}c#fxb>^zA4>MK^kA9fUi`A%K80_@T- zYBACz61^39v_zEBetn`Sjc$sjDm`_b_m@{#-_P6pooX*W$r!;Q3r%jKRZvWwhLFbk z*-DaorL|mf#j~XB9OgCiR*l6~tM)rAJ6^h*RPFH$FFE-H=ADOl%`Zw?no>j7AdyQN zgZshNN9>umt&&t3RaaaJFp{lt4g`jmi+@FUlREsN*M|)gV^*fz^Wf&<=0+niOfuSe zy?)bm>2CP>lOD(Y1BlhS-J;5znVA6y2^iRE&b&p~&WL`St2)rzEGdBOg29I6#&-zH z9Z=AZ(&?OfL3^krE==S16#ZLzRT6k_!~D7o#hYAKKvB?(0Z8)#W;R-rQEc?T$vg$qSEh z_KuXNke5+tcq)sYxoHch2ReI))u3Kb6}A~Qr%adz(3vw(>j(|idCioFB$F=&{7EQ8 zcIHt$6}1_O0SIelmJ}3YnBZ|T6X(xI%P9|vzulG9^QRZbIvr|6|8cH$(x=8OXA!*A z$e%Lq+BtbfPjU7R0psdEe&$ms!#X2@8HJ0MMXH5Khh6iZokcq$N@>GjbQ!)wqA_AM773Tx}(%Oj*v#o2*dF?8;Q< z9&>mmt!%AmH5$G`uR4IXsEqX+t0i^u1%ORjkC10$YVs~au|ISiG`3ug7On)_Kctq) z=#(rULS{|hS~zvT3dF#;if@>_hx#tHSUhwcqk)AgM-f^Ba(XjPU=$9c`;|8*EcRr- zGaKqZWwH%-f2SK!8SKkc?e>*3FMIxn5+Q_v1yy9C#rR$qw#HmC#jZx`<-Q88d5*Xt zV7rP6yX{7(uS!I9j=MR|>ISqc$DFDT_906|*+e%NF+a?T5IB|5x=eqAh%5^aGG!Ge z4i6F)680KFL-p{{W`n+D<5ViCH&m{)J-u48S(j{Y zB6Kp};Cqw}d{a+8rKW7A7_laENE3|$e}pMY;i^pkp(fqPYOiCUD920l7TI z{1HU*yqKc*@-8LBFXLm@jZHm?&@hT@VpvMnh`mYRL0@%JKqIA5?S@ z$dE8^g@pW)A?cK;l$t?e((L|$d+Vg32}HyxkO@;B$@7=kmmw;?!!E%;_|!qttZMch z1Y`>t@qYr8lki>wC#)JU*;Y3~00LRCOsP@SAP%#@Fmk<=kg_Uo72Jnm<5Hp6+U#u7 z_F!h7JXFkwxv#WGer>C$hw0~10I(hHW>Z3i4a$$FE+Hs7r!qWutHzi}-++(4IO0yi(+ zW802Hku#5en!ssys{E_Rmzy+aJq`-Yb}L$R#jC?1#-8 zPIx;>v?cW9=WUk?-}8m*Jo}-f_QDdW?B4{j&?lr?GT9KZ*U{!VY%86qs7eF7t1!)iC<<%zbF9gO`Y1)6ye>{oaahja!;t}C+;1+PRrRUOcuifVHaT;D z+$h=-4 zhT&-zlm^#jcaCXSY80Pd8lLd4#dK@!BMe^Y6%-FGD%Umq1{lQjw)>JdF8R@QihK)u zf6fKSAQcS(^B2gb3CBaD=?MIN3MZhLoK3$AMegCwH9VBO0y3r@WMWl+cLo{jb1}a{ z5O;)G=Qn3el38`^7?4KS-sHughh%Uf+rqU#KDCQ-${`$T{_Kw)=9sJ#2oqVpUlRqD zLRR1d)hfr^J2I>6^z{mDvJ2%4zW)Fe`+oZ;Ij1ohJ}7{oARs>A|4B|55Rkuh)IUv2 z2!Y%`txUrz!8O#sH{%r0;Q!t%(=FU3p!T5l5WM7UQ^7Z!I!Fx>LMs!7FCK*ZuuR>U{V9V_@sae9br>k$yhXkBkq6X= zZkm1&xvLIa3H7d+=p^65LrbmK&l9gpb8ao;LN9?apH-%hwzbCrF;yC}094|C8q3-_ zwG-^USzD-kSX7v^FkNi6WZV!)s$_)Nb*C5}(nOZ$PzIv6t<15eoVjBZb!@0oSRV?{ zEaj_|a0w(V!Zc-bmLnrA)58i4I2Y4c9WAyVSh&KzZ8_YF@%G$qX*14)nXERO{zZ}Xt}NJlIxiM2JoOrAs*9%Bo?S6Qdlgs-)tRobkoD~t6|o?*Y%K;m zrb$lmRmfo%20~UAT1J*N(=9{f?_@2P893`+C~2uNE2pP*au`@iQrn!-TQw(WAXhTG z_N~Ve<$PY~RNWf7N}gxTeX(0yaleALUs6_#FlFh8QB%YNXOXu;bMcoLJn4@v zC(%+w`tzd9&-EMviOQYLM3p3Bp+sD^!w6XmI5k-%Ezun0yGLt1)^^ddRy3eZbPVtk zZ|vvut0Y^1DxQ)j8&U$(TbDJVZmF*D6(SR~rv8DylZm?9oQc1WWzwP^FG;%_Z+WNO z%I-78Gwbpe{7GwQFFLeyY$vAim*Ix9|4NJ$GLoWL8$`o1KVe}0A> z_BO62)i*}u(FT&KfLCP&s}U}RiQDAps>EFsVOa+Reh4j4fm5CIwve#cv_epDgbKsp zqX;u=p*BYBZ9F4fzb{v(`CspQ0RS1DY%tw1D`=g5>}c;G{3d#G>+iEvBopgB~ z%xh;rQvHKF2+v?Nri>TSRB`V8-(=d2-gIK9odM^D&sF|A(Dqz6UTQ_M#|i%A4w)aX-RvCDA5XW% zwQrRW)6_vvos|G@Ma4n?F^l~TVYn^%?j0YXcZbKDD0A{`^XFqXnn}Zm0^SHUl4@mo ziSveoSKtq5uYB2askk5agPND1mtMcTq#Lu5*xlz-ar?uH?{j`IT5GwAu|jQ!ci)*e zilosORr@ol!lO^ECy`IfOxK>f(@`~=oknwk7B_uQlIv8ZZ81@X#1xO?d??spSUr;l zw$=+Cm#cL}4hj!4>COROn<6IDtfLLgY4+TpNrsm(9j~+85>m~FuA~N+DkZ$~>+>+t zq{NQXKS&#^wg~L2iYAn`rOtye~u{1XdSaC5lg-HUw`nD>joU~d0MUQz`Ui2`xD zzQdN7?;Fgg!5xA2P|a>9SkC^tgVOe|82()WYkVbZWRrvYo2@{ghZcUsj)-U_@P+L6 zQ|nwv0WR^2@QDbcbt znTK*r+=$~$0*eZOI_-hF?im;Kvqcdj;;lc)2}*CMS!0s`!NC*$up8$Vf&y@r>sagY zO%)IHw#?)e7j#bd{HhH^e7DOhZhpsZZVGgZ-3z0<@wS0= z|0P<^*6D=M5v?}3-*o7LcJDq5EC?Mgxlcx$YxTFy%-wR3$%Q26UCj}umvi_^I2lpq z*&6}jy%?}aJOBt4W)l&Crm;2q=Ej+eU_EjGrwW_yjQ#5o?luW!;+Up@y?TZe^vtPX zJc@{4_@_p;WwFQ!$VrNnMjB$Fv(k-z^kF>7&lpW_FIkm6;g73trRJIfx>)+8+^sh) zgZuaH<_L)T;xQu+%dn+Sdu!($67ijmz?bk3Zl0s?j|nW42`d^y7R_FXNpKjG?aG}2 ziQHPmZ_&Cuf54f4W5#g+r#Csrl)K#1p~`uPJF9;I?OMCjk6$>bNd9p1klr<9!~sS6 zf8O)gzG0`QB6tm+6~ugXg^oTGJu(eE1wGB=`Ek1ZM2ML#xE(m+UgiBnHr}CqKiy)5 z-qB_0>G;_#bA_3$o3tognBB*=eWR7GCBBQez+zyH=KbYIbI^7K^u_96yjr8*!>#=w zIq>R6%5e=xaaS4McSFh&UVy(Ag5pL+tRMHs6Ndq%@bFSl>Gc0akszgTK5(7IPf;tA zutp%9a1rsN!Ap$gJM!NO;(zflMhSVS1PKZe7zs9!3=L$m6i{GfNqY&3s=Q!`3VR80 zs?0zkM*|}(6K6R)X9H&oJ6kaecRC|$11F~@bxkMK6|~PQ>#ay^Bw{2u&?;Si7#dOsbd-_02Ks5CW%lwr;~ohlDu=@{)fd_q z=(1QRFDyxBuwtdK^7ffaubI27KhdAJ*FC^@_+E<7#9?TiI0ixkrC}9p2N~&9N#Y<) zEPbSh2n%NexytHscR}yp8}{(`7Bsu+F@Th~^vUQ$i@DZsPIr>ruCNyCy)c)7W z9MAQUH4^Ts{Z?>g5y2+zDVU2o-R9~n19zStIfp}+4ZsCm-)7IXVHY+15<%5maT9`FMyThwz~1Da9d5SxyG&ZfeO<;H5)R^}a%UGbw(Y9>2 z;7^3(*L$ni_Ug2D)n%A$BMlS76U)Zt5ef1z`HgLnx=~%XW!JOnA~>t9ZrMJs3PK#$ zByG>7+4AVF;fQQk-rNIPVMeRe&Oefq{ z<8><`y7`BZ=&`ad%@+s>EEI^+et@N^-SV5?vX{8kNzRrrP+T;44l%GFQ{MkYp7EyB z_;lyKYEDu7R+q*$nUEk02=ZIFffM{^K3s=0bi9JI7r|DoQ5+S!cFqPx7mEABfW1|O zSLl_)X#KNjBW^hL&=|uBX-nWLjAfwwp&%C=0GWXlnA6u`UU6cJ zI=U4{h{YIIVz+F!bQ;{Ma^&x_;ke?zZsm!{>WZc=$w@YQn$``Fs7!N+hpIXTgW ztd^;%5$)8RChHxk6xjg5V~MU#)#B2BuPY-|FVnG5ki&&Yyd~OrEark!nGd4GKnt)K zyq{v5nAiX5I=X-4|1%1G`~g2l0at?aO(dRmhM|eeNEu4Ife|;*-;utS-6$!4 zhPZ7RI)3v6`)pnJ=i-cy+qYZ^wK57OSehM>BFOt&S{BA3~R@fLm7iOPPJok z^xVGYNQ3Yzi#G_HB_`0#_+j*K*{+FoY@C_G_~RfyGJ%PO%BWv$Zfx&Z+j+4Hy=!%{ zXqWuC?3wm~IrtdpDt9cCkmAA&(?2N|r#=J~cM}oJ7W3++I60$VeEZE;RCcW}3~+X< zYw4RXtlPIX2U;AsGiSfKh5+Qfi2nr3E@H|0^(^fdMh(g6yr3TCOFtayis%hW=}WM~ z#as)|cH=g9W%wmLn8FlhL&Ec-g|AdIP|J8kLAga(V_02vi!T~45(MIPK*x1b6Tl?|9&}M984upPTH$qAdscw z=M}WLGKtN=S^V7R*_C=DpVqP0hKFSa0LPH$Sh!4wn@DT|I55^c`~*oc%$!XSHVqx@ z$-(^O8&kjGNRTnx3p9YhBmvPrbx(*2JWX~e>^OAyG*TgmaJ)D_p&)Ff#h#|uOK_a5 zVIIubXjSre6o?XUoSQv*&TZdLALr``(NT?vZb98zx0tUr z#Ay&95}SN2KJ@988Oi-4?`YcfrtoIU*$yf3vM}M+2VBvWqG;@({_WN*>Pssz`^i@f zR)h;*vWAc8Q8|;&P_{meKE3!|FIpo|^STpj6FQL$Ui zjlefNx-R&5Q;F%GIG*#zU_u%J?CsmL$Ar6GWOL}qiLm$0xYfopYngj!hvAF1(rsOi zZ(JvE|Kz9tXP+*^Nm~9f@?j<;qZaxqF;$g4?cP&N>5nfAeXuXcwpF7U86x$7qWB zvQE-baN|m$a)ZuFC5PVZjmegUip`3*rQLXMram-}c(9|O?^>-7=XHv=-GE*aaN+SN zuot@LkmHEN{#9TcGyoQ!z0t~Xd8-yIqf#o_ZV7WV$61%YQE0XZ=zT&7IPThOL z6>MR>i{-e}zIu zkt4SE#f>;$COrhuQC{xQ)iIW z@6(mir`9;TJ#@OjsYqHo{KcqG7cCLSW77cLx`YLwks8 zv%Ed9<-#ThY(CUh-cxm)@rv8U`>2jv6o#{nm=R2Tm|*zpGDcJ#Y?w$bVkr2>WsSIC zX;Hita51+@^ZKKz=CfBOp!KtDCGY^A?4H`vl2zv9WX?fnL=vxy>(x2(jH9YRcto*S z+LkqjU;J_bCxDXiFX z-Oms`<~A^E{kW`>%r++Dg+@y1UIHf_8~s_rE#^SIal{iD%sLwZ_$MV;LH--Gvm?8_ z3{uC4Z%Fbx@lSaQ~H=6tdv^pd9zU|Gx(7W3@hGjr~6%FCpZIa3^F!m zY!nBUPGOH(*Oe^#24y%vp+2rsyfCe}RCg%S|C)DX0#Jrvh&y*?onvBG1pa2Nz zF3}iSZEmB40FThGMch;kq#>hvZpq+_X*%WxWY4wr<@Nc2Z8U0L+NPyuEm>>@tLtS; zD|#=2=Eueq-YU`4r>V*8wMyt4t2brSoz9nSxA&gwx1OiF-3IY1$Xc~P>N@C}`vV@_ z-MMq1$HRAMyN3c?$md%!e%YPT820;fZK@kJUk{v~&MwgF(!w1#wLRU|G8jk)C$#M- z?Pmvxey<9Jm?ueh{t55i7{q-we4kJVM99&1Jk@7RzG}1y>m48LeQPkLH1i(wp$zYx9GrYspst8%)&U#$T9~fZ6b74 zc)#W=2_pPuXX&V+M&3OMqH@<$Q>7>kEg?j^nS|{hyA5J2%&l6v4cz6yBPuo`QA21z zT|{w1Xl9erF%3(Ng#q4l3(HsgoH=%LGQ;vBTUnCex1}!1DTS#@U$s`n1y-wsUrXLn zEYoC}$#|gK2ms{L(`Dx-b~FN&C~4GqWGH8HA}Q+-L-Y45IZsY+KUMC;RCHCEC6^!7 zXUT0_i?2%(;|xuVP0Xex72*`#Id5~9W3i_D*u;+uu)(YKrE zQNmnRoCNiSWkHg#KxYu_`XO{VdePTKpX5A|3xy5o;pM$f8?}UTeAPdp#pzk6O@*a= z)tCjRwF`u>ncD4aQdEbSR4$~|>5`;|$1X8U#eqiQe7N|vaG>cI(~P*Ijf?1n|g5X=kl{ zEm@g?a=F(eN^DDe$rIrIX(X<|v<>*A*-IS9y2wY?6UyL}Lp#j6uSCM_u4(eKx<2=BXu>FO`$_>onry#aEx*r% z2|WOnCWKp`@9KfDln;osCO5rjWx%+LE~CK-gk7K5+}l=Wmy|oTaE& z#@_bjWOy{!gQU9z5`~e#&@<~{8|KY7^*SRaI+2jbspq`Ndk4Qry$9s4Oo|gG-#|Vr zDm{t=fbTmdKcSqITfjPtOm(FryA&2QiOG9oYN$39lW*_{$-B-l{Y`72{`fPRudH@h zO8 zhH8DRXcNuRE~6%Jan}Khc-GQ8KiT-GUO)idB|m%nXlY+F+dLOEdB}U%3Q8sYT&{MD z!n^KQG<{cCXSxNp6s9aS_#liV%eY~l#$Yvl@{q;8vm^~N!{=Lxp`Quq*$-mWQFM!x zBJ6NpPVyYQ6NS}D8r5U`V5bb3pMABKCa)wbE{2y!$(lC6L1mS;Ao23wdpuKZkfVNq z24#xk!n$!5`4UN9G0`+4PrsG+6id16{0E!h0Pr6B7J<)`4Ed>Dfgw@wHpF^czGduf#g!#j%Rwqq)Msnb)da_pvr z4#FuyWq6d&@a`V*IwE3F=?v)#19B=TnX@R=OD5T&8t*nUn4Eay!8VQ(7f-6XTRtn& zd2VgrWM;Rj*-5(-XCn4R1F0fQr2s8yqyhtSn?ka$TTSJIwT-o%B?nbAAW;8H_2Fw8 z_SLJyvjuQJ{kz8Bw3GahW0o-=6D-m7%rfMHTTW0=(lCf7 zU9=+d{1$*kKhVUaH(9`_Lu^D~&aIp5BDeq?0TfuaZgjuT66#>phXno;z;~;Vh%Po}|)rHJhBRAOvY;%L(C-)Jgq( ziQGr#=xW4GuZ2GTcJrfGojbQVncj{2?&$)Xoy^RO(iV-DRu3%^=`&$LIFon)s3*C(C%cUNDSjc7$ViVR}B40{A^;@X+s%G-G2{ z$vSS?=)6d7t6Dsa1e_(Pd;+k-sevb;;t1m$WY{MdLeq9sy5u5^jA6Ba{00dqDEr=b z>_upvU$5Iq38^Cm!LIbsGj)DbQ0RUtG>^TX&WY$*!x3_J z^!(wZ9oQ4(vx`@-TT%65=^9cDG_aYB(LcpFqekjBy$Gf^RhLh2Fh{}%MwBCg{wrbz zXyqp_ph5>km4#3%D62ToN759{Sr52{qx-9V0S~UQbWO->-~?lL7jpAV5@j8z9Z(}2 zQ+mM@r{_#(JzK5wVpj^^+l1NlK-Je=h;+&-B&G7wJZ|uXqXPTPX2}SN2-|NcrGi52 z-ffpVBonO)vTw1)ol5^eX<=pqVi#+%`-E$cLNRYT&%K1|x5YAsf3+69#TE98%maD+x%i214__n*bn6~6M{Pk~ zIMoN0T)9FbU97Vjkakr+-qlVHsPSu)kTvq6_i>>~Q?|YiN~+5$|HGi&!MW>ryWXrG zt!$KV*|7S!rtD-DZ!^)1=ctxgnBovh#}s^F9xF?9QwxT92@-S0gjyF((NAYoy$zkIJc@Q6 zMj&CrFnfhGq`MkBfQExe&_g?chG29>c2fOAp{DSANBWsY9vL19aF$pFVGfSpd0pqm z5xa`;&NpZZ5moSeTb&GfWZPf2OF-n}rl>mcKwT9$SiII>az3UI=NXXE4#i z=UyoJ%%A72m$_Iq?uX0Pyv$y@YVmp``numC0Dfx?as+UZxfshCz^u5)SdEg!^+pD3 z!aKpiZY0xMCeN_H#Q5E~0~5HrX(a2$D*VWY`1I?9x0+-7-FSmlwjEki8fYooj4`{3 zarbsiFvq8@nFpP0qnI;kp+fAyr(m9%E5l{~lGRmOkIjeBF42h&J%mt3MG6N;d>HVy z?6f0{70uLOF)bIlbhu8s5|o*qbJS{uR!%uJ?Y6w*YDai$`>Oh_z-gj^G_I$VAnUc| z2KWle=i>(EAYQ8-CYy<}43iyV-1?4sERJsTyUqsrmVB9H+>t-DK|*UX=sGpFR}MY< zn*DLbF3_()ST13u(fo#`UBnABxC=(% zBXdouWbu`owiV@^##rj;GyTiY29s_ph-L!U9He*?_M7r|KZU6*euD#al@KLN!SFrT z>b?s3qPlZWv4%_ASc(AjC)dkf_(DbUScsY^Ly7Tn-g@jKpz<>~EZhQl5UUrMlifJm|Z^AS9ol4D4NxeOZiaph+>6(=A4DCbmij1La zX?eEfW%WgTL=6i5H$Apz-6M4$>uD1vESUV|sN{GA_LGG8sTu1Md$1g`yglaNxq=tV zR?(nVjH-G;AlSCO)o`LtYP=Y8Y`0*8t@|b-&xrk~&4at%v_^+nXTDd#E0-6#rXa& zI~|y(IO%;S8fG0{?~E23y_Spm_4K5i^3EcvioI_Gz@Tq=DtO{I3}LFjv8w;{IZMq4 zJy3-CGvVXJ76-!z-wL}tG@ahjF=iHTmdmeHsXZh5L7(Lz{8{K-B=^rQIW-2D4Wcy6 z^!XAK1~)v&G$mmUaqgRi1`AJ-dKNQ^sf~Mtwa!Nu8gT=KaXkGpdgdKUVGRor_l2#S z4_Twefu4Nx`ah=aZ{Z(4pt$~U2cx=rgSeI>dgTXvloGtn|7tvd;d01ttRYBvH1QVL zhDj%u12FK3_YQ!+1H!V_+Kw^R;u^Ch#5S113kw}|ppBxGG8+# z#;LMD??60XAHM|)orlqFgwdrd@i+*$5Ki#dVG0s2nB<)1dknb+&%2F7ViJDJwxQ(l z=Wym{h(w6AWx2o7t;qqtlAqD`pF(4h?Tm&Nq(^?boV4$c^USdU{gRBXOYXAV!S8o8L!*YEk}9tpWnYrg_a6~$53U@~138XE>3N59h4FsKdTp?K==#b6ZfIt=nr zFBbv#+jQ%i#n6@#@0T_%-Q42XgcZ^6k(iUmB1_0#Jp4YOHGy%ZFq#eZszbQ~E5sWr ziVD}R)MnS{{>PU1XxmT1wLcK2zNazROqMFGk{MTpPRJSkwgNBMI^hQpu7S2}a5}e# ze19dA0WL`G0j6GwJ6qjA278({<>!?V~vg@D4l#LwTMQQ$=k0t35sfN2%#zCPK-jEp$ox z2ii?Hg}(9tX?t9m0apfKKzYDK)2g}5ddxKQUuNN-;wUej78t+8&hYMmLEBh5-(9e#(i^8| zIkc`m_Z1q<6kb3WkI@l^02q@L2gmudkK}o#4!+yQhiIQls*yNxCutPY zB8`Dcc1kg42&j3|f&YhC>whAs(fBJPjEDID%36VcW(fa3Df^#<9a4W$##zDp;vv)^ zTuz1J4s*yF6~lDU+~u&a(IL-dL-_8`K#Me@TNu(;ycR0f*;Qb^*t5OIEVeX+47u_Mk|8N%s?nwy5D+%;$AK7M&*>x>h-1WfUnd%LZ` z^7}9y)3^-g@q97zJO|=D^M>%UaJTDOyAsuX2Vb5sqY52aC)$D&PntX|wdvoQv?)q| zR#hY9>EP3)41+dMf~!``^I}fblF0|Fb6BJtxU<=0yoAP(7KG=bZ%s^8!z{wH!-s5? zmy`otoViLiEQ4cCE6R)FpTFrowZ_2!s}6$G!fBnn=2TR+!YPAd7y(>y3oL{dj3t(1 zn)xm83557~@|bC<Px`>n^+ z_}KQwfSK73wN_?uRV$?&$$LecEWasc5m#-VqSW7n85yL-?D22Gs?-&f=ha}qjMLqG zi{JI6C4@`ZbE2#90p|nWl4BOlD9!+9inyb&Bwa$oTGzIbu#nKmB!;EROO9PfZyEVJ z)@%}|`pw1_NC330Cb5-f!mrS4Z3q9+Ua;_qJ{RhN8}2-C4@zyKaKU+%yTW`%o;m{P z13Fje88C+o9aqsYu0w&KF?$)HGE;;ksnS?MoL;bfqZZ&#gt-Kd-D_QWYa(NH1yNVm z;7iiUMp^%tc%hF~*Zv$ie#uyRYaBC*w+dQTQB!+&NuVPW{s;;azG&)R+}ZPD!PO3D z93SEDfWpPt&~h|Arb+wgzw!$W82WaVJ#RrN1`~~1(%;6F`yS9%Ov|@G!r)@Tfm+%P zm3sBoEVlUNJ}&Q8Xad5UIWiu~10#3A{t**z(453uN^h-xGh=V`93u`VerT$Ldvh~$ z4UReA%eCVU^mTcigc}Gf{lOGW{PisZNKrFXm${2!)z#!bM0m-!Cf-4L%$fGDmhN#O zmw#xk9qKd52j;f)PGWC?s)U^dT2dS+hiRGV8d$0;qobC{T1qReXd7rmL@04D>47y9 z&)>Vp?5{oxCXqTy>VuxJ26CtC?huwYyUvRm0Nv?Q8+C>K%pwOYK695ARJhsc*_qgB z*;qJX`aK-H9xi9EgS|<}j3d;O%Y7~SABpBHuEFz(qGT(g1?L*TR`EAWN0za*a&#O9 zSrgq&u~NR)cmobJT?!>`@=UhOEIqil~|@ z?@k$Dmr9&2dU*>pCKaBDF;7)cFnvzXdU93VJT(%lD+{dBjlQ23n#|`S%{cUo&np24 zt;MZ~NZ9tW-6>tM-aU?Aj3)`WDJPVuMC9-K{B*Bw4|JTuC{Nat)F=8N@m3#xx&gz& zxFHz`1LaoLXH|2z-b{O0TuLG(6-*Im?_o8Du><&uWa9$aBa?8qdcIUIBxC%zk?1Hr zl@8PfhbnU)^#Yj}Bd)ItsO!0G#9vkjMHlv2>|ROVQ}b-}A7>-0qepH8NC0_9l%LSE zK3RGvzPmBeE|cTW(7sgT&t{3#@*Ynw_QQDyEt)0kmG)$2oCoCAj@)Kv23ZWC&kzGa z-ZDBvYRQ2+;6K4<@p{KVxWGu@=-O(1<@|4)R95#IQ$-A0Q)wk>TMcmX!`#JvZ zctAQyjTqT&Qqjz2|5nP_4C+$KJvL$Kz125;B@y5U25!j-Zoo4{-(c3?F8!2NEEc)) za?}6%yN$PbQON~9kw2S1x%m<&`P2hXm}@^^5Da|CLb%lQiXhg~cK^6$-bxlZBA5vs z@u0J#hb9iEVA}&yPzv7}x#{QBDS;b&UoxHH1^MvC&5VnyO`e)WIc*%ODFDyR<2{R}=TX?U_$T90w3B8?eMydIDeu3JLC6wj7+ ziU<2>S)NY_Q8r|8pK-9sJ+}vc&d}l(hOGh{!yxqr)2^y*0*{(!ak(192CmrG1Mv$- z$nfuW`Uad>H#nG98iJCa$)dMc>zWsm+E7MGwxgan)=3?bh0Y2T5D#!)q4mx29dBml zPdV?*`91c#qV++4ehCT*87V7F2G*;5abvr27oy86CPv^nHd6}pVcms_OB9YWl{Ek> zykIL8C~fZ~3sWi@L`tit0b+Pr5#=Edd2*-q4=%9^TqYRWdX5y@d!O&yd}o4YLB4H% z0w*gtr4F?*7<=J98IW139fFinscyA@tdY-?18p;v^&*BMC<)K`xK$Nt|jy@EOXT)Q-*;RAbe^97x1c1udFPfC8{llFNx z9?o7kJJHCatL}wag?B4CmmAXoe{)aqG*EmfAtV( zpaF2Qf2|HvsQ;;0{$qUjD_8uhMWjuLiGfO}@%)ePq206Z+rM@PU+*|@u!+RI1b`pO zzbmI7IZ%F+0jcYrI+)ivLgd1+JTSQwY8_@#P2vX~6k!c-1|}|dQ+_Q7@K?ET(dmY>ewp96mu#A+JxbtVWX7BUDRtpRVhPH zZJrobQ^Pm4=>hd)m;j*fM{ol|^RA5^q-FtPA~2nxj`-1_FQi9!ma6<$((I9Oap00U znUgn_(l1H%sk?hNs1_rJC8-ndnu;O@iJEg3_3qUkZf^cA&Mqrq5cVR3*}89yMYRAh zoz>9clL?Psvx`ml4nk(T{kuf|sOYF-4@u2XNeF@){v9Uv!P|~Yi(=Bq$VU)MrJz-j!p)G-ej+R&#Cl!(lItQI3+g|Ayd{MstI zay{I|17C3uV`=L*qA;o)U_1_rHffN-cL3I(m`8Q0+t!n*SKZkRy}fz&m8ku>l4L6C zjU*emiSfaD@108YasII^SD{`?M2)Gkp}lu~wDbsj8JWIAfZJcZST7@|L`8$V-#jdn zEMZU8Aj^fAjWSTa{GAu)Ehh$D9`ERqK*>gSXAw51EYt-jS3YzZ25s#G7YF5koW^8d~M>d&9KB zAO=%XU_Oac|0a(B@hps*985nv_q3!J(}EX2^e53kN)+2!AKMb(BS4-6l-kH--6q`~ zR+9}MlZ*4C1hLT)(9k?Oc5y@*!EH*8bY@$t-D1SZi50&&Wdc zE*ZL!atQ>PzO6JsFtQi&XUD%YU3F-P!u=`KL?W%_)Pr`CIQp1O7VO6r{g_ zqJsRtMq9~fJ3^wh8iP~hI9*DhNUD8aGHNe7my374i1LS|s$H{B3-OZP}Kt+fFPrB0p;v<0+mdJRy>$8~aJugc`N zJv<7)71Tb+>%6Q`Z0P|j>%brv`dAtJ-T zV2fhbivXZPZw1gIG2}HB&M1l$V!@^X*Nbt$){9M+>l0G|rUf75k=+UuU7ATiFUn1p z=vSY7JIi$Pxjr7S2IO%OPZSMqc~A|88n9Fd8ZJTZl7fay5TK(Nq#=m7p%di94KfzF z-f%#e31kJ7fs7TwX6)p@?K0rB2Z}K6`pJd;2H7J?X(!MJN-^l?-RFZ}Ghyexz0|Vw5)ftcI4FT!Y86Qsg-jq_mH}jl- z8xYC|TL8K+#tRe;ym@oo`Z-K-Jr%rH=T<=wiM=wLl^^qrxe8Qc?bvv77@*q|9S}G{ zwoVi^@qz>hWj;zX*PRtpBhL87?YcLbcFz0uTjY2y2*wpy!r?{?5~GYsrO4<7i)q-w zhFaM&8f5GFB#~g%=WOcq6FXCG8$&^t%XAALAS%m6>Hdn+)BNdOTQ?gXaD=X8pREMXrE^41Np}eBft(*kL$XH#h)}1O6 z8Di_foIE>Bh!-&=at85Ky#g|@T8v;|UEP?;Z56ipvAC;DnT}qsn04q+l6qS2H7dxg zp7~`a#@&^rV`l+eGfLLg4O%1ec9YK#u*uOfX-^s&$>Cw#7^;ky;qAJ2;Y9SDF^y?p0P>b6LqTfWD?x zDXplQ_SJC->>o@&?-F@j_m|R~V=}z1M)LpzB}%iiKKupoORlIU{_n#%x!uVv?E~sd zX*6T-oXaE~-(USoh<+#$awKL~L|);laCex~;(WX2SL~f@uF65e@mVwfb7t}z3u!0N z&{{2cz0;E2=itv#eoBj_!6$$i-T zc6H!_m2XV%bmVz<3W=V@gnk_@Q@Feu5>l=d@+k(CGhR<>jMGirnsA*lGT>H1P69Vf zq6+yDRvLMTBfXQveyi(@F(f>V2i=se*H0D7)CI?s_j9$Tm8V3ECCpF$T(4Kkhmw8^ z>Kk+fiDl8LmYzjn|MYw$pVvl7gYj*@+*4>JS!kH5EMjd{2rw{d7%;H^S(0zdP7drJ z7wG1r7~ohFT@vG!zB1HYy|*|l78pVPh1^Ql7Sf*idysIPxSiiDL&j$WhE`|KV55zC z$H#!Io$N`)ddVn`qSJw_na%=$sN%WZCp4=~r(8pe{q<&7qRzDDyR(hgms{vB`yI=a1Hxi$ARS+n5=Rnrp* zATJDpf+;+zq`7V&S4#}#_FXqr(CO^?d3 zjBNf?vg8}eb&XPFb=7G6QEa@-AfC*@O6>snbGv4h*=itgLyMQf039MB*~#4zXL0r& zv(^$agKt#@0rFbP?o~zsR#s%`c2@}N0DO@;a>E4a(3WbM-j96BwoI%27^pqzJ4Q_v zbDP5Csp6S-KI%Y9q)7c4mUMS9vV0!9Rvv`oRy|}O&)C@HDI#K??=K>vKB~a-fxHp0 z*gSed=Gy;T8pIXtyfQfkyS5dCl&ZeYM)^Ia{8*h%@i*35VW9WK6a;ibHQ!X{cEf3O zVjDzJ(~ys!U{RCPcW--Y*o*@KyoEy`DgH_N^Ih}+v6*vM4z8$ch_g* z&2dv4ujzpwRv!J#i_}E*$-kpK!xz;6_ye$*1Cx2%=4~X#wx741zcPcX_v_NE_w$Nu z>SOAMm2yQDhuk7|`X$-)!PB~BPpw(|6w?^=D#Kc4Z|)>Gbs*Rm!Fvbv!X`KfSHe8= z%XFL55Y`o@_3(3!SJtXH!2dp%#il)G(5l!s>-A1nAk)E-fvzJ3m+pj1p7*H-Ae84G zIGLt;&v>}>UJ@)U$N+lG4~Q&CB9o>mcN!v)FO0o?76Kf$R|OI-t0NRIN}?vzR=f8T zNi6hm42$p442SM@`Z(`3M09gV^s83ocurF;;@MnbFjsI>Ikj};iUYApq{kQ+jL(4d zEAZ&S86=IN?woXPW;Yn{uC#3cp;&&t)QJeuEwXlwuZk8SSqxjNo@f#yWAf#;H&PLWtlb(A7bN&aDr4tisJ}juIm&A@9EPvv=8^fKp2{N)GC=t@Ii@>9^x{U zVLa0+Z4^2w>iKbpI)b1|JO5rFFepY~U<#`^Ywn;TF3ySAg}Z~NUj-6Sz+6+Bff|u9 zU+RH&q&kYuI)$lRD`E8`t{&E&e=JWmFbq#0jY8KR52L_DUgKdYF^id>hs~n-We$Pf z*l<<5oNI(H*66!lX-2MjOrp?MLdXGB91_C=q_DC%-ciQEjEQM*-VWMrqLpjPFJBF9 z#3zg~}Y5l&@HF0q>}k_YbG z5($PG$*{udCb>?rP6@UAltY8u5|^2_2rso}>l4x=qSQzWmnSL+bs#&0Runwwn3r$^_LYZdiyAf-rLb}C3QTcB ze6HQF`jydcIEQ@-;6)s1`7)YAFAO8jL-bvrOX-kzQf}a5kO!VH9*Inm5ryf` z`gFXT2|m6+{M8QdL_uhKkYHft$Y5aqu-N`uWi9X;fCfALk@BG8 z?-MEgCN^57EVf1=8>HqAXJ=%DxLM=DY6c z?fGpqpWG2;cYrlTt7CD?@ua#qt#{W2!y_@UAZ%dCgdk(HBpoq`HWcb+8vkIx*obP8 zckp;BB$KVKfG|9Jkm!Br0;D3|g_<|%IyzTQ^a-Ts8&WgIElU9J%w|6gml4<=58ryB zz?Gl4<~`>2jp6o~Wqd6uqVTunHqZQ_W;n+iuyL1PxolukbdYu`6`CvC{O}Vl_d<%A z;6Yji7}~;NU)j@Bco|xgmCe&GPv9V-qJq?zLyCSuNy1=scK%Dl1aJ?I|Eq+6vY2W1 zMg0<3rBQsFykw(8?>(4pv$no>PGa07pM!n&WVnIduPUNDhSZGX0NHX3i|IlwJ^*hO zbtuc&er82K!-u}>k_J{U-6A?ngIHf0v&V+!Bu{JNqYL3t()fCao++Sio0!jr|<$L&`Qw0d20+!@2C{PqSlC5Wr$|s`<3z zvQS!-2iF8VX85F>(_FajPVK#tg1G$g<=(%`*BJ|+j#=*c15L$hHzL+Z(-4zLWl$qt z0OOM9sH&g~am|gexzx17q&JW)mW(t_mj~=oD&=!#L9LS=8Gu`4y5QBx#Q6}v4_mx1 zHd}dlQD>CU*oskglgz|UF*Uv<>yYoDM|fygY@$WVFV37-^;y)}D zFlkUV5)nYu(ZR#q#ZApoT$MxA&e+ve+QHSy+|;MI+MfM*NAIih5XoS%nrfk}c%dx-rL46dRqRJg{L5R#)YiiAz)bXvp6Z|PB zIEUjnd$_A>$una(`Kt1mwH8PGQD$y5v+X?V8j!i))_8sP@@HbA6Pyc3)bRZS|Ms~Y zcC?pd{}R)BUo+2%kR!o3DLLU|$h_g#4{ek?{y4$LdR@>g(=5Q=ld6zN<8ADCCYra+ z5uvAndoBzUzkOrV+o1)4-g<19(tTzZm@`3PP0g)haAsWWZs|tpA@=htf-dk=zq_O- zJs?9EhfUt02w~2-sV7cG@%k73f@M>@raWs2PO@s9cQ@6Z8*5t4D7QnasRm%LsnLAW z4NlM1eIzQ0yU*CtP1SRP#p-gQt1-ti+!<&zoW6&!GSf2jHS!O&Lu`pE)R@?Gav|nh>FTY$~I zaic|Lt+C#?r)){q5b8gor6qe@_KsybSpLZx7@^8R;i+;dh4btwijj5{DUG*bxLem1 z#o07zQRU;m!faIc^c_0mriT_#UlWribS-|NM+TH2?XFSGkz}Hq^Y1z?Q(|&!8vRef@7+}vDHa`Z^ySs zXx#yMQf7u6%el3#I#afM{S?BDzNSXnu}r^}9E5K%56x@tq!t*X4Xk)o$AUw%DjNTd zTfr*oPrij!^n|NuXBNF+BoW!-k-_jSWCfwU(hi#4Tv^+pxlwZGbqU;ddmGT{j?NjB z6T|cA+i_{3L=tP=5RbgwRZDmPSIu@`ouGlgl*a(z6wkxB{ zX{C;sL)rrQ-sI9Y67{T43h@9{VEYx3Z5D0V^{>7GW5(gu8me1${-XLI0Q@I(@dKy8%jI`~`K-IE`d@SKVeU)7h3Q5W?0fncuMc#vJ<&vMDDb4Xwjs zQ8kUB-B;t}CAk8Bsc?-@1%4e1DK{}uBF-CTb|G>eDK1|?aU=gTF8!ip*`u`V=P$Sk zD=WN&f%TpOBHy23Z3qFAYG97juM7!wQ4m&;eDae@k|gcPWK1%z%yp;=D7Oh1weImo zx5!fLipI}kvFwCt+l)zrG#ESg>kEuh7*E0ZU&HrMhPV(ZmVLut98F5e(@u%6h~qsI z5aLg~A|{q8Hw_>8O2r}Y;Kw|Fg%|EW#5n149UkeiK%QhxSuwuI`6CCz( zXq3A%A6!gWaXsVapKx7&IKEpT0z2C=2B29wvqBPpWLgUHe*jlt<*ZZZ<77VvrePrb zVqcvyVj+_yY6!*1!D2c%t{4dpGL;@8@2Mj4!u-0ho4&8cy<{2Lpvf7E=Q4omTX?Ge zr-jzv;pKb0F(hMck4%P_mDPGehshrO2VV!kRbB?&GQ_F8fwGlA^b|aN$&~z)}0=CDY;+%>yhrf0Vg)t7kM@qTr$vn?st2y*ulc5m~p15nQz9$_&T=%Lsu)S zs^*obi+<`<pPVo76*VD@oxKF zZil9q6nDtRt25J)TF=Y>SklFQ6W)2nikhd{WdBSZ+Yq>=e@@L<>TH9k!L7E$*m>GK zrB8}>se4olg#a38M8SEOJ-T@&_%2uu$;4CoiM+*_P1n@TfcTXCkl7~&`;REo4h%&9 z$!C*nk^yI)ucX(mWYrQ^JPd$@Wb5`I*(L#HhjZ_qzJB(w_HM{tR3-o*Q<6dxd*oa$Xce5yk4){mP}p ztfTRwQOYLUlbTxW;Ixqn@6r+E*ikx4OiU;;wgc9c0Zv1<)o=;U^pzc9?+>MxZ{Y(M zo1xmiR__Q-o>{{je~r{(yluaswW^yu&x5&yH}!?(hvfPZ0_xLaW9n ze4L*mGB~-`#e!=?!Ka1LJ-?8&jA(jA{nA(HUdiN5+R*2h{F9(bTdK>qzGA5LqL>`} z=+%XQj2xLI&av6@(UZ;;Y5iS7%GEnImOg-iN&G(y`S-mP^r%Gnf7(0$vtxeKuz$1J zF#;T5PSA2qzLZ)WlL-Hm)z&SaHz{W(4%#aCm>L*hlsrb>+_WTr7fRh3mZl(B_nfO* z^xM?(p`^3;W_1h-4GrfrtK~#H<%Iuu^S(I<@bb9B2!>o05BL&+is{+P91#`447mgA zW+Kv^A2fj}$Lz*PXa}QsA2Sk{*=T>ZN7r-RG{97Etd(nZ@0aw74U?kTbm~i+rL}9Z z>0^>Tp_6lZ@3(+%4F5_kDrsRC{5i`tB6CZ|V9}4d_{7O`Y_WPUVVJkj*dDtg?r{+N zZX_sEU>vKt127?;ri`OI$FaKRMix_(=_dJ}4@$g0QS z43O|rAK}tsq3K=9#u+)sc?3G(ct|teS5(P{v^L`|b`)QD`(}$!o@=jo_=(mieeCfb zpg;6o-Ec-U_HA*#D(LuiFB@o%DoOMw-Syk|Y|LqY!LhbZG~vHT3bqt`meK_c`eqKBiL^>8<}nq`DOUqI202-<8dhKHSHRE zj6Wct8v5b{z9nP!6xiOc+7Bzrc-1!i(7ycBjj+KEK7vfEfDj&p-b4ZTY$jaK8o^Fp zme5PCX94hvqjkNmr|@7GWhIwmMbur{O4sI{h{RnRni?!dRYlAbQrsr&Flr)O63v(F zMQFu3$-ep1q7U^--jfIKV>&rOqrpW?`N%#{ja`G)uH6$B+jvbQV{XWZ+a{9Lla;(C zo79m!VhJC5>gVC=?Qiev;O^~j?n~XuMN8Qz1|R?!OyafpW-Z=W<*pKr6Fciz(>$l7bxT)H&_v}QuFTQdJe(InENa`4A@Gy z&OZQ)fi%A)KY$qFd<=5FDWu1r;R7IU@#q02O)?W^V__H%Qg;b%p~)Y7Zf96O5soJ$ z&u6LGT{}_{I9^_8E_<*k-P9?qcKO)1e^=5G3_n?rV$~BY3?Njd1W11U71Ow-(BK5n z*bkT+_Ro`Fbe3NGqil?vje1M$Fl{Y8hFXNl#3kITFZP7=En^4Wagv;$T0W}|m*omT zrrCI5ePA2M;F1ya!&j4;&_@$RRTG0oHqSRYpZAl!8JlPmI;JNJjRW1wNXc-&&Kc)i zMqI4{FAg3lrJ1>Fu;AApJ;napQ!NZQC8`_vBJ%v)Vv=EmHeE>UgJHAZz9wRcyo48_ zvQH!4y9LY1v@gX!R5*nZPEWwOBbQ$S z5Gq<$lXQOa+FmqzdG9@&wTYfrRnLmaI+cyoNpjPGoZ;c|fRq6ur&@Rgz8@rp@*e|+zJry_-XXVXt_1F+S^TfkfkCXuG!2x(e8iZxw%Px$m^i%p)$`{o-(^`p!RpN8gB zj(*t()k=!9q91dBnR9LVI|4*-vriw67(Ms0e9yd3S|^%WUti7z1;8(u))kEyDRd`; zgYd`6xcCaTe*pXh%D2m;-Arl1vB!rRuT`Gvxw51;kDKB`A{={jD4C;OoiTQ(q?_Yp zSfvx0Y45OU7$`1(_@&d(z@Gdx!%y~Gb}1g-YW~==S?siHpcq#f2jt@}B`n)brQ5R4E7H9+R|ajXstRZv{u8v1t>JCeW~F%r+=ZQC zW7sRJh!;G?%_}U18NuUW!+795U38U@e(-exeG0}b+4)3}cLYfog9Vp$M&D{BV5J50 zloIwV{G0)_KG%kvLTx28TL+R;JPp@5jUUWVke4{O7H3$x55!$7VgI&3l+ed!41daG zvIy0lq6g3#ve~DAsmpiTY5hqkhASicvAqi)L$z!^;$^_)@UqA6yl1wf_ubYM68`yL(Yn9 z-wju?d#Ir8MH$Lzn}WetgGvfAk>KK^sa{Tqk^m$o(-k-jMDn=pjW`V;rhFD`LUrt+ zZI~1*+o~WA1rHUnDv5%APqRrq|4bZKiF&{e3n;mxA@RtiV?ec+%Vw|E!}@>_JhPcP?af)mD#;^Lu=(A>?X$g+M- zc2>22S?`o|>x)}w@f2107S??Men7#Nd$s#Njmq6lb2xIs5#p}(Ad2{4>t#C|>wBw$>h@zdqIaXi z^W4CsUxMtMT!GMNeEZ<*wz#~2~TJI6OgSfT9AS%La^E)S##jNUUh!# z`|iAMNrWew7Z%bhW6T9Kl$D6gy1Wr5k_FDVujXj&Q>gMH#pC_DV)%q*$b|h8B-PUD zSF7P$|FFRgstDol1g)GyiH%YDW^7g`o%yF zw~%f=F&sQbPbQ4MZMlM{U^@rGsRQ1F;XRU)MZWaPT>6a2LbVP9Q92j?#;~R!-LP*b zx?+(*uyAO6i`}|P$YPI<#N1Qa(|c1bg7cXAVi`fPxsIm3k|(&!52}EbCX`gz1(M)M zE6di!ESa&L3Wza+>av5;7Xo?xv87dT54v2^prVZdq+yaWv#DeE)U4uAgRh4WCj%)E z`G#GjUTj|uS&)pv9%8$Dh5bSgV|KuioC$j{vj&YTIH2PQh^4v+Pbh?2VO?UrAfinV zz#J)$_m}XCPFftE!|?+;dgmHpeiB%|MiK>p3XX|7r=~kZXHH;UQ1Ic{a;`-IQW^)8~C+ zAoQ@)p?i?|@X_WMRK-huAXksO7*JG9&4LrS^O@U&*%SpniK`C4+=-MsDZcgGnv;p_`!iJ%h0W?`P&znNgPCjNB!4Xb0z}XdSKXI5dSiTuoDah* z=rzzGP%OgwV0ZZe=#P{EoS4$j9ZZ<=&pA#IfR1p_34N_DUm|F4w$NYvp)=jrL$B`< z9;N=}ZwGHKE2#G55O3PHwuLYAUBiO3#rfYAC%t?h#Czwr5<9}X2Bnv0 z1sUlh10<}y{^O|BtLduZi(~V*H>T0Sf0nH<8YBy>()&uaN5U+^@G$|A7_WK~+Ey#w zeDGwHhgEhfSg_YnC`nOApf@!lnNerg@sbl;aRMoYj#gS5ZqBvi?1f>!_2%VrK~WGQ zwaeub4?|-P@-uD)75=2M($`>IAR7X_nFC;{f?)j<6I@@7Cc8anVvMO{dVLoM7Q|x* zY1uR)C3Fg;if21JwNsl_t4oK0e$orN?cA1h$3YUk<;M$B z;4Q0j?>j67$|FT4JE|YfXM5-~)`_gRN*}mPUDNIrB53-LctFf7ce3rbJ9V6Kxg}Sx z(VtV#+_#i47|6G1jB(g@G*XY`G%t1yCI7OplWgc%DtPYCwRI*Aq;-@OOJgH}cY9@} z4YadoOb}Xm*((+DrLG%RB+{*KN&)DI0~LR9{8sn`6`3)gY|fLc%PgDY*oygZWL@!W zOYT_oCrZ8kTjkyoiUfnVdnX+p{sjKnOKL=153?D2)Gww8=D>B0G`|+(uQh75!z^!c zYjAzpnj?GZylwBKYOgOYOp~-smyUZE<)eg5iycD*v_=~Ik~c}UV?m>}S>%A^2uO^k zt{OuAwKVpUVpuYG8#;xX-@oI5`;rhNh#*DGJ*X7drU=j4$%`x@OV=W{Hby7k<;vM4 zP1CjO=n}8J=;bq8W~hhY4?Vh^55d(hUB&aklSZu3>efwav(EZPRufSac`7sIvMecyixvBCz$$_|-Yo3@xt|7Ofa+_*3PWZ3;r`IO6twWzw z(|QmH&72Wy!BcJ>_wgk)=qwvy?ixpG3is4{L<3dnb4$_*MVTWdy+#!Xu6i5Mh9Mk2 z)o7`u>(g7=Xl<9R3dUrQeK@9U8r(Zn0$9WRhKUox^MvpHSZ#XmX*C2OVrFK0LfH1r zBAXgNKkTP}jg_1yIOv7-8C2E~aLa1EKKV8%axkbm`H{Va>cV5t;y01)G^o0fagMoqf2YCsjqW0pYsN zFc?USRNk4#Pz!3a@J7z$X|Gjv!N%M6+veMny@cBs)sbBCcBJdnr!3yAp04DWhmEM` zgvOQ}<;S##Py9!oDCg*DXd8X2y1Rle;IRUa+cZD?N)7D~szI>i%+nUep(@UXzNEkCiql6E4`0|ms}KErvhyd=NLNcyU;z4A;~);8;_yCd3$#Z zwx*z;oVFZ@_5hn9C@*mbk51eIK|N>!N1`Z{BTj}m0(*VbnV)zhLr+peoMA1oX+S^$ zlzmv&48mBK;G6>9T*{zQi%T!PHKM2k<@JIzX~JqXefYCM(E8wJHBhbAm|WD-GZ9*{ ziKll5R(vKXzR95wAuFoLr1aB?vb^e?NxQ`Pmy&_zK0xD<&yU!RWEDgQg##?O6?OS~ z4rZ-rO|c!jpVmi~PM&cvqUw#Mmr69uUC|ks3C0(m$Ef7%mDr{C9z1I#en8A;8NFzl zPoDTvPGc;dsWwEh`3R~6Ti={pD-GGzWhoPP8RT~)B=wl(6|T!^QEhroGEuaUxux%7 z!aC?nVF1?BrUGWts)z}nm{XywCO_%2wPPIaK+}tcFXl90MwgR5yOS!q&=1##4UdhF z>Zz!Kl%lre7SrNzDrm=}b7jO44CJMqSWCoC+Rij35{>kxOuDPgQ6|kAr=?b0h)LDp zfX4_kAqm32iF=lF9pYg)gF(4VxrF(LFI2I;n1Eo(S^**xs?%Az;PvZi!a_QB!V~2L zL=R5+^z4a2(IEudMvU}H0rv4+W_uENOk>$_1Q48Vbx5t+ZgCg$D5kfw7k7NJ&D`j@ z>4865TKbXGi~|s8ch)jW07a?f3vEphTdYioD4$=S!wen5)L1yRr>Kx+6VaC~n6$P0 z1jqu{f@^9sW-p}Hkonlr;S8k;_c)8Ii3Xu;E)mG_!$NCai?|+=eIgBwzQ<%hCoqcR zN6R*BeqW<8RAjF+SZHOt$a+R_K?^#MUA)c9Cw?^*7ZVw zFHt(^wrE*8BEFjYA)?|K4sc4j)K=(H{E0u=nvWx7FXOwnU?(hGAf3BUj(T&P&;T8@ zJHGcFQA9AinwZj%J?SGQh2XnBfX-0lkTj%A=r(kHEc#S2wnp$Rlp z>-Ku03Tcm-^v?;iC;ZO1OWDlI{>oCarxx7K_)FaNu(%Kn%~ zLF$NJ=V>IElkV8Nf%3^Ns95&SFhYqEeQT3zvVm(*Q^xKw4dfL`y;cFa{T*(rBx;>tG3SQ$Lx zJ{6&yb($()Y-t@t7-&Dp8i1hMfN`o6Ya$NBuCS)7kl<35m_#2?RU1Es%MN4Z1rp~; zN=H0RuJgCgsM^LaPSWw$hW>IT@x?$KeF7Jy#0nmuN?LV-!oL0F8Bp4%8?l~x1!wdi zz%+`SHltKvX!bD8meyb#Ddv^n@;r&zd@^fb%G%1xMn|IO^R^tuSOa!Fn;{vOvPb3V4Q2_-6xz9mlu*g1K>*`7%O3j)H>VyrO^ zGm7C6B|_P9n80Z8+HH06xaIKoF*BO0-SBY6aA~nF2Yn)iDT@oEiv5_Nn<t z2~{TuhmR*3lxa@!GA+1V5$=+g2}0M{tCq?wwg_2S$$QFDfyvB?;a@#}j*@uUb;?+~ zK>og${sV5;Zvt>zq&S`)uAxXV!fP2+gDky7;Dt+RlFyH>HITZ2#Ho}n zQx}yNv<2f(BthQ8trn^?piHmhy1YtuQt2LRa)#;^W9SniVB60en=|hZ6rsR`*Q@$E zKAj(GqGGRms7<%5uFC@~TjmQ?r79_i>BBfed!5VEN(ZPboGQ;YpAWFN%GmI4DbEsh zCZbKXo*rm^&&<+QQoN{FF~g&3@Q66F2&qEnW%`m4CqxuO66IU0Nn8_-Vq36|;v+o* zR$u`wour~jD-E=+BZQW2*pN8W`qXU7VGwl#&eA@kGC@+JKg)`I7Wv)x=h?s%$<`-W z-%tE9OYVU1$8^w=0~+R^N>s1t?PZ~B95xuQt6WeX|%bi!b`}w3m-vdzCIty;i-fnx-WV zolsgkf`nM1j>Hri92>e_x#X6B^sHX@@^%_ng-rdEPxMeBqr=%I zJcQg%M)jk%oMg=qo-@<$ghYwog=CQqEtH2!K1ebQCKVwo3?d{ZfLdPzBkK;8j z%y_O9NnzptXnJ{G#)QPS~qLi zTJ7?)$ArPJ|D@;|l@&w=LSja#<+gz_)QC%DXsPo|dB(}c0V6fyV^@EmUYSt{9RV%_ zDdf}~UhEh7i#sD8#Vcqk_Z0(i!@Nj$E)C@5DF{8Dp`=f~2%<}e^gyria%W&Ifr-i#*7IPlvo0rK1v!SLHu+*Wd zj6Qu4ZuV!_m<#2SOT%rXx@|}B3jl2+F4g^)ggE*YpAH9h*jEvcmMYs*?LvEQ_u3QR z5K#}!w^$#ReAZh6NF#A5cc-bNK#3|NJm`3CO#e)iPnK)C4#^<>xT2GAk;6DjRiy>F)ltRB>%K-K>dcL%? zdIxD^6;q!_;WPwJ5no{Qov@`8oVFVW-c!zVW+1=uAU=ca(A5F1z@5(#=#$Hm@^cx# zS4XeskFMLEGjx%f6DWfuL5$L7*8#iLwj(7tQYq%uA$G6dX>1;P6IKmth-l`M+v_m| zO@VAjA6d@pl@X-1>m@aM^Z;<#Mp?#3sm?fU=-92JkEgLMMMH7CfrAKp%Fjr5r<-ku zEgU_g#K_8y_ZDN@@>g(@I*64vZUN%!Q=oI|(r(JQb57s$qrVvhI{Ch9^XDUzI;W`R%B9ebGb9HVxle?p|rLziu&4 znVYA3RokUk*G5FfVE`b(6dZ8{NlO19o^WbME>ulm$RCi#NW47w!p8oCHHx4(uTnn6 zGkl9}SHr)-qW&iUCQ23Ay*L}HPyqFYPo5IQMVgiB{oxi5mN~P)vb4OHJCia1XvHa+B^V0{)NO@;)37+8rAK{ z6M_2V9_&Pos9~x*U^Uj?TWHxC@*9`NGDtGtACf4pG3f1Bz{jXDv?={U5gQt7r;$zW$ z0Pfi(t&QhVS7|`~vHip%8{}ttU7Sa5v2Q|;Sh2s5%rO-K&B*-zmPDdCzr9jUy|CnI zvKEV4;&!vO!oJ5J)=aofWp1yC9=7iKN1?nHu7*!$PtZ-#=R)SLdhq$j+EIo9WS?j* zAA2Rk8>_bu`$(&J+(eztv#c^Yd#~c}RR6?u{u~AsF;)RuVp%Jdl(uo3JCN}5bnY1$ zEVgCYL_R6U93aYnFb#_zTsJBuwWaD%E_)cC>8+-Z1swH7wa?T@*wxE##4mYqDJ{g4 zW##))4BlgyyuSO)W%-vQLvKDa@4r%U|D9|jc`pP5*@@$V!~rPp5kf6M_lNfmeqj7Z z2#2UnP*o_|d%F-y32>YhLTEp)baMS(G^)fPHRsSNZc6!=?E0xR31=bIobn{s+^VeQFA!Gr z+yY?VN|{@oW{pszJwN&qZG!F!`Zfds-Ah8cBZQnvNZ4UHOMq}M+V%3?8&5c%F`O!m zeh0MjOySmp9nmF7v8`h=-t*uKdnAu$9*+iG7wdeI)WTz0U81$jZ;qZT83G@x$`HE0 zLrtm=V@f$~k?7bm#KIQa;}UI)jOUAYiHC@APhvCA_J5uQ4mP1-AG=;9LpbTN$bNiU zPyaGtsvbdO5)EKLqblk?zoR3BBLY|1`F57Tl;b6Jw+AczLt-6^2qkL8*9+p;iV`u1 zElUK`RJ2GXnL@*U{SV1fG6-V0dZo{*!l&N9e`UpvKIJwl2GdR~yyP17ka48K)|~#A z{n8!BE>74Lr0Z?xmbX&BJ}j%2FQZMR?#MLVPAehQpe*2L0Z;L9M);t?fh9gb&U9OBwry#oo&|TY1c&1NZQCQ4F*<_Puc{EWGr=c~7&R)7^ z>KDT+AE4&j-7U>MgeHPfQd!rG|)a_ zV&z!hvagD8LPKt^`184lC+Bkc{6#Ppem|4iV1}SBqvd?*BNRWN{^c#M0}W%oAE&DI zR+828UU2gP90TlsAGnpXP3gMe00W_h^Sy_!mBJa`+rV({_qIJ;66UXP|2-ZELWuA~ z`g`*~r$Io;5eCG6LH{hy=lf?#Bp4k$=mS0>i2nmL=nNhQbP$2?PVmoyO6h+QJR$xi z(Ejhzu>WHPzmn|#%kP@1y)@sgm9QFnQ~> zWBujx|60HX^7~(N{Ab#p|6kNhxPPfp{~x0O4T13gW*R`ok$B)fL~ls!bpJg!pO30) z&Tr}eYIHC#)qimvc_#pIArt@a*PNEBs1AHP)@lDnp!F~0cB;SJK{VLppswiuS%;@<*J@BY7#=|M}N z|BUSK9PEAG!K8_3@ASQWpNfp%s^p~J7B2h0{;d2zh@k)+P*mc7=ra=Wz@7cx>7@hF zL5GP5nr|BBUq^Rg|HT6`5DZLSTuqo>T0w&GpAz<$?4SF^n~?qEq6-AcB@rMIff0eh Nyq&t~3;z4;{{l><`!oOm diff --git a/resources/META-INF/plugin.xml b/resources/META-INF/plugin.xml index 7506530..7f621c3 100644 --- a/resources/META-INF/plugin.xml +++ b/resources/META-INF/plugin.xml @@ -1,18 +1,19 @@ de.veihelmann.closureplugin Inspections for Googleâ„¢ Closure - 1.0.2 + 1.1.0 Daniel Veihelmann @@ -26,6 +27,7 @@ + diff --git a/src/de/veihelmann/closureplugin/ClosureDependenciesExtractor.java b/src/de/veihelmann/closureplugin/ClosureDependenciesExtractor.java index 25f98d0..080b67f 100644 --- a/src/de/veihelmann/closureplugin/ClosureDependenciesExtractor.java +++ b/src/de/veihelmann/closureplugin/ClosureDependenciesExtractor.java @@ -41,8 +41,10 @@ public class ClosureDependenciesExtractor { */ public final Set rawTypesInComments = new HashSet<>(); + private final GoogRequireOrProvideRecognizer googRequireOrProvideRecognizer = new GoogRequireOrProvideRecognizer(googRequires, googProvides); + private final List dependencyRecognizers = asList( // - new GoogRequireOrProvideRecognizer(googRequires, googProvides), // + googRequireOrProvideRecognizer, // new GoogInheritsLikeDependencyRecognizer(dependencies), // new ConstructorDependencyRecognizer(dependencies), // new ES6BaseClassDependencyRecognizer(dependencies), // @@ -68,6 +70,15 @@ public void extractDependencies(PsiFile file) { new RecursiveElementVisitor().visitElement(file); } + public ListMap getDuplicateGoogRequires() { + return googRequireOrProvideRecognizer.duplicateGoogRequires; + } + + + public ListMap getDuplicateGoogProvides() { + return googRequireOrProvideRecognizer.duplicateGoogProvides; + } + class RecursiveElementVisitor extends FilteringPsiRecursiveElementWalkingVisitor { @Override diff --git a/src/de/veihelmann/closureplugin/ClosureInspectionsProvider.java b/src/de/veihelmann/closureplugin/ClosureInspectionsProvider.java index ab67fdf..94ec4ef 100644 --- a/src/de/veihelmann/closureplugin/ClosureInspectionsProvider.java +++ b/src/de/veihelmann/closureplugin/ClosureInspectionsProvider.java @@ -10,10 +10,7 @@ public class ClosureInspectionsProvider implements InspectionToolProvider { @NotNull public Class[] getInspectionClasses() { - return new Class[]{MissingOrObsoleteGoogRequiresInspection.class, - - // TODO: Disabled (for now): - // ConvertToES6ClassInspection.class + return new Class[]{MissingOrObsoleteGoogRequiresInspection.class, UseOfBracketNotationInspection.class }; } } diff --git a/src/de/veihelmann/closureplugin/ConvertToES6ClassInspection.java b/src/de/veihelmann/closureplugin/ConvertToES6ClassInspection.java deleted file mode 100644 index a9515cb..0000000 --- a/src/de/veihelmann/closureplugin/ConvertToES6ClassInspection.java +++ /dev/null @@ -1,111 +0,0 @@ -package de.veihelmann.closureplugin; - -import com.intellij.codeInsight.daemon.GroupNames; -import com.intellij.codeInspection.LocalInspectionTool; -import com.intellij.codeInspection.LocalQuickFix; -import com.intellij.codeInspection.ProblemDescriptor; -import com.intellij.codeInspection.ProblemsHolder; -import com.intellij.lang.javascript.psi.JSDefinitionExpression; -import com.intellij.lang.javascript.refactoring.convertToClass.JSConvertToClassProcessor; -import com.intellij.openapi.editor.Document; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.EmptyRunnable; -import com.intellij.psi.PsiDocumentManager; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiElementVisitor; -import com.intellij.psi.PsiFile; -import org.jetbrains.annotations.Nls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.debugger.PsiVisitors; - -public class ConvertToES6ClassInspection extends LocalInspectionTool { - - @NotNull - public String getDisplayName() { - return "Check if a class can be converted into an ES6 class"; - } - - @NotNull - public String getGroupDisplayName() { - return GroupNames.CLASS_LAYOUT_GROUP_NAME; - } - - @NotNull - public String getShortName() { - return "ES6Conversion"; - } - - - @NotNull - @Override - public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) { - return new ValidateRequirementsPsiRecursiveElementVisitor(holder); - } - - public boolean isEnabledByDefault() { - return true; - } - - private class ValidateRequirementsPsiRecursiveElementVisitor extends PsiElementVisitor { - - private final ProblemsHolder problemsHolder; - - ValidateRequirementsPsiRecursiveElementVisitor(ProblemsHolder holder) { - this.problemsHolder = holder; - } - - @Override - public void visitFile(PsiFile file) { - super.visitFile(file); - - // new MyVisitor(problemsHolder).visitFile(file); - - } - - } - - class MyVisitor extends PsiVisitors.FilteringPsiRecursiveElementWalkingVisitor { - - private ProblemsHolder problemsHolder; - - public MyVisitor(ProblemsHolder problemsHolder) { - this.problemsHolder = problemsHolder; - } - - @Override - public void visitElement(PsiElement psiElement) { - super.visitElement(psiElement); - - - if (psiElement instanceof JSDefinitionExpression) { - problemsHolder.registerProblem(psiElement, "Convert to ES6 class", new LocalQuickFix() { - @Nls - @NotNull - @Override - public String getFamilyName() { - return "ES6"; - } - - @Override - public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor problemDescriptor) { - - - final PsiDocumentManager psiManager = PsiDocumentManager.getInstance(project); - Document document = psiManager.getDocument(problemDescriptor.getPsiElement().getContainingFile()); - - psiElement.toString(); - - String text = document.getText(); - text = text.replaceAll("(^|\\s)ts\\.test\\.MyFile\\.", "MyFile."); - text = text.replaceAll("(^|\\s)ts\\.test\\.MyFile\\s", "MyFile "); - document.setText(text); - - if (false) { - new JSConvertToClassProcessor(project, EmptyRunnable.getInstance(), null).generateTheWholeTree(); - } - } - }); - } - } - } -} diff --git a/src/de/veihelmann/closureplugin/MissingOrObsoleteGoogRequiresInspection.java b/src/de/veihelmann/closureplugin/MissingOrObsoleteGoogRequiresInspection.java index 005859f..21beb54 100644 --- a/src/de/veihelmann/closureplugin/MissingOrObsoleteGoogRequiresInspection.java +++ b/src/de/veihelmann/closureplugin/MissingOrObsoleteGoogRequiresInspection.java @@ -7,7 +7,8 @@ import com.intellij.psi.PsiElementVisitor; import com.intellij.psi.PsiFile; import de.veihelmann.closureplugin.fixes.MissingGoogRequireFix; -import de.veihelmann.closureplugin.fixes.ObsoleteRequireFix; +import de.veihelmann.closureplugin.fixes.ObsoleteRequireOrProvideFix; +import de.veihelmann.closureplugin.utils.ListMap; import org.jetbrains.annotations.NotNull; import java.util.List; @@ -64,6 +65,9 @@ public void visitFile(PsiFile file) { markMissingRequires(extractor); markObsoleteRequires(extractor); + + markDuplicationProblem(extractor.getDuplicateGoogRequires(), "Duplicate goog.require"); + markDuplicationProblem(extractor.getDuplicateGoogProvides(), "Duplicate goog.provide"); } private void markObsoleteRequires(ClosureDependenciesExtractor extractor) { @@ -78,7 +82,7 @@ private void markObsoleteRequires(ClosureDependenciesExtractor extractor) { continue; } PsiElement requireElement = declaredDependency.getValue(); - ObsoleteRequireFix fix = new ObsoleteRequireFix(requireElement); + ObsoleteRequireOrProvideFix fix = new ObsoleteRequireOrProvideFix(requireElement); problemsHolder.registerProblem(requireElement, "Obsolete require: " + declaredDependency.getKey(), fix); } } @@ -105,7 +109,12 @@ private boolean namespaceIsPrefixOfProvidedNamespace(Set providedNamespa return providedNamespaces.stream().anyMatch(providedNamespace -> providedNamespace.startsWith(namespace)); } - } + private void markDuplicationProblem(ListMap duplicateElements, String message) { + duplicateElements.keys().forEach(namespace -> { + duplicateElements.getNullSafe(namespace).forEach(element -> problemsHolder.registerProblem(element, message, new ObsoleteRequireOrProvideFix(element))); + }); + } + } } diff --git a/src/de/veihelmann/closureplugin/UseOfBracketNotationInspection.java b/src/de/veihelmann/closureplugin/UseOfBracketNotationInspection.java new file mode 100644 index 0000000..8c82dc5 --- /dev/null +++ b/src/de/veihelmann/closureplugin/UseOfBracketNotationInspection.java @@ -0,0 +1,62 @@ +package de.veihelmann.closureplugin; + +import com.intellij.codeInsight.daemon.GroupNames; +import com.intellij.codeInspection.LocalInspectionTool; +import com.intellij.codeInspection.ProblemsHolder; +import com.intellij.lang.javascript.psi.JSIndexedPropertyAccessExpression; +import com.intellij.lang.javascript.psi.JSLiteralExpression; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiElementVisitor; +import de.veihelmann.closureplugin.fixes.BracketNotationFix; +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; + +/** + * Checks for usages of bracket notation (e.g. myVar['fieldName']), which cannot be type-checked by the Closure compiler. + * Quick fix is to use dot notation (myVar.fieldName) instead. + */ +public class UseOfBracketNotationInspection extends LocalInspectionTool { + + @NotNull + @Override + public String getShortName() { + return "UseOfBracketNotationInspection"; + } + + @NotNull + @Override + public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) { + return new PsiElementVisitor() { + @Override + public void visitElement(PsiElement element) { + super.visitElement(element); + + if (element instanceof JSIndexedPropertyAccessExpression) { + checkBracketNotation((JSIndexedPropertyAccessExpression) element, holder); + } + } + }; + } + + @NotNull + public String getDisplayName() { + return "Checks for uses of bracket notation"; + } + + @NotNull + public String getGroupDisplayName() { + return GroupNames.PROPERTIES_GROUP_NAME; + } + + public boolean isEnabledByDefault() { + return true; + } + + private void checkBracketNotation(JSIndexedPropertyAccessExpression accessElement, ProblemsHolder problemsHolder) { + JSLiteralExpression literal = (JSLiteralExpression) Arrays.stream(accessElement.getChildren()).filter(element -> element instanceof JSLiteralExpression).findFirst().orElse(null); + if (literal != null && literal.getText().matches("[\"']\\w+['\"]")) { + problemsHolder.registerProblem(accessElement, "Access of property " + literal.getText() + " cannot be type-checked (bracket notation)", new BracketNotationFix(literal)); + } + } +} \ No newline at end of file diff --git a/src/de/veihelmann/closureplugin/dependency_recognizers/GoogRequireOrProvideRecognizer.java b/src/de/veihelmann/closureplugin/dependency_recognizers/GoogRequireOrProvideRecognizer.java index 6c0de82..948ec1d 100644 --- a/src/de/veihelmann/closureplugin/dependency_recognizers/GoogRequireOrProvideRecognizer.java +++ b/src/de/veihelmann/closureplugin/dependency_recognizers/GoogRequireOrProvideRecognizer.java @@ -5,6 +5,7 @@ import com.intellij.lang.javascript.psi.JSReferenceExpression; import com.intellij.lang.javascript.psi.JSStatement; import com.intellij.psi.PsiElement; +import de.veihelmann.closureplugin.utils.ListMap; import org.jetbrains.annotations.NotNull; import java.util.Map; @@ -13,8 +14,12 @@ public class GoogRequireOrProvideRecognizer extends DependencyRecognizerBase googRequires; + public final ListMap duplicateGoogRequires = new ListMap<>(); + private final Map googProvides; + public final ListMap duplicateGoogProvides = new ListMap<>(); + public GoogRequireOrProvideRecognizer(Map googRequires, Map googProvides) { this.googRequires = googRequires; this.googProvides = googProvides; @@ -46,14 +51,26 @@ protected boolean doConsumeElement(JSCallExpression callElement) { } String targetNamespace = argumentList.getArguments()[0].getText().replaceAll("[\"']", ""); + collectGoogRequireOrProvide(callElement, isGoogRequire, targetNamespace); + return true; + + } + + private void collectGoogRequireOrProvide(JSCallExpression callElement, boolean isGoogRequire, String targetNamespace) { if (isGoogRequire) { - googRequires.put(targetNamespace, getParentStatement(callElement)); + if (googRequires.containsKey(targetNamespace)) { + duplicateGoogRequires.put(targetNamespace, getParentStatement(callElement)); + } else { + googRequires.put(targetNamespace, getParentStatement(callElement)); + } } else { // We checked for goog.provide above, so we are safe in the 'else' clause here. - googProvides.put(targetNamespace, getParentStatement(callElement)); + if (googProvides.containsKey(targetNamespace)) { + duplicateGoogProvides.put(targetNamespace, getParentStatement(callElement)); + } else { + googProvides.put(targetNamespace, getParentStatement(callElement)); + } } - return true; - } private @NotNull diff --git a/src/de/veihelmann/closureplugin/fixes/BracketNotationFix.java b/src/de/veihelmann/closureplugin/fixes/BracketNotationFix.java new file mode 100644 index 0000000..a4d5bca --- /dev/null +++ b/src/de/veihelmann/closureplugin/fixes/BracketNotationFix.java @@ -0,0 +1,56 @@ +package de.veihelmann.closureplugin.fixes; + +import com.intellij.codeInspection.LocalQuickFixOnPsiElement; +import com.intellij.lang.javascript.psi.JSLiteralExpression; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiDocumentManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; + +/** + * Fixes usages of bracket notation (e.g. myVar['field']) by inserting dot notation instead (myVar.field). + */ +public class BracketNotationFix extends LocalQuickFixOnPsiElement { + + public BracketNotationFix(@NotNull PsiElement bracketNotationElement) { + super(bracketNotationElement); + + if (!(bracketNotationElement instanceof JSLiteralExpression)) { + throw new AssertionError("Expected bracket notation element (JSLiteralExpression) as input"); + } + } + + @NotNull + @Override + public String getText() { + return "Change to " + getDotAccessForElement(); + } + + private String getDotAccessForElement() { + return "." + getStartElement().getText().substring(1, getStartElement().getText().length() - 1); + } + + @Override + public void invoke(@NotNull Project project, @NotNull PsiFile psiFile, @NotNull PsiElement bracketNotationElement, @NotNull PsiElement psiElement1) { + + Document document = PsiDocumentManager.getInstance(project).getDocument(bracketNotationElement.getContainingFile()); + if (document == null) { + return; + } + String documentText = document.getText(); + String newDocumentText = documentText.substring(0, bracketNotationElement.getTextRange().getStartOffset() - 1) + + getDotAccessForElement() + + documentText.substring(bracketNotationElement.getTextRange().getEndOffset() + 1); + document.setText(newDocumentText); + } + + @Nls + @NotNull + @Override + public String getFamilyName() { + return "Compile safety inspections"; + } +} \ No newline at end of file diff --git a/src/de/veihelmann/closureplugin/fixes/ObsoleteRequireFix.java b/src/de/veihelmann/closureplugin/fixes/ObsoleteRequireOrProvideFix.java similarity index 78% rename from src/de/veihelmann/closureplugin/fixes/ObsoleteRequireFix.java rename to src/de/veihelmann/closureplugin/fixes/ObsoleteRequireOrProvideFix.java index 6e8fb8b..9b89977 100644 --- a/src/de/veihelmann/closureplugin/fixes/ObsoleteRequireFix.java +++ b/src/de/veihelmann/closureplugin/fixes/ObsoleteRequireOrProvideFix.java @@ -9,10 +9,10 @@ /** * Fixes a superfluous goog.require by removing the corresponding PSI element. */ -public class ObsoleteRequireFix extends GoogRequireFixBase { +public class ObsoleteRequireOrProvideFix extends GoogRequireFixBase { - public ObsoleteRequireFix(@NotNull PsiElement requireElement) { - super(requireElement); + public ObsoleteRequireOrProvideFix(@NotNull PsiElement requireOrProvideElement) { + super(requireOrProvideElement); } @Override @@ -27,6 +27,6 @@ public void invoke(@NotNull Project project, @NotNull PsiFile psiFile, @NotNull @NotNull @Override public String getText() { - return "Remove goog.require"; + return "Remove statement"; } }