From 7c3a57244e0cb8bbfd2698f488234809745dc492 Mon Sep 17 00:00:00 2001 From: liach <7806504+liach@users.noreply.github.com> Date: Wed, 23 Dec 2020 11:23:44 -0600 Subject: [PATCH 01/43] Add type annotation support and mapping info in jd gen (#6) * Supports type annotations Signed-off-by: liach Minor stuff Guess receivers work Signed-off-by: liach Migrate to new entry triple Signed-off-by: liach Seems it works at least it handles test files' inner classes Stage Now annotations include their defaults in generated files. works good More tests. Seems javadoc tool is more broken than this project Signed-off-by: liach * Add a table for each element on obfuscation information * bump version Co-authored-by: liach --- build.gradle | 48 ++-- gradle/wrapper/gradle-wrapper.jar | Bin 55190 -> 59203 bytes gradle/wrapper/gradle-wrapper.properties | 5 +- gradlew | 53 +++-- gradlew.bat | 43 ++-- .../fabricmc/mappingpoet/ClassBuilder.java | 141 ++++++++--- .../fabricmc/mappingpoet/FieldBuilder.java | 156 +++++++++++-- .../java/net/fabricmc/mappingpoet/Main.java | 119 ++++++++-- .../fabricmc/mappingpoet/MappingsStore.java | 117 +++++++--- .../fabricmc/mappingpoet/MethodBuilder.java | 88 +++++-- .../fabricmc/mappingpoet/ModifierBuilder.java | 9 +- .../net/fabricmc/mappingpoet/Signatures.java | 36 +-- .../mappingpoet/jd/MappingTaglet.java | 125 ++++++++++ .../signature/AnnotationAwareDescriptors.java | 151 ++++++++++++ .../signature/AnnotationAwareSignatures.java | 50 ++++ .../mappingpoet/signature/ClassSignature.java | 35 +++ .../signature/ClassStaticContext.java | 37 +++ .../signature/MethodSignature.java | 36 +++ .../PoetClassMethodSignatureVisitor.java | 197 ++++++++++++++++ .../signature/PoetTypeSignatureWriter.java | 203 ++++++++++++++++ .../signature/TypeAnnotationBank.java | 72 ++++++ .../signature/TypeAnnotationMapping.java | 30 +++ .../signature/TypeAnnotationStorage.java | 218 ++++++++++++++++++ src/main/resources/copy_on_click.js | 19 ++ .../net/fabricmc/mappingpoet/BorkAnno.java | 29 +++ .../fabricmc/mappingpoet/SignaturesTest.java | 108 ++++++++- .../net/fabricmc/mappingpoet/TestAnno.java | 30 +++ .../net/fabricmc/mappingpoet/TestOuter.java | 73 +++++- src/test/resources/dummy.tiny | 5 + 29 files changed, 2031 insertions(+), 202 deletions(-) create mode 100644 src/main/java/net/fabricmc/mappingpoet/jd/MappingTaglet.java create mode 100644 src/main/java/net/fabricmc/mappingpoet/signature/AnnotationAwareDescriptors.java create mode 100644 src/main/java/net/fabricmc/mappingpoet/signature/AnnotationAwareSignatures.java create mode 100644 src/main/java/net/fabricmc/mappingpoet/signature/ClassSignature.java create mode 100644 src/main/java/net/fabricmc/mappingpoet/signature/ClassStaticContext.java create mode 100644 src/main/java/net/fabricmc/mappingpoet/signature/MethodSignature.java create mode 100644 src/main/java/net/fabricmc/mappingpoet/signature/PoetClassMethodSignatureVisitor.java create mode 100644 src/main/java/net/fabricmc/mappingpoet/signature/PoetTypeSignatureWriter.java create mode 100644 src/main/java/net/fabricmc/mappingpoet/signature/TypeAnnotationBank.java create mode 100644 src/main/java/net/fabricmc/mappingpoet/signature/TypeAnnotationMapping.java create mode 100644 src/main/java/net/fabricmc/mappingpoet/signature/TypeAnnotationStorage.java create mode 100644 src/main/resources/copy_on_click.js create mode 100644 src/test/java/net/fabricmc/mappingpoet/BorkAnno.java create mode 100644 src/test/java/net/fabricmc/mappingpoet/TestAnno.java create mode 100644 src/test/resources/dummy.tiny diff --git a/build.gradle b/build.gradle index c7f17ba..4a3beca 100644 --- a/build.gradle +++ b/build.gradle @@ -1,12 +1,12 @@ plugins { id 'java' + id 'java-library' id 'maven-publish' + id("org.cadixdev.licenser") version "0.5.0" } group 'net.fabricmc' -version '0.1.0' - -sourceCompatibility = 1.8 +version '0.2.0' def ENV = System.getenv() version = version + "+" + (ENV.BUILD_NUMBER ? ("build." + ENV.BUILD_NUMBER) : "local") @@ -15,38 +15,54 @@ repositories { mavenCentral() maven { name = 'Fabric' - url = 'http://maven.modmuss50.me/' + url = 'https://maven.modmuss50.me/' } } dependencies { - compile 'com.squareup:javapoet:1.12.1' - compile 'net.fabricmc:tiny-mappings-parser:0.2.2.14' + implementation 'com.squareup:javapoet:1.13.0' + implementation 'net.fabricmc:tiny-mappings-parser:0.3.0+build.17' runtimeOnly 'com.google.guava:guava:28.2-jre' - compile 'org.ow2.asm:asm:8.0' - compile 'org.ow2.asm:asm-analysis:8.0' - compile 'org.ow2.asm:asm-commons:8.0' - compile 'org.ow2.asm:asm-tree:8.0' - compile 'org.ow2.asm:asm-util:8.0' + implementation 'org.ow2.asm:asm:9.0' + implementation 'org.ow2.asm:asm-analysis:9.0' + implementation 'org.ow2.asm:asm-commons:9.0' + implementation 'org.ow2.asm:asm-tree:9.0' + implementation 'org.ow2.asm:asm-util:9.0' - testImplementation 'org.junit.jupiter:junit-jupiter-api:5.1.0' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.1.0' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0' +} + +java { + withSourcesJar() + toolchain { + languageVersion.set(JavaLanguageVersion.of(11)) + } } test { useJUnitPlatform() } +tasks.withType(Jar) { + from("LICENSE") { + rename { "${it}_${project.archivesBaseName}" } + } +} + jar { manifest { attributes 'Implementation-Title': 'MappingPoet', - 'Implementation-Version': version, + 'Implementation-Version': archiveVersion, 'Main-Class': "net.fabricmc.mappingpoet.Main" } } -apply from: 'https://github.com/FabricMC/fabric-docs/raw/master/gradle/license.gradle' +license { + header file("HEADER") + include '**/*.java' +} publishing { publications { @@ -67,4 +83,4 @@ publishing { } } } -} \ No newline at end of file +} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 87b738cbd051603d91cc39de6cb000dd98fe6b02..e708b1c023ec8b20f512888fe07c5bd3ff77bb8f 100644 GIT binary patch delta 26193 zcmZ6yQ+S|Vu&o>0wrv|7+qP{xU&pp>+fK)}ZKK1EI!T}Z?6uCtKF>3+>b7Q$8a3;k z=?&n+bKs5iponRd%jI35ARxHlARx>siR4%*il7((1uK)8y@{J!oa(gW@(&EbVLvhOxk#E0z~5*_n$Tfk4BT1W zh~4H^yI$w!jrIW$@8~{|r_Pqh9?;*1{Rs-h$o?FVSot<3yKX_cH33Wqgy&Ugow#-- zd$AFKpvAm7vspRndDP5Y*{X$rg0EvCe9(Ow>lBeyGY!V@xQpXomHjCWwMA-rDRPSv zY@gq7;|J=t%N|R7799odG(V`K@OXpjH2q11r=-spt+w zmng+yzxXW&2lk&G)N z-h)16N@V9eFCNeZrbSiuE44@1#kS@h5wqX)wgpxfDiThLBx=5wyP_q&uT8OO)g!i} z`ony65!)LBh`yjIhNFW{%5vZka3CNsFd!fxA|N)P3^l}%ARrX~g&6-g&ji4>8oCzF zKSH<7MutdMx~SkLQ5g_)<~Gen%{ZC`NJdbH)-9$<(ppE)OUsf4+q=3xf!CmpZ`c>g z4Ys!B49{{P<@lMuM@Gi9cVK3-W&h8s0rx+luP@f0C2um4An0s{!;rApVwtHdlxBE$ zQ}-fiEaWDdk_Z{*`eS})9~03LOH#dsT^&c)G^Img%Th&3)4?O4Wq0Y&WfVC|VC zaAQwCL*mCoU593J>8NRWao@R|t#I*_etEAkj;Pnx3Px?Zvdq$zVwkChuPxdoUTJ_f z91pe6B-4rYiTj&D4-yF14*5BofspUDM3g|`#ZB$#P?p~-U9+h+Tp`mRxh*=&=&T*z2q>oXsGC%dWpshF`TNHT@_F>BTVa9G zFHYaGE;{c#SSHF=YdV#s&=@2HPVty?i1KRKnHMZOfiniPe%}^B8HFW z*bJMvi!j9I(^KSPI$-KTx8V>{A^SDH?XXHk2r zl3KMvKg}3t6q5GEn_a9c#&WLtG*Z+HlGMW<(x+DV$pO_9MbEmMd(|gjX$n1RcRRtv zDT~=Ns?nTUr{?a8bL%J`yhpBI_HJ=#J82CYL&{%*ODAh3aQ7C!&9@kuw2vTv^C5Jv zw{IBtth8_1lePLj%=eb2<|{r*Tr*eZc-3zAmND82-Y2(LCRJAYureb+>#gbkwS;}t z*dnlaO#wXPiqx378QPITyhU~VJF;i9bY&O>9`a<{Z=?tck-b5V=Ao(5iSinj^|JG0 z^Mei%8;vfT5yjl03`{X#`7o70WDu59Odv`qB&Kd4C_bQnCkPF-Z;JgZ^g{2~-?;k+ z9+d0E@fT(gQ5tY0OC?v8n)9lJ>xx!1rO|MACzpKq&HkF1K{ zFMRybn|7SN@1S0)$Tgnp%zhGmU0>jDj(qPx9cd6`;(p;9lq7up`hoX{FkphHyA0DN z5*0_8Cr`bKX4N+FM+NK)D;S+PQe|0pN`4GS%9VQJ!F@1AmvLj;s* z?5g2wVEo&)=YpSxQkAAjZU5QM2_ajp*;-oX5M*sllctPP$Cq)!W#4miWC{L-|8byZ z^iiy&Xyktx3$vQ_qG0ub{r0Drov-9Lg!p(omOcL5a7e1+=Q3+nuHS2}-`t&-(97AN zF!4V4J;ELv>Nxx#>p@srsIrMn3PoV;Fg0q~y9pFFHz~V?YR;q*bQp&>(1D%FPs zC*IM^c|*^YFd>8K!*CNjO?IyyVo0Oj58J=V+HZAg4EGQ_44PdzlAt7maXilOhlg5a01 zY;8K$cR z`?@05v}ykdXcpLFzwCu_^1Ix5oA^_#4P!q~iRGZaX}VfO>ocM-TIR_OVK|WIk=>*a zeNESLpfO2pCzrnXhvy4zVJJ|)bs@SBYiq&LgqV+kKtj0biu*n~3>Ls(AQ(f9*~_s) zl-KPHr3GJJdZbJ9z~4gno4QuCR6$+sXgnW-SR$UwdY>J(?y@VzOw-!z29BZMAa@*>cOMvu0j;NRm&a zA?dwChkQuKL|!${FHs;*>8zcvo{*&C&2uo)%+*>dx4mwK>fGN+2G`s+E+?FoDMB>o zeEk&R)YUb-)hB0btx0ZnL88NiU<4a4`*dXC&pJay_*!BvzV5L3egZfJ^3pQHC8zFj z6=tLQ9h+!XzlAle1MVUJR85LGy?b&&${lv)c!u?eR_HV5VGs~FMZC*XTEE>nWMNC4 zB-UE7S$o)*022^2SpSi8XR351W?e8S@6i^nRhZK21FxbQo=r|Xn3;a2gqkA9jC)ti z1U4zFR*N)5@{VZmvX8drmAd;H`V9VYPp)`CJ<24J3+oWFOOh|D+JrBTtRrT-UNiS+ z(J%rlp)E0cuK~b2h31^v%*?vFF%$`yaX*844h@8tiqzpL`V|45>?UdyCevybaaT+l zdZ{j2LANKlT=)%J%zpa;hj+KHasV#AP+j%_aV7mNFYy(I_e39m$ld%;hB{CR3NVHM zs?_7ryClg9%EdjJGu)cCVf%af}^xD1`=ey;xTSwvKswhL}f-h0rN zx$a-|8ICEr+~Tj|Q4jJ&D%Al!W{4)^8UYCecR(m4n1Xox7yTqZ!IweY}ynJI3 zMz}L%pqst|R9anw=H*@%l{5QYAlsH-?qK4IOT|U_%?X}+&3)yyoEsv22Yx~r!!S#D zFHjffGZQ^)k^dxFhZ09Hl^#$)1$%|>4LpawxEh+VJLRz_6n%#;LPdOiZ?-?QopPOR@$pf0U=M zotnQ+LX;pV(2mBcz5(Tq6mtI6^{nnb0ZCeqdc2jimiO)`7S5L5d*s~AL(wwRx^y_) zh#GRJ6CxyPN*6Zaw(!3)H6nkpJ5EKdx44c~YYcFRRlLrSK}q>QJLrKU+@6Erj&$a; zqseNY2DlS-f#nv2LUG7?M@oSa$z=|r!z!Vove26#Jt4%MY5?-5EAFbS6yguDs?gCE z(vc>HKlF#duyAd`Ef7JyP%dBGd}$B5LM>{YZJ8-rOT-4~#18)T(~5~bG7eBFL@D*sXp~E2b)#Kj-6#_;rKFTcZ5;~q>XBa%9qtn zh|*NK&npj)_X0e@`Q)Duq;*G(ix)9}{FJ(tBr%|Zl{%`3vm<3;ZTao!@JCy!w$Hd$ zeTsHc-QO?{AjJ$$xyVeeiaa(mIS{g>H~RWDd^7NrcuhG+n6;;IOM;Pnv9AXK%*F>l zh;aH=_~cR-sWJe&{k3#sLEJ9Q;xpFrzQ!1IA($)K6A(HHJ78{YNzs2fS9t(^@rq2; z%#zYDCmxz&BIxr`?~%}btlSLY*nUOqSIu}@IIZ6m+uae;rw{n@(ccR5i+I!DYr1e1 za(MOzHzGaa-+2Qi4lE{yhB?MQdUJSqM$cf$?F?6pb~QsYC}kb`SX9W4V`o%%*{zQJ z64`;gk{^o`6(Of^2y<*)?pbt(p*cCs&QLrs354H|(M+Bl84yFLM>{4$a^t<&uOd2( zDhK}WqM`tq3_L~#0nsJ_0U`b0qJjbbXWp&Th4scC_XtdYXp(dG5kaH82(=)@Kwe1p zNKUs;DyER`6;Dj1)k)SGNDhTGJscIq$m5B>ort=n@wBIQ$t`!x`S0)~<-(*&Y|AE0 z)a`OzqP|LRKT9XHDk!b@B{%*6j6c1Qx`5psOT1Mo>jGwg; zn#*@S7dQbm1brRiPk)Qw!Na~6#2i1!S>M_ZKFrd-N5lZxeU;03j1M7M?Pf4N8dDV?~ChR zl~dm^ZdlcjsW>`r+GpIb96^EutTZQ7HZJ;Ji9;!9fm+SDzseGRa8}V!>`vLfEA5< z^)ZQgMs(z0cl=&{{#-n$H4i7s&F>pR0-jaEn=80*K7h4_Idl}?F4O-j&+iq}!q|0u zW>KXn0n?zIbBoRPGAVPB&EzsF)TGUQQbxPlc&8)*U!LeW9DyE}^H`oU%IDjfiRxVP zcZm6`!=m@f-tdayub+@lecT1jHj$I7CX&YH9$FlZ&!uBZ_-j7{`7B}n<(LR^mFlUm zdPXw&F#ypd4Z0KNnbu6!n+YwuuibHJChS6JgbF%iJ2%OW%yroEX{36{1($2+bB-&K zC0J1^1xfhaH|c}lg(Z}>?KcTy2vs7B`wT%jT2_Co)Dt-(~ z$*7abZzyD0vyDjXlMsm7MuDfEld>A6c;^VEn_#?$SSettv}`*0^ICen24YL)KM7sp>Adr36Z)i zLZ)C~O4l-Gf7j-`wbz!yKgf7>5oT>A5&2stuDEVk(Mb*S$E|S5S*`6RXM&8_DcsVv zCK2jHYi|StkgaGR5AN&9NqFZaeIZ_hgv4iEeNG!)WAE2;tZty`kUh#rx0T{i<$L(pl}iOmk&Jn&`s#jtF66@s#y-I zrs`Ym7<%r)TW;h`wil?x%EZp6y^@4kv#)JSw#ajW_F1RVu}r@b$DP>2UqH&8hkfa) zgPn~tP`HoQzMD8L-$()v073u!X)Q$4`&f7(NRb`EPA>$p&-63+XPOTAUl+O`CVMBv zUrQ*z96r#y(>OjwsSPUDv!=|yZT$0zP51zJCqSw3{3pOd>*?-nTsY6nx@rVd9r#ph z^8SY>H;-e8C;6+TlQz|S9$*y4dPkmczn4KLYdPZkMB5YQKCyx1k zJU4XSsE4Vem=3%L+>&Z1KHvXd;|(^h;3Q!f2m$|_<7NAaA#5;^0T^^w!jQ4QL;le} z*zsm?=EF;Xc)4tMRH8y4kh-rGShhn)F}9Mo8($sHHs?z!aFY1UepV8{ZGt?)QusJ7 zzf~$ngGIL`3tXTAjsF%C+r97MR_g|>aA)^c*OI<*yVs|9XU79XL4qJI26Uk7Ijv3x zoINaggyd9a%t_q%0Ph8Ql54a^ty-n_TBVQcb?WVteFYzbIN`|xuv|=$?1TOt2d7n0 zl5X7BBE4qHiyuUa#im|F_P^ddNQq;Qd~V)7b~RAGgIK3?C-mhqFa+JRkpBJJtsb?Y z62_+%!ETHm0%1mb%*fmFd z-(YSD22!E5B|nk@2o@GOO91cOjR9JiitxXy-!;sEW|(do8;%0P&eP`;44pK7O*MhX zdlfBHfc!vIi~q{+{~Yhf~URiRcY@Pkc?o3SCkQQg}E+y{>J{{cN^5EY^KdbZj0eL(u#c~39>G3r3`=a|y(g9VG ze}!4C?0rHYoy*G-LX{VUGPp;XC>s6yOH$*fi2M)v$zDQ~Z-5?Et!K&4XKhzSA@f~# z2D4gmA=DNBUoxh8%ui`)gXJ{mzO;`Ka7Yro`3THr#>S{ih`Fm&Af_p<$IpA2`> zcde1;fXK1=Y%7#s1`@e0{)Ze>eOIs%ZAx25fAtKS2&3m==&$*)WJQuNTkc$bqb}pE z-|}i=Zhj)B^u#$9ue!%(%F|I3Z>Ea=V?a$?fMBd} ze1q9wcHuXQpXD!fBk-UaRsr3cun@5r2vH(J2asdupCZQXtO!W>%S8LAv!xe0kfu2n zjW5_uuq+)vtGwrR=+l{QqF2kBE78!W(J}GR<%hyOSa^#KW2A9#7?v-EpG}|G-ghyn z=?rspMd0U@OLxiB;Y?ZmX`qtu$BtOjBlV)!Sme@`-#+XmY|ZzS&1tu!IJe(QY_SR1 z0UV=l1SuTQ1Woeb)q8dM)^=&@D0MIY=odw=R}Ix1`s7uYSGi_ZR9?Ypz~{)8DQKuF z;;$|^>WXy8;kVBCj)zk}goNWAo+T`+Eu^`)Rq5;Orj}=OtP(k(_`S?Ia*=lu&i(!Y z6ky!UGfXJmharkF3Z=N zw|spi95hC)Z#|XXFr~?^gLGr^%K#mG*CRRdI!@8olzM+?;<` zmMBkcY<*15Y~<5?on)3RjW#`011xN|mi+U4bC%t&;oTcGP~j?Uw(l_ls= z>}ftPt(>WqU$ooRt&WD#h(kUpTahm$0)a5J z-Z=WZ(i=h)mcpDWFgE-@IdH`}B3S$|R`_jjI00_L3YJ|7a(6Hf0Ikg*&c>H}i8a<* z^1^4vKTOgld+Y*{4;&xunXo&fUk)n(nZ7>(A~0v{k}!HW8=|4a&j(!xARx)

$|c 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∨fd|u2@Kuk2 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 F_djzcFxCJ7 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 2db7c08..4d9ca16 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Sun Apr 05 23:36:17 BST 2020 -distributionUrl=https\://services.gradle.org/distributions/gradle-5.2.1-all.zip distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index af6708f..4f906e0 100644 --- a/gradlew +++ b/gradlew @@ -1,5 +1,21 @@ #!/usr/bin/env sh +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + ############################################################################## ## ## Gradle start up script for UN*X @@ -28,7 +44,7 @@ APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m"' +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" @@ -66,6 +82,7 @@ esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then @@ -109,10 +126,11 @@ if $darwin; then GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" fi -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath @@ -138,19 +156,19 @@ if $cygwin ; then else eval `echo args$i`="\"$arg\"" fi - i=$((i+1)) + i=`expr $i + 1` done case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; esac fi @@ -159,14 +177,9 @@ save () { for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done echo " " } -APP_ARGS=$(save "$@") +APP_ARGS=`save "$@"` # Collect all arguments for the java command, following the shell quoting and substitution rules eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" -fi - exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index 6d57edc..107acd3 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,3 +1,19 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + @if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @@ -13,15 +29,18 @@ if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if "%ERRORLEVEL%" == "0" goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -35,7 +54,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -45,28 +64,14 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell diff --git a/src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java b/src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java index 3dbf661..a4c13ff 100644 --- a/src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java +++ b/src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java @@ -16,21 +16,33 @@ package net.fabricmc.mappingpoet; +import static net.fabricmc.mappingpoet.FieldBuilder.parseAnnotation; + import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.function.Function; +import com.squareup.javapoet.AnnotationSpec; import com.squareup.javapoet.ClassName; import com.squareup.javapoet.TypeSpec; +import com.squareup.javapoet.TypeVariableName; import org.objectweb.asm.Opcodes; +import org.objectweb.asm.TypeReference; import org.objectweb.asm.tree.AnnotationNode; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.FieldNode; import org.objectweb.asm.tree.InnerClassNode; import org.objectweb.asm.tree.MethodNode; +import net.fabricmc.mappingpoet.signature.AnnotationAwareDescriptors; +import net.fabricmc.mappingpoet.signature.AnnotationAwareSignatures; +import net.fabricmc.mappingpoet.signature.ClassSignature; +import net.fabricmc.mappingpoet.signature.ClassStaticContext; +import net.fabricmc.mappingpoet.signature.TypeAnnotationMapping; +import net.fabricmc.mappingpoet.signature.TypeAnnotationStorage; + public class ClassBuilder { private final MappingsStore mappings; @@ -39,26 +51,31 @@ public class ClassBuilder { private final TypeSpec.Builder builder; private final List innerClasses = new ArrayList<>(); private final Function> superGetter; + private final ClassStaticContext context; - private Signatures.ClassSignature signature; + private final ClassSignature signature; // not really signature + private final TypeAnnotationMapping typeAnnotations; + private boolean annotationClass; private boolean enumClass; private boolean instanceInner = false; + // only nonnull if any class in the inner class chain creates a generic decl + // omits L and ; + private String receiverSignature; - public ClassBuilder(MappingsStore mappings, ClassNode classNode, Function> superGetter) { + public ClassBuilder(MappingsStore mappings, ClassNode classNode, Function> superGetter, ClassStaticContext context) { this.mappings = mappings; this.classNode = classNode; this.superGetter = superGetter; + this.context = context; + this.typeAnnotations = setupAnnotations(); + this.signature = setupSignature(); this.builder = setupBuilder(); + addInterfaces(); - addDirectAnnotations(); + addAnnotations(); addJavaDoc(); } - public void addMembers() { - addMethods(); - addFields(); - } - public static ClassName parseInternalName(String internalName) { int classNameSeparator = -1; int index = 0; @@ -96,23 +113,52 @@ public static ClassName parseInternalName(String internalName) { return currentClassName; } + private TypeAnnotationMapping setupAnnotations() { + return TypeAnnotationStorage.builder() + .add(classNode.invisibleTypeAnnotations) + .add(classNode.visibleTypeAnnotations) + .build(); + } + + public void addMembers() { + addMethods(); + addFields(); + } + + private ClassSignature setupSignature() { + return classNode.signature == null ? + AnnotationAwareDescriptors.parse(classNode.superName, classNode.interfaces, typeAnnotations, context) : + AnnotationAwareSignatures.parseClassSignature(classNode.signature, typeAnnotations, context); + } + private TypeSpec.Builder setupBuilder() { - if (classNode.signature != null) { - signature = Signatures.parseClassSignature(classNode.signature); - } TypeSpec.Builder builder; + ClassName name = parseInternalName(classNode.name); // no type anno here if (Modifier.isInterface(classNode.access)) { - builder = TypeSpec.interfaceBuilder(parseInternalName(classNode.name)); + if (classNode.interfaces.size() == 1 && classNode.interfaces.get(0).equals("java/lang/annotation/Annotation")) { + builder = TypeSpec.annotationBuilder(name); + this.annotationClass = true; + } else { + builder = TypeSpec.interfaceBuilder(name); + } } else if (classNode.superName.equals("java/lang/Enum")) { enumClass = true; - builder = TypeSpec.enumBuilder(parseInternalName(classNode.name)); + builder = TypeSpec.enumBuilder(name); } else { - builder = TypeSpec.classBuilder(parseInternalName(classNode.name)) - .superclass(signature == null ? parseInternalName(classNode.superName) : signature.superclass); + builder = TypeSpec.classBuilder(name) + .superclass(signature.superclass); } - if (signature != null && signature.generics != null) { + if (!signature.generics.isEmpty()) { builder.addTypeVariables(signature.generics); + StringBuilder sb = new StringBuilder(); + sb.append(classNode.name); + sb.append("<"); + for (TypeVariableName each : signature.generics) { + sb.append("T").append(each.name).append(";"); + } + sb.append(">"); + receiverSignature = sb.toString(); } return builder @@ -120,18 +166,22 @@ private TypeSpec.Builder setupBuilder() { } private void addInterfaces() { + if (annotationClass) { + return; + } if (signature != null) { builder.addSuperinterfaces(signature.superinterfaces); return; } - if (classNode.interfaces == null) return; + if (classNode.interfaces.isEmpty()) return; for (String iFace : classNode.interfaces) { builder.addSuperinterface(parseInternalName(iFace)); } } - private void addDirectAnnotations() { + private void addAnnotations() { + // type anno already done through class sig addDirectAnnotations(classNode.invisibleAnnotations); addDirectAnnotations(classNode.visibleAnnotations); } @@ -141,7 +191,7 @@ private void addDirectAnnotations(List regularAnnotations) { return; } for (AnnotationNode annotation : regularAnnotations) { - builder.addAnnotation(FieldBuilder.parseAnnotation(annotation)); + builder.addAnnotation(parseAnnotation(annotation)); } } @@ -172,7 +222,7 @@ private void addMethods() { formalParamStartIndex = 1; // 0 this$0 } } - builder.addMethod(new MethodBuilder(mappings, classNode, method, superGetter, formalParamStartIndex).build()); + builder.addMethod(new MethodBuilder(mappings, classNode, method, superGetter, context, receiverSignature, formalParamStartIndex).build()); } } @@ -183,22 +233,42 @@ private void addFields() { continue; // hide synthetic stuff } if ((field.access & Opcodes.ACC_ENUM) == 0) { - builder.addField(new FieldBuilder(mappings, classNode, field).build()); + builder.addField(new FieldBuilder(mappings, classNode, field, context).build()); } else { TypeSpec.Builder enumBuilder = TypeSpec.anonymousClassBuilder(""); + // jd FieldBuilder.addFieldJavaDoc(enumBuilder, mappings, classNode, field); + + // annotations + addDirectAnnotations(enumBuilder, field.invisibleAnnotations); + addDirectAnnotations(enumBuilder, field.visibleAnnotations); + List annotations = TypeAnnotationStorage.builder() + .add(field.invisibleTypeAnnotations) + .add(field.visibleTypeAnnotations) + .build().getBank(TypeReference.newTypeReference(TypeReference.FIELD)) + .getCurrentAnnotations(); + if (!annotations.isEmpty()) { + enumBuilder.addAnnotations(annotations); // no custom paths for annotations rip + } + builder.addEnumConstant(field.name, enumBuilder.build()); } } } - private void addJavaDoc() { - String javadoc = mappings.getClassDoc(classNode.name); - if (javadoc != null) { - builder.addJavadoc(javadoc); + private void addDirectAnnotations(TypeSpec.Builder builder, List regularAnnotations) { + if (regularAnnotations == null) { + return; + } + for (AnnotationNode annotation : regularAnnotations) { + builder.addAnnotation(parseAnnotation(annotation)); } } + private void addJavaDoc() { + mappings.addClassDoc(builder::addJavadoc, classNode.name); + } + public void addInnerClass(ClassBuilder classBuilder) { InnerClassNode innerClassNode = null; if (classNode.innerClasses != null) { @@ -215,7 +285,26 @@ public void addInnerClass(ClassBuilder classBuilder) { classBuilder.builder.addModifiers(javax.lang.model.element.Modifier.STATIC); } else { classBuilder.builder.addModifiers(new ModifierBuilder(innerClassNode.access).getModifiers(classBuilder.enumClass ? ModifierBuilder.Type.ENUM : ModifierBuilder.Type.CLASS)); - if (!Modifier.isStatic(innerClassNode.access)) classBuilder.instanceInner = true; + if (!Modifier.isStatic(innerClassNode.access)) { + classBuilder.instanceInner = true; + } + // consider emit warning if this.instanceInner is true when classBuilder.instanceInner is false + + if (this.receiverSignature != null && classBuilder.instanceInner) { + StringBuilder sb = new StringBuilder(); + sb.append(this.receiverSignature).append("."); // like O. for O + sb.append(innerClassNode.innerName); // append simple name + + List innerClassGenerics = classBuilder.signature.generics; + if (!innerClassGenerics.isEmpty()) { + sb.append("<"); + for (TypeVariableName each : innerClassGenerics) { + sb.append("T").append(each.name).append(";"); + } + sb.append(">"); + } + classBuilder.receiverSignature = sb.toString(); + } } innerClasses.add(classBuilder); } diff --git a/src/main/java/net/fabricmc/mappingpoet/FieldBuilder.java b/src/main/java/net/fabricmc/mappingpoet/FieldBuilder.java index a5596ab..3488138 100644 --- a/src/main/java/net/fabricmc/mappingpoet/FieldBuilder.java +++ b/src/main/java/net/fabricmc/mappingpoet/FieldBuilder.java @@ -17,6 +17,8 @@ package net.fabricmc.mappingpoet; import java.util.AbstractMap; +import java.util.ArrayDeque; +import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -30,32 +32,44 @@ import com.squareup.javapoet.TypeSpec; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; +import org.objectweb.asm.TypePath; +import org.objectweb.asm.TypeReference; import org.objectweb.asm.tree.AnnotationNode; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.FieldNode; -import net.fabricmc.mappings.EntryTriple; +import net.fabricmc.mapping.util.EntryTriple; +import net.fabricmc.mappingpoet.signature.AnnotationAwareDescriptors; +import net.fabricmc.mappingpoet.signature.AnnotationAwareSignatures; +import net.fabricmc.mappingpoet.signature.ClassStaticContext; +import net.fabricmc.mappingpoet.signature.TypeAnnotationBank; +import net.fabricmc.mappingpoet.signature.TypeAnnotationMapping; +import net.fabricmc.mappingpoet.signature.TypeAnnotationStorage; public class FieldBuilder { private final MappingsStore mappings; private final ClassNode classNode; private final FieldNode fieldNode; private final FieldSpec.Builder builder; + private final TypeAnnotationMapping annotations; + private final ClassStaticContext context; - public FieldBuilder(MappingsStore mappings, ClassNode classNode, FieldNode fieldNode) { + public FieldBuilder(MappingsStore mappings, ClassNode classNode, FieldNode fieldNode, ClassStaticContext context) { this.mappings = mappings; this.classNode = classNode; this.fieldNode = fieldNode; + this.context = context; + this.annotations = TypeAnnotationStorage.builder() + .add(fieldNode.invisibleTypeAnnotations) + .add(fieldNode.visibleTypeAnnotations) + .build(); this.builder = createBuilder(); addDirectAnnotations(); addJavaDoc(); } static void addFieldJavaDoc(TypeSpec.Builder enumBuilder, MappingsStore mappings, ClassNode classNode, FieldNode fieldNode) { - String javaDoc = mappings.getFieldDoc(new EntryTriple(classNode.name, fieldNode.name, fieldNode.desc)); - if (javaDoc != null) { - enumBuilder.addJavadoc(javaDoc); - } + mappings.addFieldDoc(enumBuilder::addJavadoc, new EntryTriple(classNode.name, fieldNode.name, fieldNode.desc)); } public static AnnotationSpec parseAnnotation(AnnotationNode annotation) { @@ -75,7 +89,7 @@ public static AnnotationSpec parseAnnotation(AnnotationNode annotation) { return builder.build(); } - private static CodeBlock codeFromAnnoValue(Object value) { + public static CodeBlock codeFromAnnoValue(Object value) { // BCDFIJSZ; String; String[] (for enum); asm type; anno node; list of any prev stuff (cannot nest) if (value instanceof List) { return ((List) value).stream().map(FieldBuilder::codeFromAnnoValue).collect(CodeBlock.joining(",", "{", "}")); @@ -208,6 +222,125 @@ public static Map.Entry parseType(final String desc, final in return new AbstractMap.SimpleImmutableEntry<>(index, current); } + public static Map.Entry parseAnnotatedType(final String desc, final int start, TypeAnnotationBank annotations, ClassStaticContext context) { + int index = start; + Deque> arrayAnnos = new ArrayDeque<>(); + while (desc.charAt(index) == '[') { + arrayAnnos.push(annotations.getCurrentAnnotations()); + annotations = annotations.advance(TypePath.ARRAY_ELEMENT, 0); + index++; + } + + TypeName current; + switch (desc.charAt(index)) { + case 'B': { + current = TypeName.BYTE; + index++; + break; + } + case 'C': { + current = TypeName.CHAR; + index++; + break; + } + case 'D': { + current = TypeName.DOUBLE; + index++; + break; + } + case 'F': { + current = TypeName.FLOAT; + index++; + break; + } + case 'I': { + current = TypeName.INT; + index++; + break; + } + case 'J': { + current = TypeName.LONG; + index++; + break; + } + case 'S': { + current = TypeName.SHORT; + index++; + break; + } + case 'Z': { + current = TypeName.BOOLEAN; + index++; + break; + } + case 'V': { + current = TypeName.VOID; + index++; + break; + } + case 'L': { + int classNameSeparator = index; + index++; + int nameStart = index; + ClassName currentClassName = null; + boolean instanceInner = false; + + char ch; + do { + ch = desc.charAt(index); + + if (ch == '$' || ch == ';') { + // collect class name + if (currentClassName == null) { + String packageName = nameStart < classNameSeparator ? desc.substring(nameStart, classNameSeparator).replace('/', '.') : ""; + String simpleName = desc.substring(classNameSeparator + 1, index); + currentClassName = ClassName.get(packageName, simpleName); + } else { + String simpleName = desc.substring(classNameSeparator + 1, index); + + if (!instanceInner && context.isInstanceInner(desc.substring(nameStart, index))) { + instanceInner = true; + } + + currentClassName = currentClassName.nestedClass(simpleName); + + if (instanceInner) { + currentClassName = AnnotationAwareDescriptors.annotate(currentClassName, annotations); + annotations = annotations.advance(TypePath.INNER_TYPE, 0); + } + } + } + + if (ch == '/' || ch == '$') { + // Start of simple name + classNameSeparator = index; + } + + index++; + } while (ch != ';'); + + if (currentClassName == null) { + throw invalidDesc(desc, index); + } + + current = currentClassName; + break; + } + default: + throw invalidDesc(desc, index); + } + + while (!arrayAnnos.isEmpty()) { + current = ArrayTypeName.of(current); + List currentAnnos = arrayAnnos.pop(); + if (!currentAnnos.isEmpty()) { + current = current.annotated(currentAnnos); + } + } + + return new AbstractMap.SimpleImmutableEntry<>(index, current); + } + private static IllegalArgumentException invalidDesc(String desc, int index) { return new IllegalArgumentException(String.format("Invalid descriptor at index %d for \"%s\"", index, desc)); } @@ -285,10 +418,7 @@ private CodeBlock makeInitializer(String desc) { } private void addJavaDoc() { - String javaDoc = mappings.getFieldDoc(new EntryTriple(classNode.name, fieldNode.name, fieldNode.desc)); - if (javaDoc != null) { - builder.addJavadoc(javaDoc); - } + mappings.addFieldDoc(builder::addJavadoc, new EntryTriple(classNode.name, fieldNode.name, fieldNode.desc)); } private void addDirectAnnotations() { @@ -307,9 +437,9 @@ private void addDirectAnnotations(List regularAnnotations) { private TypeName calculateType() { if (fieldNode.signature != null) { - return Signatures.parseFieldSignature(fieldNode.signature); + return AnnotationAwareSignatures.parseFieldSignature(fieldNode.signature, annotations, context); } - return typeFromDesc(fieldNode.desc); + return parseAnnotatedType(fieldNode.desc, 0, annotations.getBank(TypeReference.newTypeReference(TypeReference.FIELD)), context).getValue(); } public FieldSpec build() { diff --git a/src/main/java/net/fabricmc/mappingpoet/Main.java b/src/main/java/net/fabricmc/mappingpoet/Main.java index 98d6f69..1935428 100644 --- a/src/main/java/net/fabricmc/mappingpoet/Main.java +++ b/src/main/java/net/fabricmc/mappingpoet/Main.java @@ -19,9 +19,14 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.io.UncheckedIOException; +import java.lang.reflect.Modifier; +import java.nio.file.FileVisitResult; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -30,26 +35,31 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.function.BiConsumer; +import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; import java.util.jar.JarEntry; import java.util.jar.JarFile; import com.squareup.javapoet.JavaFile; -import com.squareup.javapoet.TypeSpec; import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.InnerClassNode; + +import net.fabricmc.mappingpoet.signature.ClassStaticContext; public class Main { public static void main(String[] args) { - if (args.length != 3) { - System.out.println(" "); + if (args.length != 3 && args.length != 4) { + System.out.println(" []"); return; } Path mappings = Paths.get(args[0]); Path inputJar = Paths.get(args[1]); Path outputDirectory = Paths.get(args[2]); + Path librariesDir = args.length < 4 ? null : Paths.get(args[3]); try { if (Files.exists(outputDirectory)) { @@ -74,13 +84,13 @@ public static void main(String[] args) { return; } - generate(mappings, inputJar, outputDirectory); + generate(mappings, inputJar, outputDirectory, librariesDir); } - public static void generate(Path mappings, Path inputJar, Path outputDirectory) { + public static void generate(Path mappings, Path inputJar, Path outputDirectory, Path librariesDir) { final MappingsStore mapping = new MappingsStore(mappings); Map classes = new HashMap<>(); - forEachClass(inputJar, (superGetter, classNode) -> writeClass(mapping, classNode, classes, superGetter)); + forEachClass(inputJar, (superGetter, classNode, context) -> writeClass(mapping, classNode, classes, superGetter, context), librariesDir); classes.values().stream() .filter(classBuilder -> !classBuilder.getClassName().contains("$")) @@ -97,9 +107,16 @@ public static void generate(Path mappings, Path inputJar, Path outputDirectory) } - private static void forEachClass(Path jar, BiConsumer>, ClassNode> classNodeConsumer) { + private static void forEachClass(Path jar, ClassNodeConsumer classNodeConsumer, Path librariesDir) { List classes = new ArrayList<>(); Map> supers = new HashMap<>(); + + Map instanceInnerClasses = new ConcurrentHashMap<>(); + + if (librariesDir != null) { + scanInnerClasses(instanceInnerClasses, librariesDir); + } + try (final JarFile jarFile = new JarFile(jar.toFile())) { Enumeration entryEnumerator = jarFile.entries(); @@ -113,7 +130,7 @@ private static void forEachClass(Path jar, BiConsumer superNames = new ArrayList<>(); if (classNode.superName != null && !classNode.superName.equals("java/lang/Object")) { superNames.add(classNode.superName); @@ -125,6 +142,12 @@ private static void forEachClass(Path jar, BiConsumer o.name)); + ClassStaticContext innerClassContext = new InnerClassStats(instanceInnerClasses); Function> superGetter = k -> supers.getOrDefault(k, Collections.emptyList()); - classes.forEach(node -> classNodeConsumer.accept(superGetter, node)); + classes.forEach(node -> classNodeConsumer.accept(superGetter, node, innerClassContext)); + } + + private static void scanInnerClasses(Map instanceInnerClasses, Path librariesDir) { + try { + Files.walkFileTree(librariesDir, new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + if (!file.getFileName().toString().endsWith(".jar")) { + return FileVisitResult.CONTINUE; + } + + try (final JarFile jarFile = new JarFile(file.toFile())) { + Enumeration entryEnumerator = jarFile.entries(); + + while (entryEnumerator.hasMoreElements()) { + JarEntry entry = entryEnumerator.nextElement(); + + if (entry.isDirectory() || !entry.getName().endsWith(".class")) { + continue; + } + + try (InputStream is = jarFile.getInputStream(entry)) { + ClassReader reader = new ClassReader(is); + reader.accept(new ClassVisitor(Opcodes.ASM8) { + @Override + public void visitInnerClass(String name, String outerName, String innerName, int access) { + instanceInnerClasses.put(name, !Modifier.isStatic(access)); + } + }, ClassReader.SKIP_CODE); + } + } + } + + return FileVisitResult.CONTINUE; + } + }); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + } + + private static boolean isInstanceInnerOnClasspath(String internalName) { + String javaBinary = internalName.replace('/', '.'); + + try { + Class c = Class.forName(javaBinary, false, Main.class.getClassLoader()); + return !Modifier.isStatic(c.getModifiers()) && c.getDeclaringClass() != null; + } catch (Throwable ex) { + return false; + } } private static boolean isDigit(char ch) { return ch >= '0' && ch <= '9'; } - private static void writeClass(MappingsStore mappings, ClassNode classNode, Map existingClasses, Function> superGetter) { + private static void writeClass(MappingsStore mappings, ClassNode classNode, Map existingClasses, Function> superGetter, ClassStaticContext context) { String name = classNode.name; { //Block anonymous class and their nested classes @@ -157,7 +231,7 @@ private static void writeClass(MappingsStore mappings, ClassNode classNode, Map< } } - ClassBuilder classBuilder = new ClassBuilder(mappings, classNode, superGetter); + ClassBuilder classBuilder = new ClassBuilder(mappings, classNode, superGetter, context); if (name.contains("$")) { String parentClass = name.substring(0, name.lastIndexOf("$")); @@ -172,10 +246,25 @@ private static void writeClass(MappingsStore mappings, ClassNode classNode, Map< } - private static TypeSpec.Builder createTypeSpecBuilder(ClassNode classNode) { - return TypeSpec.classBuilder(classNode.name) - .addModifiers(); + @FunctionalInterface + private interface ClassNodeConsumer { + void accept(Function> superGetter, ClassNode node, ClassStaticContext staticContext); } + private static final class InnerClassStats implements ClassStaticContext { + final Map instanceInnerClasses; + + InnerClassStats(Map instanceInnerClasses) { + this.instanceInnerClasses = instanceInnerClasses; + } + @Override + public boolean isInstanceInner(String internalName) { + if (internalName.indexOf('$') == -1) { + return false; // heuristics + } + + return instanceInnerClasses.computeIfAbsent(internalName, Main::isInstanceInnerOnClasspath); + } + } } diff --git a/src/main/java/net/fabricmc/mappingpoet/MappingsStore.java b/src/main/java/net/fabricmc/mappingpoet/MappingsStore.java index 7153aa1..40a61ac 100644 --- a/src/main/java/net/fabricmc/mappingpoet/MappingsStore.java +++ b/src/main/java/net/fabricmc/mappingpoet/MappingsStore.java @@ -16,13 +16,6 @@ package net.fabricmc.mappingpoet; -import net.fabricmc.mapping.tree.ClassDef; -import net.fabricmc.mapping.tree.FieldDef; -import net.fabricmc.mapping.tree.MethodDef; -import net.fabricmc.mapping.tree.TinyMappingFactory; -import net.fabricmc.mapping.tree.TinyTree; -import net.fabricmc.mappings.EntryTriple; - import java.io.BufferedReader; import java.io.IOException; import java.nio.file.Files; @@ -30,20 +23,33 @@ import java.util.AbstractMap; import java.util.Collection; import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.function.BiConsumer; import java.util.function.Function; +import net.fabricmc.mapping.tree.ClassDef; +import net.fabricmc.mapping.tree.FieldDef; +import net.fabricmc.mapping.tree.Mapped; +import net.fabricmc.mapping.tree.MethodDef; +import net.fabricmc.mapping.tree.TinyMappingFactory; +import net.fabricmc.mapping.tree.TinyTree; +import net.fabricmc.mapping.util.EntryTriple; + //Taken from loom public class MappingsStore { private final Map classes = new HashMap<>(); private final Map fields = new HashMap<>(); - private final Map methods = new HashMap<>(); + private final Map> methods = new HashMap<>(); private final String namespace = "named"; + private final List namespaces; public MappingsStore(Path tinyFile) { final TinyTree mappings = readMappings(tinyFile); + namespaces = mappings.getMetadata().getNamespaces(); + for (ClassDef classDef : mappings.getClasses()) { final String className = classDef.getName(namespace); classes.put(className, classDef); @@ -53,24 +59,71 @@ public MappingsStore(Path tinyFile) { } for (MethodDef methodDef : classDef.getMethods()) { - methods.put(new EntryTriple(className, methodDef.getName(namespace), methodDef.getDescriptor(namespace)), methodDef); + methods.put(new EntryTriple(className, methodDef.getName(namespace), methodDef.getDescriptor(namespace)), new AbstractMap.SimpleImmutableEntry<>(className, methodDef)); } } } + private static TinyTree readMappings(Path input) { + try (BufferedReader reader = Files.newBufferedReader(input)) { + return TinyMappingFactory.loadWithDetection(reader); + } catch (IOException e) { + throw new RuntimeException("Failed to read mappings", e); + } + } + + @Deprecated public String getClassDoc(String className) { ClassDef classDef = classes.get(className); return classDef != null ? classDef.getComment() : null; } + private void addDoc(Mapped element, BiConsumer addJavadoc) { + String doc = element.getComment(); + if (doc != null) { + addJavadoc.accept(doc, new Object[0]); + } + } + + public void addClassDoc(BiConsumer addJavadoc, String className) { + ClassDef classDef = classes.get(className); + if (classDef == null) { + return; + } + addDoc(classDef, addJavadoc); + addJavadoc.accept("\n", new Object[0]); + for (String namespace : namespaces) { + String transformedName = classDef.getName(namespace); + addJavadoc.accept("@mapping {@literal $L:$L}\n", new Object[] {namespace, transformedName}); + } + } + + @Deprecated public String getFieldDoc(EntryTriple fieldEntry) { FieldDef fieldDef = fields.get(fieldEntry); return fieldDef != null ? fieldDef.getComment() : null; } + public void addFieldDoc(BiConsumer addJavadoc, EntryTriple fieldEntry) { + FieldDef fieldDef = fields.get(fieldEntry); + if (fieldDef == null) { + return; + } + + addDoc(fieldDef, addJavadoc); + ClassDef owner = classes.get(fieldEntry.getOwner()); + addJavadoc.accept("\n", new Object[0]); + for (String namespace : namespaces) { + String transformedName = fieldDef.getName(namespace); + String mixinForm = "L" + owner.getName(namespace) + ";" + transformedName + ":" + fieldDef.getDescriptor(namespace); + addJavadoc.accept("@mapping {@literal $L:$L:$L}\n", new Object[] {namespace, transformedName, mixinForm}); + } + } + public Map.Entry getParamNameAndDoc(Function> superGetters, EntryTriple methodEntry, int index) { - MethodDef methodDef = searchMethod(superGetters, methodEntry); - if (methodDef != null) { + Map.Entry found = searchMethod(superGetters, methodEntry); + if (found != null) { + MethodDef methodDef = found.getValue(); if (methodDef.getParameters().isEmpty()) { return null; } @@ -83,17 +136,35 @@ public Map.Entry getParamNameAndDoc(Function> superGetters, EntryTriple methodEntry) { - MethodDef methodDef = searchMethod(superGetters, methodEntry); + Map.Entry methodDef = searchMethod(superGetters, methodEntry); if (methodDef != null) { - return methodDef.getComment(); // comment doc handled separately by javapoet + return methodDef.getValue().getComment(); // comment doc handled separately by javapoet } return null; } - - private MethodDef searchMethod(Function> superGetters, EntryTriple methodEntry) { + + public void addMethodDoc(BiConsumer addJavadoc, Function> superGetters, EntryTriple methodEntry) { + Map.Entry found = searchMethod(superGetters, methodEntry); + if (found == null) { + return; + } + + MethodDef methodDef = found.getValue(); + addDoc(methodDef, addJavadoc); + ClassDef owner = classes.get(found.getKey()); + addJavadoc.accept("\n", new Object[0]); + for (String namespace : namespaces) { + String transformedName = methodDef.getName(namespace); + String mixinForm = "L" + owner.getName(namespace) + ";" + transformedName + methodDef.getDescriptor(namespace); + addJavadoc.accept("@mapping {@literal $L:$L:$L}\n", new Object[] {namespace, transformedName, mixinForm}); + } + } + + private Map.Entry searchMethod(Function> superGetters, EntryTriple methodEntry) { String className = methodEntry.getOwner(); if (!classes.containsKey(className)) { return null; @@ -102,25 +173,17 @@ private MethodDef searchMethod(Function> superGetters if (methods.containsKey(methodEntry)) { return methods.get(methodEntry); // Nullable! } - + for (String superName : superGetters.apply(className)) { - EntryTriple triple = new EntryTriple(superName, methodEntry.getName(), methodEntry.getDesc()); - MethodDef ret = searchMethod(superGetters, triple); + EntryTriple triple = new EntryTriple(superName, methodEntry.getName(), methodEntry.getDescriptor()); + Map.Entry ret = searchMethod(superGetters, triple); if (ret != null) { methods.put(triple, ret); return ret; } } - + methods.put(methodEntry, null); return null; } - - private static TinyTree readMappings(Path input) { - try (BufferedReader reader = Files.newBufferedReader(input)) { - return TinyMappingFactory.loadWithDetection(reader); - } catch (IOException e) { - throw new RuntimeException("Failed to read mappings", e); - } - } } diff --git a/src/main/java/net/fabricmc/mappingpoet/MethodBuilder.java b/src/main/java/net/fabricmc/mappingpoet/MethodBuilder.java index 7983066..0530d42 100644 --- a/src/main/java/net/fabricmc/mappingpoet/MethodBuilder.java +++ b/src/main/java/net/fabricmc/mappingpoet/MethodBuilder.java @@ -32,11 +32,19 @@ import com.squareup.javapoet.MethodSpec; import com.squareup.javapoet.ParameterSpec; import com.squareup.javapoet.TypeName; +import org.objectweb.asm.TypeReference; import org.objectweb.asm.tree.AnnotationNode; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; -import net.fabricmc.mappings.EntryTriple; +import net.fabricmc.mapping.util.EntryTriple; +import net.fabricmc.mappingpoet.signature.AnnotationAwareDescriptors; +import net.fabricmc.mappingpoet.signature.AnnotationAwareSignatures; +import net.fabricmc.mappingpoet.signature.ClassStaticContext; +import net.fabricmc.mappingpoet.signature.MethodSignature; +import net.fabricmc.mappingpoet.signature.TypeAnnotationBank; +import net.fabricmc.mappingpoet.signature.TypeAnnotationMapping; +import net.fabricmc.mappingpoet.signature.TypeAnnotationStorage; public class MethodBuilder { private static final Set RESERVED_KEYWORDS = Collections.unmodifiableSet(new HashSet<>(Arrays.asList( @@ -52,18 +60,29 @@ public class MethodBuilder { private final MethodSpec.Builder builder; private final Function> superGetter; private final int formalParamStartIndex; + private final ClassStaticContext context; + private final String receiverSignature; + private final TypeAnnotationMapping typeAnnotations; - private Signatures.MethodSignature signature; + private MethodSignature signature; - public MethodBuilder(MappingsStore mappings, ClassNode classNode, MethodNode methodNode, Function> superGetter, int formalParamStartIndex) { + public MethodBuilder(MappingsStore mappings, ClassNode classNode, MethodNode methodNode, Function> superGetter, ClassStaticContext context, String receiverSignature, int formalParamStartIndex) { this.mappings = mappings; this.classNode = classNode; this.methodNode = methodNode; this.superGetter = superGetter; + this.context = context; + this.receiverSignature = receiverSignature; this.formalParamStartIndex = formalParamStartIndex; + + typeAnnotations = TypeAnnotationStorage.builder() + .add(methodNode.invisibleTypeAnnotations) + .add(methodNode.visibleTypeAnnotations) + .build(); + this.builder = createBuilder(); addJavaDoc(); - addDirectAnnotations(); + addAnnotations(); setReturnType(); addParameters(); addExceptions(); @@ -107,7 +126,7 @@ static String reserveValidName(String suggestedName, Set usedNames) { } static String suggestName(TypeName type) { - String str = type.toString(); + String str = type.withoutAnnotations().toString(); int newStart = 0; int newEnd = str.length(); int ltStart; @@ -139,16 +158,14 @@ private MethodSpec.Builder createBuilder() { } if (methodNode.signature != null) { - signature = Signatures.parseMethodSignature(methodNode.signature); - if (signature.generics != null) { - builder.addTypeVariables(signature.generics); - } + signature = AnnotationAwareSignatures.parseMethodSignature(methodNode.signature, typeAnnotations, context); + builder.addTypeVariables(signature.generics); } return builder; } - private void addDirectAnnotations() { + private void addAnnotations() { addDirectAnnotations(methodNode.invisibleAnnotations); addDirectAnnotations(methodNode.visibleAnnotations); } @@ -173,22 +190,46 @@ private void setReturnType() { typeName = signature.result; } else { String returnDesc = methodNode.desc.substring(methodNode.desc.lastIndexOf(")") + 1); - typeName = FieldBuilder.typeFromDesc(returnDesc); + typeName = AnnotationAwareDescriptors.parseDesc(returnDesc, typeAnnotations.getBank(TypeReference.newTypeReference(TypeReference.METHOD_RETURN)), context); } builder.returns(typeName); if (typeName != TypeName.VOID && !builder.modifiers.contains(Modifier.ABSTRACT)) { builder.addStatement("throw new RuntimeException()"); + } else if (methodNode.annotationDefault != null) { + builder.defaultValue(FieldBuilder.codeFromAnnoValue(methodNode.annotationDefault)); } } - private void addParameters() { + private void addParameters(MethodBuilder this) { // todo fix enum ctors List paramTypes = new ArrayList<>(); boolean instanceMethod = !builder.modifiers.contains(Modifier.STATIC); Set usedParamNames = new HashSet<>(RESERVED_KEYWORDS); getParams(paramTypes, instanceMethod, usedParamNames); + // generate receiver param for type annos + + TypeAnnotationBank receiverAnnos = typeAnnotations.getBank(TypeReference.newTypeReference(TypeReference.METHOD_RECEIVER)); + if (!receiverAnnos.isEmpty()) { + ParameterSpec.Builder receiverBuilder; + // only instance inner class ctor can have receivers + if (methodNode.name.equals("")) { + TypeName annotatedReceiver = AnnotationAwareSignatures.parseSignature("L" + receiverSignature.substring(0, receiverSignature.lastIndexOf('.')) + ";", receiverAnnos, context); + // vulnerable heuristics + String simpleNameChain = classNode.name.substring(classNode.name.lastIndexOf('/') + 1); + int part1 = simpleNameChain.lastIndexOf('$'); // def exists + int part2 = simpleNameChain.lastIndexOf('$', part1 - 1); // may be -1 + String usedName = simpleNameChain.substring(part2 + 1, part1); + receiverBuilder = ParameterSpec.builder(annotatedReceiver, usedName + ".this"); + } else { + TypeName annotatedReceiver = AnnotationAwareSignatures.parseSignature("L" + receiverSignature + ";", receiverAnnos, context); + receiverBuilder = ParameterSpec.builder(annotatedReceiver, "this"); + } + // receiver param cannot have its jd/param anno except type use anno + builder.addParameter(receiverBuilder.build()); + } + List[] visibleParameterAnnotations = methodNode.visibleParameterAnnotations; List[] invisibleParameterAnnotations = methodNode.invisibleParameterAnnotations; int index = 0; @@ -218,18 +259,22 @@ private void getParams(List paramTypes, boolean instance, Set Iterator signatureParamIterator = signature == null ? Collections.emptyIterator() : signature.parameters.iterator(); while (desc.charAt(index) != ')') { + int oldIndex = index; Map.Entry parsedParam = FieldBuilder.parseType(desc, index); index = parsedParam.getKey(); - TypeName paramType = parsedParam.getValue(); + TypeName nonAnnotatedParsedType = parsedParam.getValue(); if (paramIndex >= formalParamStartIndex) { // skip guessed synthetic/implicit params + TypeName parsedType; if (signatureParamIterator.hasNext()) { - paramType = signatureParamIterator.next(); + parsedType = signatureParamIterator.next(); + } else { + parsedType = AnnotationAwareDescriptors.parseDesc(desc.substring(oldIndex, index), typeAnnotations.getBank(TypeReference.newFormalParameterReference(paramIndex - formalParamStartIndex)), context); } - paramTypes.add(new ParamType(mappings.getParamNameAndDoc(superGetter, new EntryTriple(classNode.name, methodNode.name, methodNode.desc), slot), paramType, usedParamNames, slot)); + paramTypes.add(new ParamType(mappings.getParamNameAndDoc(superGetter, new EntryTriple(classNode.name, methodNode.name, methodNode.desc), slot), parsedType, usedParamNames, slot)); } slot++; - if (paramType.equals(TypeName.DOUBLE) || paramType.equals(TypeName.LONG)) { + if (nonAnnotatedParsedType.equals(TypeName.DOUBLE) || nonAnnotatedParsedType.equals(TypeName.LONG)) { slot++; } paramIndex++; @@ -251,17 +296,16 @@ private void addExceptions() { } List exceptions = methodNode.exceptions; if (exceptions != null) { + int index = 0; for (String internalName : exceptions) { - builder.addException(ClassBuilder.parseInternalName(internalName)); + builder.addException(AnnotationAwareDescriptors.parseType(internalName, typeAnnotations.getBank(TypeReference.newExceptionReference(index)), context)); + index++; } } } private void addJavaDoc() { - String javaDoc = mappings.getMethodDoc(superGetter, new EntryTriple(classNode.name, methodNode.name, methodNode.desc)); - if (javaDoc != null) { - builder.addJavadoc(javaDoc); - } + mappings.addMethodDoc(builder::addJavadoc, superGetter, new EntryTriple(classNode.name, methodNode.name, methodNode.desc)); } public MethodSpec build() { @@ -278,7 +322,7 @@ public ParamType(Map.Entry nameAndDoc, TypeName type, Set;B:Ljava/lang/Object>Ljava/lang/Object; etc etc int index = 0; char ch; - List generics = null; + List generics = Collections.emptyList(); if (signature.charAt(0) == '<') { // parse generic decl index++; // consume '<' @@ -86,23 +90,10 @@ public static ClassSignature parseClassSignature(final String signature) { return new ClassSignature(generics, supers.removeFirst(), supers); } - public static final class ClassSignature { - // Nullable - public final List generics; - public final TypeName superclass; - public final List superinterfaces; - - ClassSignature(List generics, TypeName superclass, List superinterfaces) { - this.generics = generics; - this.superclass = superclass; - this.superinterfaces = superinterfaces; - } - } - public static MethodSignature parseMethodSignature(String signature) { int index = 0; char ch; - List generics = null; + List generics = Collections.emptyList(); if (signature.charAt(0) == '<') { // parse generic decl index++; // consume '<' @@ -177,21 +168,6 @@ public static MethodSignature parseMethodSignature(String signature) { return new MethodSignature(generics, params, returnType, thrown); } - public static final class MethodSignature { - // Nullable - public final List generics; - public final List parameters; - public final TypeName result; - public final List thrown; - - MethodSignature(List generics, List parameters, TypeName result, List thrown) { - this.generics = generics; - this.parameters = parameters; - this.result = result; - this.thrown = thrown; - } - } - public static TypeName parseFieldSignature(String signature) { return parseParameterizedType(signature, 0).getValue(); } diff --git a/src/main/java/net/fabricmc/mappingpoet/jd/MappingTaglet.java b/src/main/java/net/fabricmc/mappingpoet/jd/MappingTaglet.java new file mode 100644 index 0000000..98cbd34 --- /dev/null +++ b/src/main/java/net/fabricmc/mappingpoet/jd/MappingTaglet.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2020 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.mappingpoet.jd; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.UncheckedIOException; +import java.nio.charset.StandardCharsets; +import java.util.EnumSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; + +import com.sun.source.doctree.DocTree; +import com.sun.source.doctree.LiteralTree; +import com.sun.source.doctree.UnknownBlockTagTree; +import jdk.javadoc.doclet.Taglet; + +@SuppressWarnings("unused") +public final class MappingTaglet implements Taglet { + + private static final String JS_CONTENT; + + public MappingTaglet() { + // Required by javadoc + } + + @Override + public Set getAllowedLocations() { + return EnumSet.of(Location.TYPE, Location.CONSTRUCTOR, Location.METHOD, Location.FIELD); + } + + @Override + public boolean isInlineTag() { + return false; + } + + @Override + public String getName() { + return "mapping"; + } + + @Override + public String toString(List tags, Element element) { + boolean typeDecl = element instanceof TypeElement; // means it's a class, itf, enum, etc. + StringBuilder builder = new StringBuilder(); + builder.append("

Mapping data

\n"); + builder.append("\n"); + builder.append("\n"); + builder.append("\n"); + builder.append("\n"); + builder.append("\n"); + if (!typeDecl) { + builder.append("\n"); + } + builder.append("\n"); + builder.append("\n"); + + for (DocTree each : tags) { + String body = ((UnknownBlockTagTree) each).getContent().stream().map(t -> ((LiteralTree) t).getBody().getBody()).collect(Collectors.joining()); + String[] ans = body.split(":", 3); + builder.append("\n"); + builder.append(String.format("\n", escaped(ans[0]))); + final int bound = typeDecl ? 2 : 3; + for (int i = 1; i < bound; i++) { + builder.append(String.format("\n", escaped(ans[i]))); + } + builder.append("\n"); + } + + builder.append("\n"); + builder.append("
NamespaceNameMixin form
%s%s
\n"); + builder.append("\n"); + return builder.toString(); + } + + // I hate + private static String escaped(String original) { + StringBuilder builder = new StringBuilder(original.length()); + final int len = original.length(); + for (int i = 0; i < len; i++) { + char c = original.charAt(i); + if (c > 127 || c == '"' || c == '\'' || c == '<' || c == '>' || c == '&') { + builder.append("&#").append((int) c).append(";"); + } else { + builder.append(c); + } + } + return builder.toString(); + } + + static { + StringBuilder sb = new StringBuilder(); + try (BufferedReader reader = new BufferedReader(new InputStreamReader(Objects.requireNonNull(MappingTaglet.class.getResourceAsStream("/copy_on_click.js"), "copy_on_click.js stream"), StandardCharsets.UTF_8))) { + String line; + while ((line = reader.readLine()) != null) { + sb.append(line).append("\n"); + } + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + JS_CONTENT = sb.toString(); + } +} diff --git a/src/main/java/net/fabricmc/mappingpoet/signature/AnnotationAwareDescriptors.java b/src/main/java/net/fabricmc/mappingpoet/signature/AnnotationAwareDescriptors.java new file mode 100644 index 0000000..decf8ae --- /dev/null +++ b/src/main/java/net/fabricmc/mappingpoet/signature/AnnotationAwareDescriptors.java @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2020 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.mappingpoet.signature; + +import java.util.AbstractMap; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Deque; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; + +import com.squareup.javapoet.AnnotationSpec; +import com.squareup.javapoet.ArrayTypeName; +import com.squareup.javapoet.ClassName; +import com.squareup.javapoet.TypeName; +import org.objectweb.asm.TypePath; +import org.objectweb.asm.TypeReference; + +import net.fabricmc.mappingpoet.Signatures; + +public final class AnnotationAwareDescriptors { + + private AnnotationAwareDescriptors() { + } + + // not really signature, but annotated classes + public static ClassSignature parse(String rawSuper, List rawInterfaces, TypeAnnotationMapping mapping, ClassStaticContext context) { + ClassName superName = parseType(rawSuper, mapping.getBank(TypeReference.newSuperTypeReference(-1)), context); + + List interfaces = new ArrayList<>(rawInterfaces.size()); + for (ListIterator itr = rawInterfaces.listIterator(); itr.hasNext(); ) { + int i = itr.nextIndex(); + String item = itr.next(); + + ClassName itfName = parseType(item, mapping.getBank(TypeReference.newSuperTypeReference(i)), context); + interfaces.add(itfName); + } + + return new ClassSignature(Collections.emptyList(), superName, interfaces); + } + + // only for descriptor-based ones. Use signature visitor for signature-based ones! + public static TypeName parseDesc(String desc, TypeAnnotationBank bank, ClassStaticContext context) { + Deque> arrayAnnotations = new ArrayDeque<>(); + int len = desc.length(); + int index; + for (index = 0; (index < len) && (desc.charAt(index) == '['); index++) { + arrayAnnotations.push(bank.getCurrentAnnotations()); + bank = bank.advance(TypePath.ARRAY_ELEMENT, 0); + } + + TypeName current; + if (len - index == 1) { + current = annotate(Signatures.getPrimitive(desc.charAt(index)), bank); + } else { + // L ; + assert desc.charAt(index) == 'L' && desc.charAt(len - 1) == ';'; + current = parseType(desc.substring(index + 1, len - 1), bank, context); + } + while (!arrayAnnotations.isEmpty()) { + current = ArrayTypeName.of(current); + List specs = arrayAnnotations.pop(); + if (!specs.isEmpty()) { + current = current.annotated(specs); + } + } + + return current; + } + + public static ClassName parseType(String internalName, TypeAnnotationBank bank, ClassStaticContext context) { + Map.Entry result = annotateUpTo(internalName, bank, context); + return annotate(result.getKey(), result.getValue()); + } + + /** + * Annotate class name chains until the last element. Useful for making the last + * element a parameterized type before annotating it. + * + * @param internalName the internal name chain + * @param bank the annotation storage + * @param context the context for testing instance inner class + * @return the class name ready for parameterization/annotation and the current annotation state + */ + static Map.Entry annotateUpTo(String internalName, TypeAnnotationBank bank, ClassStaticContext context) { + if (internalName.startsWith("L") && internalName.endsWith(";")) { + throw new AssertionError(internalName); + } + int slice = internalName.lastIndexOf('/'); + String packageSt = slice < 0 ? "" : internalName.substring(0, slice).replace('/', '.'); + + int moneySign = internalName.indexOf('$', slice + 1); + if (moneySign == -1) { + return new AbstractMap.SimpleImmutableEntry<>(ClassName.get(packageSt, internalName.substring(slice + 1)), bank); + } + + ClassName current = ClassName.get(packageSt, internalName.substring(slice + 1, moneySign)); + + final int len = internalName.length(); + boolean enteredInner = false; + for (int i = moneySign; i < len; ) { + int t = internalName.indexOf('$', i + 1); + if (t < 0) { + t = len; + } + + // do work + if (!enteredInner && context.isInstanceInner(internalName.substring(0, t))) { + enteredInner = true; // instance inner classes cannot nest static ones + } + + if (enteredInner) { + // annotate parent before we advance + current = annotate(current, bank); + } + + current = current.nestedClass(internalName.substring(i + 1, t)); + + if (enteredInner) { + // advance on path as it's instance inner class + bank = bank.advance(TypePath.INNER_TYPE, 0); + } + + i = t; + } + + return new AbstractMap.SimpleImmutableEntry<>(current, bank); + } + + @SuppressWarnings("unchecked") + public static T annotate(T input, TypeAnnotationBank storage) { + List annotations = storage.getCurrentAnnotations(); + return annotations.isEmpty() ? input : (T) input.annotated(annotations); // it's implemented so + } +} diff --git a/src/main/java/net/fabricmc/mappingpoet/signature/AnnotationAwareSignatures.java b/src/main/java/net/fabricmc/mappingpoet/signature/AnnotationAwareSignatures.java new file mode 100644 index 0000000..c6572d6 --- /dev/null +++ b/src/main/java/net/fabricmc/mappingpoet/signature/AnnotationAwareSignatures.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2020 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.mappingpoet.signature; + +import com.squareup.javapoet.TypeName; +import org.objectweb.asm.TypeReference; +import org.objectweb.asm.signature.SignatureReader; + +public final class AnnotationAwareSignatures { + + private AnnotationAwareSignatures() { + } + + public static ClassSignature parseClassSignature(String signature, TypeAnnotationMapping annotationMapping, ClassStaticContext context) { + PoetClassMethodSignatureVisitor visitor = new PoetClassMethodSignatureVisitor(annotationMapping, context, true); + new SignatureReader(signature).accept(visitor); + return visitor.collectClass(); + } + + // Note: No receiver (self) parameter included! + public static MethodSignature parseMethodSignature(String signature, TypeAnnotationMapping annotationMapping, ClassStaticContext context) { + PoetClassMethodSignatureVisitor visitor = new PoetClassMethodSignatureVisitor(annotationMapping, context, false); + new SignatureReader(signature).accept(visitor); + return visitor.collectMethod(); + } + + public static TypeName parseFieldSignature(String signature, TypeAnnotationMapping annotationMapping, ClassStaticContext context) { + return parseSignature(signature, annotationMapping.getBank(TypeReference.newTypeReference(TypeReference.FIELD)), context); + } + + public static TypeName parseSignature(String signature, TypeAnnotationBank annotations, ClassStaticContext context) { + PoetTypeSignatureWriter visitor = new PoetTypeSignatureWriter(annotations, context); + new SignatureReader(signature).acceptType(visitor); + return visitor.compute(); + } +} diff --git a/src/main/java/net/fabricmc/mappingpoet/signature/ClassSignature.java b/src/main/java/net/fabricmc/mappingpoet/signature/ClassSignature.java new file mode 100644 index 0000000..e3b5df5 --- /dev/null +++ b/src/main/java/net/fabricmc/mappingpoet/signature/ClassSignature.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2020 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.mappingpoet.signature; + +import java.util.List; + +import com.squareup.javapoet.TypeName; +import com.squareup.javapoet.TypeVariableName; + +// no more a class signature but general super info about class +public final class ClassSignature { + public final List generics; + public final TypeName superclass; + public final List superinterfaces; + + public ClassSignature(List generics, TypeName superclass, List superinterfaces) { + this.generics = generics; + this.superclass = superclass; + this.superinterfaces = superinterfaces; + } +} diff --git a/src/main/java/net/fabricmc/mappingpoet/signature/ClassStaticContext.java b/src/main/java/net/fabricmc/mappingpoet/signature/ClassStaticContext.java new file mode 100644 index 0000000..1ba5c49 --- /dev/null +++ b/src/main/java/net/fabricmc/mappingpoet/signature/ClassStaticContext.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.mappingpoet.signature; + +/** + * A context to retrieve if a class is an instance inner class. Useful for + * placing type annotations correctly. See + * + * an example in JVM Specification 15. + */ +public interface ClassStaticContext { + + /** + * Returns if this class is an instance inner class. + * + *

For example, a top-level class is not so. A static inner + * class, such as {@code Map.Entry}, is not as well.

+ * + * @param internalName the JVM name of the class + * @return whether this class is not an instance inner class. + */ + boolean isInstanceInner(String internalName); +} diff --git a/src/main/java/net/fabricmc/mappingpoet/signature/MethodSignature.java b/src/main/java/net/fabricmc/mappingpoet/signature/MethodSignature.java new file mode 100644 index 0000000..20cfe16 --- /dev/null +++ b/src/main/java/net/fabricmc/mappingpoet/signature/MethodSignature.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2020 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.mappingpoet.signature; + +import java.util.List; + +import com.squareup.javapoet.TypeName; +import com.squareup.javapoet.TypeVariableName; + +public final class MethodSignature { + public final List generics; + public final List parameters; + public final TypeName result; + public final List thrown; + + public MethodSignature(List generics, List parameters, TypeName result, List thrown) { + this.generics = generics; + this.parameters = parameters; + this.result = result; + this.thrown = thrown; + } +} diff --git a/src/main/java/net/fabricmc/mappingpoet/signature/PoetClassMethodSignatureVisitor.java b/src/main/java/net/fabricmc/mappingpoet/signature/PoetClassMethodSignatureVisitor.java new file mode 100644 index 0000000..1c6056d --- /dev/null +++ b/src/main/java/net/fabricmc/mappingpoet/signature/PoetClassMethodSignatureVisitor.java @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2020 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.mappingpoet.signature; + +import java.util.LinkedList; + +import com.squareup.javapoet.TypeName; +import com.squareup.javapoet.TypeVariableName; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.TypeReference; +import org.objectweb.asm.signature.SignatureVisitor; + +public final class PoetClassMethodSignatureVisitor extends SignatureVisitor { + + private final TypeAnnotationMapping mapping; + private final ClassStaticContext context; + private final boolean forClass; + LinkedList generics = new LinkedList<>(); + // collecting generic + String currentGenericName; + LinkedList currentGenericBounds = new LinkedList<>(); + // bound for each generic + PoetTypeSignatureWriter pendingLowerBound; + + // classes usage + LinkedList superTypes = new LinkedList<>(); + PoetTypeSignatureWriter pendingSupertype; + + // methods usage + LinkedList params = new LinkedList<>(); + LinkedList throwables = new LinkedList<>(); + PoetTypeSignatureWriter pendingSlot; + TypeName returnType; + + public PoetClassMethodSignatureVisitor(TypeAnnotationMapping mapping, ClassStaticContext context, boolean forClass) { + super(Opcodes.ASM8); + this.mapping = mapping; + this.context = context; + this.forClass = forClass; + } + + private void collectGeneric() { + collectLowerBound(); + + if (currentGenericName != null) { + TypeVariableName generic = TypeVariableName.get(currentGenericName, currentGenericBounds.toArray(new TypeName[0])); + TypeAnnotationBank bank = mapping.getBank(TypeReference.newTypeParameterReference(forClass ? TypeReference.CLASS_TYPE_PARAMETER : TypeReference.METHOD_TYPE_PARAMETER, generics.size())); + generic = AnnotationAwareDescriptors.annotate(generic, bank); + generics.add(generic); + + currentGenericName = null; + currentGenericBounds.clear(); + } + } + + private void collectGenerics() { + // end all generics + collectGeneric(); + } + + // starts a new generic declaration, like in " T[] toArray(T[] input);" + @Override + public void visitFormalTypeParameter(String name) { + collectGeneric(); + // collect existing type parameter + // start type var name + currentGenericName = name; + currentGenericBounds.clear(); + } + + private void collectLowerBound() { + if (pendingLowerBound != null) { + currentGenericBounds.addLast(pendingLowerBound.compute()); + pendingLowerBound = null; + } + } + + private SignatureVisitor visitLowerBound() { + collectLowerBound(); + + TypeAnnotationBank bank = mapping.getBank(TypeReference.newTypeParameterBoundReference(forClass ? + TypeReference.CLASS_TYPE_PARAMETER_BOUND : TypeReference.METHOD_TYPE_PARAMETER_BOUND, generics.size(), + currentGenericBounds.size())); + return pendingLowerBound = new PoetTypeSignatureWriter(bank, context); + } + + @Override + public SignatureVisitor visitClassBound() { + return visitLowerBound(); + } + + @Override + public SignatureVisitor visitInterfaceBound() { + return visitLowerBound(); + } + + // class exclusive + + private void collectSupertype() { + if (pendingSupertype != null) { + TypeName simple = pendingSupertype.compute(); + superTypes.addLast(simple); + + pendingSupertype = null; + } + } + + // always called + @Override + public SignatureVisitor visitSuperclass() { + collectGenerics(); + // don't need to collect other supertype + + return pendingSupertype = new PoetTypeSignatureWriter(mapping.getBank(TypeReference.newSuperTypeReference(-1)), context); + } + + @Override + public SignatureVisitor visitInterface() { + // super class always visited, no generic check + collectSupertype(); + + return pendingSupertype = new PoetTypeSignatureWriter(mapping.getBank(TypeReference.newSuperTypeReference(superTypes.size() - 1)), context); + } + + public ClassSignature collectClass() { + collectSupertype(); + + TypeName superclass = superTypes.removeFirst(); + return new ClassSignature(generics, superclass, superTypes); + } + + // method exclusive + + private void collectParam() { + if (pendingSlot != null) { + TypeName slot = pendingSlot.compute(); + params.addLast(slot); + + pendingSlot = null; + } + } + + private void collectReturnOrThrows() { + if (pendingSlot != null) { + if (returnType == null) { + returnType = pendingSlot.compute(); + } else { + throwables.addLast(pendingSlot.compute()); + } + + pendingSlot = null; + } + } + + @Override + public SignatureVisitor visitParameterType() { + collectGenerics(); + collectParam(); + + return pendingSlot = new PoetTypeSignatureWriter(mapping.getBank(TypeReference.newFormalParameterReference(params.size())), context); + } + + @Override + public SignatureVisitor visitReturnType() { + collectGenerics(); // they may skip visiting params, rip! + collectParam(); + + return pendingSlot = new PoetTypeSignatureWriter(mapping.getBank(TypeReference.newTypeReference(TypeReference.METHOD_RETURN)), context); + } + + @Override + public SignatureVisitor visitExceptionType() { + collectReturnOrThrows(); + + return pendingSlot = new PoetTypeSignatureWriter(mapping.getBank(TypeReference.newExceptionReference(throwables.size())), context); + } + + public MethodSignature collectMethod() { + collectReturnOrThrows(); + + return new MethodSignature(generics, params, returnType, throwables); + } +} diff --git a/src/main/java/net/fabricmc/mappingpoet/signature/PoetTypeSignatureWriter.java b/src/main/java/net/fabricmc/mappingpoet/signature/PoetTypeSignatureWriter.java new file mode 100644 index 0000000..bf5014f --- /dev/null +++ b/src/main/java/net/fabricmc/mappingpoet/signature/PoetTypeSignatureWriter.java @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2020 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.mappingpoet.signature; + +import java.util.LinkedList; +import java.util.Map; +import java.util.Objects; + +import com.squareup.javapoet.ArrayTypeName; +import com.squareup.javapoet.ClassName; +import com.squareup.javapoet.ParameterizedTypeName; +import com.squareup.javapoet.TypeName; +import com.squareup.javapoet.TypeVariableName; +import com.squareup.javapoet.WildcardTypeName; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.TypePath; +import org.objectweb.asm.signature.SignatureVisitor; + +import net.fabricmc.mappingpoet.Signatures; + +/** + * A type signature to javapoet visitor. + * + *

A type signature is one at the usage of type, such as field and local var type. + * It does not include class or method signatures where new generics like {@code } + * can be defined.

+ */ +public final class PoetTypeSignatureWriter extends SignatureVisitor { + + private final ClassStaticContext context; + private final LinkedList params = new LinkedList<>(); + private /* NonNull */ TypeAnnotationBank storage; // mutable + private TypeName result; + // array + private PoetTypeSignatureWriter arrayChild; + // class type signature stuff + private TypeName currentType; // ClassName or ParameterizedTypeName + private String nestedClassName; + // single type argument + private char activeTypeArgumentKind; + private PoetTypeSignatureWriter activeTypeArgument; + + public PoetTypeSignatureWriter(TypeAnnotationBank storage, ClassStaticContext context) { + super(Opcodes.ASM8); + this.storage = storage; + this.context = context; + } + + public TypeName compute() { + // array cleanup. doesn't have visit end TwT + if (arrayChild != null) { + result = ArrayTypeName.of(arrayChild.compute()); + + result = annotate(result); + } + + return Objects.requireNonNull(result, "writer did not visit"); + } + + private T annotate(T input) { + return AnnotationAwareDescriptors.annotate(input, storage); + } + + private void annotateResult() { + result = annotate(result); + } + + // primitives + @Override + public void visitBaseType(char descriptor) { + result = Signatures.getPrimitive(descriptor); + annotateResult(); + } + + // T, E etc + @Override + public void visitTypeVariable(String name) { + result = TypeVariableName.get(name); + annotateResult(); + } + + @Override + public SignatureVisitor visitArrayType() { + return arrayChild = new PoetTypeSignatureWriter(this.storage.advance(TypePath.ARRAY_ELEMENT, 0), context); + // post cleanup, annotate in #getResult() + } + + // outer class, may have instance inner class. ends with visitEnd + @Override + public void visitClassType(String internalName) { + Map.Entry entry = AnnotationAwareDescriptors.annotateUpTo(internalName, storage, context); + + currentType = entry.getKey(); + storage = entry.getValue(); + // later collect annotations in #collectPreviousTypeArgumentsAndAnnotations + } + + // collect info onto this before we append inners + private void collectPreviousTypeArgumentsAndAnnotations() { + collectLastTypeArgument(); + + if (!params.isEmpty()) { + if (currentType instanceof ParameterizedTypeName) { + // top-level handled already + currentType = ((ParameterizedTypeName) currentType).nestedClass(nestedClassName, params); + } else { // assume ClassName + if (nestedClassName == null) { // top-level + currentType = ParameterizedTypeName.get((ClassName) currentType, params.toArray(new TypeName[0])); + } else { + currentType = ParameterizedTypeName.get(((ClassName) currentType).nestedClass(nestedClassName), params.toArray(new TypeName[0])); + } + } + + params.clear(); + nestedClassName = null; + } else if (nestedClassName != null) { + if (currentType instanceof ParameterizedTypeName) { + currentType = ((ParameterizedTypeName) currentType).nestedClass(nestedClassName); + } else { + currentType = ((ClassName) currentType).nestedClass(nestedClassName); + } + nestedClassName = null; + } + + currentType = annotate(currentType); + } + + @Override + public void visitInnerClassType(String name) { + collectPreviousTypeArgumentsAndAnnotations(); + // collect previous type arguments + nestedClassName = name; + storage = storage.advance(TypePath.INNER_TYPE, 0); + } + + private void collectLastTypeArgument() { + if (activeTypeArgument != null) { + TypeName hold = activeTypeArgument.compute(); + TypeName used; + switch (activeTypeArgumentKind) { + case SignatureVisitor.EXTENDS: + used = WildcardTypeName.subtypeOf(hold); + break; + case SignatureVisitor.SUPER: + used = WildcardTypeName.supertypeOf(hold); + break; + case SignatureVisitor.INSTANCEOF: + used = hold; + break; + default: + throw new IllegalStateException(String.format("Illegal type argument wildcard %s", activeTypeArgumentKind)); + } + + used = AnnotationAwareDescriptors.annotate(used, storage.advance(TypePath.TYPE_ARGUMENT, params.size())); + params.addLast(used); + + activeTypeArgument = null; + activeTypeArgumentKind = 0; + } + } + + // wildcard ? like in List + @Override + public void visitTypeArgument() { + collectLastTypeArgument(); + + TypeName used = WildcardTypeName.subtypeOf(TypeName.OBJECT); + used = AnnotationAwareDescriptors.annotate(used, storage.advance(TypePath.TYPE_ARGUMENT, params.size())); + params.addLast(used); + } + + // (? extends/ ? super)? ClassType like in Consumer, + // Supplier + @Override + public SignatureVisitor visitTypeArgument(char wildcard) { + collectLastTypeArgument(); + + activeTypeArgumentKind = wildcard; + return activeTypeArgument = new PoetTypeSignatureWriter(storage.advance(TypePath.WILDCARD_BOUND, 0), context); + } + + @Override + public void visitEnd() { + collectPreviousTypeArgumentsAndAnnotations(); + // finalize result! + result = currentType; + currentType = null; + } +} diff --git a/src/main/java/net/fabricmc/mappingpoet/signature/TypeAnnotationBank.java b/src/main/java/net/fabricmc/mappingpoet/signature/TypeAnnotationBank.java new file mode 100644 index 0000000..3b24907 --- /dev/null +++ b/src/main/java/net/fabricmc/mappingpoet/signature/TypeAnnotationBank.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2020 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.mappingpoet.signature; + +import java.util.Collections; +import java.util.List; + +import com.squareup.javapoet.AnnotationSpec; + +// recommended storing with a sorted array + index slicing + +/** + * The collection of type annotations on a specific type. Can be narrowed down through type path. + */ +public interface TypeAnnotationBank { + TypeAnnotationBank EMPTY = new TypeAnnotationBank() { + @Override + public TypeAnnotationBank advance(int step, int stepArgument) { + return this; + } + + @Override + public List getCurrentAnnotations() { + return Collections.emptyList(); + } + + @Override + public boolean isEmpty() { + return true; + } + }; + + /** + * Make the scope of type annotations smaller. + * + * @param step see {@link org.objectweb.asm.TypePath#getStep(int)} + * @param stepArgument see {@link org.objectweb.asm.TypePath#getStepArgument(int)} + * @return the sliced type annotation storage + */ + TypeAnnotationBank advance(int step, int stepArgument); + + /** + * Accesses annotations applicable at current type location. + * + *

Do not modify the returned list!

+ * + * @return the current annotations to apply + */ + List getCurrentAnnotations(); + + /** + * Returns if there is no more annotations. Used to check for receiver + * declarations. + * + * @return whether there's no more annotations + */ + boolean isEmpty(); +} diff --git a/src/main/java/net/fabricmc/mappingpoet/signature/TypeAnnotationMapping.java b/src/main/java/net/fabricmc/mappingpoet/signature/TypeAnnotationMapping.java new file mode 100644 index 0000000..f6caaae --- /dev/null +++ b/src/main/java/net/fabricmc/mappingpoet/signature/TypeAnnotationMapping.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2020 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.mappingpoet.signature; + +import org.objectweb.asm.TypeReference; + +/** + * The collection of type annotations from a bytecode structure that stores type annotations. + */ +public interface TypeAnnotationMapping { + + TypeAnnotationMapping EMPTY = reference -> TypeAnnotationBank.EMPTY; + + // implNote: TypeReference is not a pojo! No equals or hash! + TypeAnnotationBank getBank(TypeReference reference); +} diff --git a/src/main/java/net/fabricmc/mappingpoet/signature/TypeAnnotationStorage.java b/src/main/java/net/fabricmc/mappingpoet/signature/TypeAnnotationStorage.java new file mode 100644 index 0000000..14af548 --- /dev/null +++ b/src/main/java/net/fabricmc/mappingpoet/signature/TypeAnnotationStorage.java @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2020 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.mappingpoet.signature; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +import com.squareup.javapoet.AnnotationSpec; +import org.objectweb.asm.TypePath; +import org.objectweb.asm.TypeReference; +import org.objectweb.asm.tree.TypeAnnotationNode; + +import net.fabricmc.mappingpoet.FieldBuilder; + +public final class TypeAnnotationStorage implements TypeAnnotationMapping, TypeAnnotationBank { + + private final int[] targets; // target type and info, only exist in mapping version + private final String[] paths; + private final AnnotationSpec[] contents; + private final int startIndex; + private final int endIndex; + private final String currentPath; + + TypeAnnotationStorage(int startIndex, int endIndex, String currentPath, int[] targets, String[] paths, AnnotationSpec[] contents) { + this.targets = targets; + this.paths = paths; + this.contents = contents; + this.startIndex = startIndex; + this.endIndex = endIndex; + this.currentPath = currentPath; + } + + public static Builder builder() { + return new Builder(); + } + + static int comparePath(TypePath left, TypePath right) { + int len = Math.min(left.getLength(), right.getLength()); + for (int i = 0; i < len; i++) { + int leftStep = left.getStep(i); + int rightStep = right.getStep(i); + if (leftStep != rightStep) { + return Integer.compare(leftStep, rightStep); + } + + int leftStepArg = left.getStepArgument(i); + int rightStepArg = right.getStepArgument(i); + if (leftStepArg != rightStepArg) { + return Integer.compare(leftStepArg, rightStepArg); + } + } + + // shorter ones definitely go first! + return Integer.compare(left.getLength(), right.getLength()); + } + + @Override + public TypeAnnotationBank advance(int step, int stepArgument) { + if (currentPath == null) { + throw new IllegalStateException(); + } + + String suffix; + switch (step) { + case TypePath.ARRAY_ELEMENT: + suffix = "["; + break; + case TypePath.INNER_TYPE: + suffix = "."; + break; + case TypePath.WILDCARD_BOUND: + suffix = "*"; + break; + case TypePath.TYPE_ARGUMENT: + suffix = stepArgument + ";"; + break; + default: + throw new IllegalArgumentException(); + } + + String check = currentPath.concat(suffix); + + String hiCheck = check.substring(0, check.length() - 1).concat(Character.toString((char) (check.charAt(check.length() - 1) + 1))); + + + int low = Arrays.binarySearch(paths, startIndex, endIndex, check); + if (low < 0) { + low = -(low + 1); + } + + // exclusive hi + int hi = Arrays.binarySearch(paths, startIndex, endIndex, hiCheck); + if (hi < 0) { + hi = -(hi + 1); + } + + return new TypeAnnotationStorage(low, hi, check, null, paths, contents); + } + + @Override + public List getCurrentAnnotations() { + if (currentPath == null) { + throw new IllegalStateException(); + } + + int hi = Arrays.binarySearch(paths, startIndex, endIndex, currentPath + '\u0000'); + if (hi < 0) { + hi = -(hi + 1); + } + + return Arrays.asList(contents).subList(startIndex, hi); + } + + @Override + public boolean isEmpty() { + return startIndex >= endIndex; + } + + @Override + public TypeAnnotationBank getBank(TypeReference reference) { + if (targets == null) { + throw new IllegalStateException(); + } + + int target = reference.getValue(); + // inclusive low + int low = Arrays.binarySearch(targets, startIndex, endIndex, target); + if (low < 0) { + low = -(low + 1); + } + + // exclusive hi + int hi = Arrays.binarySearch(targets, startIndex, endIndex, target + 1); + if (hi < 0) { + hi = -(hi + 1); + } + + return new TypeAnnotationStorage(low, hi, "", null, paths, contents); + } + + public static final class Builder { + + final List entries = new ArrayList<>(); + + Builder() { + } + + public Builder add(int typeReference, String typePath, AnnotationSpec spec) { + entries.add(new Entry(typeReference, typePath, spec)); + return this; + } + + public Builder add(Iterable nodes) { + if (nodes == null) { + return this; // thanks asm + } + for (TypeAnnotationNode node : nodes) { + entries.add(new Entry(node.typeRef, node.typePath == null ? "" : node.typePath.toString(), FieldBuilder.parseAnnotation(node))); + } + return this; + } + + public TypeAnnotationMapping build() { + this.entries.sort(null); + int len = this.entries.size(); + + int[] targets = new int[len]; + String[] paths = new String[len]; + AnnotationSpec[] contents = new AnnotationSpec[len]; + + Iterator itr = this.entries.iterator(); + for (int i = 0; i < len; i++) { + Entry entry = itr.next(); + targets[i] = entry.target; + paths[i] = entry.path; + contents[i] = entry.content; + } + + return new TypeAnnotationStorage(0, len, null, targets, paths, contents); + } + + private static final class Entry implements Comparable { + final int target; + final String path; + final AnnotationSpec content; + + Entry(int target, String path, AnnotationSpec content) { + this.target = target; + this.path = path; + this.content = content; + } + + @Override + public int compareTo(Entry o) { + int c0 = Integer.compare(target, o.target); + if (c0 != 0) return c0; + return path.compareTo(o.path); + } + } + + } +} diff --git a/src/main/resources/copy_on_click.js b/src/main/resources/copy_on_click.js new file mode 100644 index 0000000..a70c7e3 --- /dev/null +++ b/src/main/resources/copy_on_click.js @@ -0,0 +1,19 @@ +/* https://stackoverflow.com/a/45071478 */ +/* doesn't work yet */ +const items = document.querySelectorAll("span"); + +items.forEach(item => { + item.onclick = function() { + item.select(); + item.setSelectionRange(0, 1048576); + document.execCommand("copy"); + }; +}); + +items.forEach(item => { + item.addEventListener("copy", function(event) { + event.preventDefault(); + event.clipboardData.setData("text/plain", span.textContent); + console.log(event.clipboardData.getData("text")); + }) +}); diff --git a/src/test/java/net/fabricmc/mappingpoet/BorkAnno.java b/src/test/java/net/fabricmc/mappingpoet/BorkAnno.java new file mode 100644 index 0000000..1e13873 --- /dev/null +++ b/src/test/java/net/fabricmc/mappingpoet/BorkAnno.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2020 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.mappingpoet; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Documented +@Target(ElementType.PARAMETER) +@Retention(RetentionPolicy.RUNTIME) +public @interface BorkAnno { +} diff --git a/src/test/java/net/fabricmc/mappingpoet/SignaturesTest.java b/src/test/java/net/fabricmc/mappingpoet/SignaturesTest.java index 810d073..026c10a 100644 --- a/src/test/java/net/fabricmc/mappingpoet/SignaturesTest.java +++ b/src/test/java/net/fabricmc/mappingpoet/SignaturesTest.java @@ -32,6 +32,14 @@ import com.squareup.javapoet.WildcardTypeName; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import org.objectweb.asm.signature.SignatureReader; + +import net.fabricmc.mappingpoet.signature.ClassSignature; +import net.fabricmc.mappingpoet.signature.MethodSignature; +import net.fabricmc.mappingpoet.signature.PoetClassMethodSignatureVisitor; +import net.fabricmc.mappingpoet.signature.PoetTypeSignatureWriter; +import net.fabricmc.mappingpoet.signature.TypeAnnotationBank; +import net.fabricmc.mappingpoet.signature.TypeAnnotationMapping; public class SignaturesTest { @@ -44,6 +52,10 @@ public void testRandomMapType() { Assertions.assertEquals(85, result.getKey().intValue()); Assertions.assertEquals("java.util.Map[]>, double[][][]>", result.getValue().toString()); + + PoetTypeSignatureWriter writer = new PoetTypeSignatureWriter(TypeAnnotationBank.EMPTY, s -> false); + new SignatureReader(signature).acceptType(writer); + Assertions.assertEquals("java.util.Map[]>, double[][][]>", writer.compute().toString()); } @Test @@ -73,6 +85,10 @@ public void soo() { Assertions.assertEquals(322, result.getKey().intValue()); Assertions.assertEquals("net.fabricmc.mappingpoet.TestOuter.Inner, java.net.URLClassLoader>.ExtraInner, java.lang.Integer, java.net.URLClassLoader>>>>", result.getValue().toString()); + + PoetTypeSignatureWriter writer = new PoetTypeSignatureWriter(TypeAnnotationBank.EMPTY, s -> false); + new SignatureReader(signature).acceptType(writer); + Assertions.assertEquals("net.fabricmc.mappingpoet.TestOuter.Inner, java.net.URLClassLoader>.ExtraInner, java.lang.Integer, java.net.URLClassLoader>>>>", writer.compute().toString()); } @Test @@ -86,6 +102,10 @@ public void arrSoo() { Assertions.assertEquals(324, result.getKey().intValue()); Assertions.assertEquals("net.fabricmc.mappingpoet.TestOuter.Inner, java.net.URLClassLoader>.ExtraInner, java.lang.Integer, java.net.URLClassLoader>>>>[][]", result.getValue().toString()); + + PoetTypeSignatureWriter writer = new PoetTypeSignatureWriter(TypeAnnotationBank.EMPTY, s -> false); + new SignatureReader(arraySignature).acceptType(writer); + Assertions.assertEquals("net.fabricmc.mappingpoet.TestOuter.Inner, java.net.URLClassLoader>.ExtraInner, java.lang.Integer, java.net.URLClassLoader>>>>[][]", writer.compute().toString()); } @Test @@ -97,7 +117,20 @@ public void testClassDeeSignature() { Assertions.assertEquals(102, dBound.getKey().intValue()); Assertions.assertEquals("java.util.function.UnaryOperator>>", dBound.getValue().toString()); - Signatures.ClassSignature parsed = Signatures.parseClassSignature(classSig); + ClassSignature parsed = Signatures.parseClassSignature(classSig); + Assertions.assertIterableEquals(Collections.singleton(TypeVariableName.get("D")), parsed.generics); + Assertions.assertEquals(ClassName.OBJECT, parsed.superclass); + Assertions.assertIterableEquals(Collections.emptyList(), parsed.superinterfaces); + } + + @Test + public void testClassDeeSignatureVisitor() { + // signature ;>;>;>Ljava/lang/Object; + String classSig = ";>;>;>Ljava/lang/Object;"; + + PoetClassMethodSignatureVisitor visitor = new PoetClassMethodSignatureVisitor(TypeAnnotationMapping.EMPTY, s -> false, true); + new SignatureReader(classSig).accept(visitor); + ClassSignature parsed = visitor.collectClass(); Assertions.assertIterableEquals(Collections.singleton(TypeVariableName.get("D")), parsed.generics); Assertions.assertEquals(ClassName.OBJECT, parsed.superclass); Assertions.assertIterableEquals(Collections.emptyList(), parsed.superinterfaces); @@ -107,7 +140,7 @@ public void testClassDeeSignature() { public void testCollectionIntFunctionToArraySignature() { // signature (Ljava/util/function/IntFunction<[TT;>;)[TT; String methodSignature = "(Ljava/util/function/IntFunction<[TT;>;)[TT;"; - Signatures.MethodSignature parsed = Signatures.parseMethodSignature(methodSignature); + MethodSignature parsed = Signatures.parseMethodSignature(methodSignature); Assertions.assertIterableEquals(Collections.singleton(TypeVariableName.get("T")), parsed.generics); Assertions.assertEquals(ArrayTypeName.of(TypeVariableName.get("T")), parsed.result); Assertions.assertIterableEquals(Collections.emptyList(), parsed.thrown); @@ -118,7 +151,20 @@ public void testCollectionIntFunctionToArraySignature() { public void testCollectionArrayToArraySignature() { // signature ([TT;)[TT; String methodSignature = "([TT;)[TT;"; - Signatures.MethodSignature parsed = Signatures.parseMethodSignature(methodSignature); + MethodSignature parsed = Signatures.parseMethodSignature(methodSignature); + Assertions.assertIterableEquals(Collections.singleton(TypeVariableName.get("T")), parsed.generics); + Assertions.assertEquals(ArrayTypeName.of(TypeVariableName.get("T")), parsed.result); + Assertions.assertIterableEquals(Collections.emptyList(), parsed.thrown); + Assertions.assertIterableEquals(Collections.singleton(ArrayTypeName.of(TypeVariableName.get("T"))), parsed.parameters); + } + + @Test + public void testCollectionArrayToArraySignatureVisitor() { + // signature ([TT;)[TT; + String methodSignature = "([TT;)[TT;"; + PoetClassMethodSignatureVisitor visitor = new PoetClassMethodSignatureVisitor(TypeAnnotationMapping.EMPTY, s -> false, false); + new SignatureReader(methodSignature).accept(visitor); + MethodSignature parsed = visitor.collectMethod(); Assertions.assertIterableEquals(Collections.singleton(TypeVariableName.get("T")), parsed.generics); Assertions.assertEquals(ArrayTypeName.of(TypeVariableName.get("T")), parsed.result); Assertions.assertIterableEquals(Collections.emptyList(), parsed.thrown); @@ -129,8 +175,23 @@ public void testCollectionArrayToArraySignature() { public void testTweakLastSignature() { // signature (Ljava/util/function/UnaryOperator;)V String methodSignature = "(Ljava/util/function/UnaryOperator;)V"; - Signatures.MethodSignature parsed = Signatures.parseMethodSignature(methodSignature); - Assertions.assertNull(parsed.generics); + MethodSignature parsed = Signatures.parseMethodSignature(methodSignature); + Assertions.assertTrue(parsed.generics.isEmpty()); + Assertions.assertEquals(TypeName.VOID, parsed.result); + Assertions.assertIterableEquals(Collections.emptyList(), parsed.thrown); + ClassName unaryOperatorClass = ClassName.get(UnaryOperator.class); + ClassName typeNameClass = ClassName.get(TypeName.class); + Assertions.assertIterableEquals(Collections.singleton(ParameterizedTypeName.get(unaryOperatorClass, typeNameClass)), parsed.parameters); + } + + @Test + public void testTweakLastSignatureVisitor() { + // signature (Ljava/util/function/UnaryOperator;)V + String methodSignature = "(Ljava/util/function/UnaryOperator;)V"; + PoetClassMethodSignatureVisitor visitor = new PoetClassMethodSignatureVisitor(TypeAnnotationMapping.EMPTY, s -> false, false); + new SignatureReader(methodSignature).accept(visitor); + MethodSignature parsed = visitor.collectMethod(); + Assertions.assertTrue(parsed.generics.isEmpty()); Assertions.assertEquals(TypeName.VOID, parsed.result); Assertions.assertIterableEquals(Collections.emptyList(), parsed.thrown); ClassName unaryOperatorClass = ClassName.get(UnaryOperator.class); @@ -142,7 +203,21 @@ public void testTweakLastSignature() { public void testCheckHeadSignature() { // signature (Lnet/fabricmc/mappingpoet/Signatures$HeadChecker;)V^TE; String raw = "(Lnet/fabricmc/mappingpoet/Signatures$HeadChecker;)V^TE;"; - Signatures.MethodSignature parsed = Signatures.parseMethodSignature(raw); + MethodSignature parsed = Signatures.parseMethodSignature(raw); + Assertions.assertIterableEquals(Collections.singleton(TypeVariableName.get("E", ClassName.get(Throwable.class))), parsed.generics); + ClassName headCheckerClass = ClassName.get(Signatures.class).nestedClass("HeadChecker"); + Assertions.assertIterableEquals(Collections.singleton(ParameterizedTypeName.get(headCheckerClass, TypeVariableName.get("E"))), parsed.parameters); + Assertions.assertEquals(TypeName.VOID, parsed.result); + Assertions.assertIterableEquals(Collections.singleton(TypeVariableName.get("E")), parsed.thrown); + } + + @Test + public void testCheckHeadSignatureVisitor() { + // signature (Lnet/fabricmc/mappingpoet/Signatures$HeadChecker;)V^TE; + String raw = "(Lnet/fabricmc/mappingpoet/Signatures$HeadChecker;)V^TE;"; + PoetClassMethodSignatureVisitor visitor = new PoetClassMethodSignatureVisitor(TypeAnnotationMapping.EMPTY, s -> false, false); + new SignatureReader(raw).accept(visitor); + MethodSignature parsed = visitor.collectMethod(); Assertions.assertIterableEquals(Collections.singleton(TypeVariableName.get("E", ClassName.get(Throwable.class))), parsed.generics); ClassName headCheckerClass = ClassName.get(Signatures.class).nestedClass("HeadChecker"); Assertions.assertIterableEquals(Collections.singleton(ParameterizedTypeName.get(headCheckerClass, TypeVariableName.get("E"))), parsed.parameters); @@ -162,5 +237,26 @@ public void testBrokenVariantSettingSignature() { ClassName mapClass = ClassName.get(Map.class); ParameterizedTypeName genericMap = ParameterizedTypeName.get(mapClass, wildcardVariantSetting, valueClass); Assertions.assertEquals(genericMap, parsed.getValue()); + + PoetTypeSignatureWriter writer = new PoetTypeSignatureWriter(TypeAnnotationBank.EMPTY, s -> false); + new SignatureReader(signature).acceptType(writer); + Assertions.assertEquals(genericMap, writer.compute()); + } + + @Test + public void testStaticOuters() { + Outer.MiddleStatic.@TestAnno InnerStatic instance = null; + + // https://docs.oracle.com/javase/specs/jvms/se15/html/jvms-4.html#jvms-4.7.20.2-220-B-A.1 + Outer.@TestAnno("a") MiddleStatic<@TestAnno("b") Object>.@TestAnno("c") Inner<@TestAnno("d") Integer> instance2 = new Outer.MiddleStatic<>().new Inner(); + + String input = "Lnet/fabricmc/mappingpoet/Outer$MiddleStatic.Inner;"; + + TypeName name = Signatures.parseFieldSignature(input); + Assertions.assertEquals("net.fabricmc.mappingpoet.Outer.MiddleStatic.Inner", name.toString()); + + PoetTypeSignatureWriter writer = new PoetTypeSignatureWriter(TypeAnnotationBank.EMPTY, s -> false); + new SignatureReader(input).acceptType(writer); + Assertions.assertEquals(name, writer.compute()); } } diff --git a/src/test/java/net/fabricmc/mappingpoet/TestAnno.java b/src/test/java/net/fabricmc/mappingpoet/TestAnno.java new file mode 100644 index 0000000..d9ce704 --- /dev/null +++ b/src/test/java/net/fabricmc/mappingpoet/TestAnno.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2020 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.mappingpoet; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE_USE) +public @interface TestAnno { + String value() default ""; +} diff --git a/src/test/java/net/fabricmc/mappingpoet/TestOuter.java b/src/test/java/net/fabricmc/mappingpoet/TestOuter.java index 79def97..3ea1468 100644 --- a/src/test/java/net/fabricmc/mappingpoet/TestOuter.java +++ b/src/test/java/net/fabricmc/mappingpoet/TestOuter.java @@ -21,6 +21,12 @@ import java.util.function.BiFunction; import java.util.function.UnaryOperator; +enum StupidEnum { + FIRST, + @TestAnno + SECOND; +} + // signature ;>Ljava/lang/Object; public class TestOuter> { @@ -28,7 +34,72 @@ public class TestOuter> { class Inner, C extends ClassLoader & AutoCloseable> { // signature ;>;>;>Ljava/lang/Object; class ExtraInner>>> { - + + ExtraInner(InnerInner.this) { + // constructor receiver example. Notice 'this' cannot receive parameter annos + } + + void work(Inner.@TestAnno("on extra inner") ExtraInnerthis, Inner<@TestAnno("pig") B, C> @TestAnno("lion") [][] @TestAnno("rat") [] arr) { + + } + + void work2(Inner<@TestAnno("on B") B, C>.ExtraInnerthis) { + } + } + } +} + +class Outer { + void eat(@BorkAnno @TestAnno MiddleTwo.InnerThree apple) { + } + + void eat(@BorkAnno MiddleStatic.@TestAnno InnerStatic apple) { + } + + static class MiddleStatic { + static class InnerStatic { + } + + class Inner { + } + } + + class MiddleTwo { + class InnerThree { + } + } +} + +class OuterTwo { + static class InnerOne { + class InnerTwo { + InnerTwo(InnerOnenet.fabricmc.mappingpoet.OuterTwo.InnerOne.this) { + + } + + void called(InnerTwo this, InnerTwo other) { + } + + class NestedThree { + void work(NestedThreethis, NestedThree other) { + } + } + } + } + + class InnerTwo { + class NestedThree { + void workSelf(@TestAnno("on myself!")NestedThree<@TestAnno("on my W") W>this) { + } + + void workSelf1(NestedThree<@TestAnno("on my W only") W>this) { + } + + void workSelf2(@TestAnno("on myself only")NestedThreethis) { + } + + void work(@TestAnno("on myself!")NestedThree<@TestAnno("on my W") W>this, NestedThree<@TestAnno("on their W") W> other) { + } } } } diff --git a/src/test/resources/dummy.tiny b/src/test/resources/dummy.tiny new file mode 100644 index 0000000..f6d17d6 --- /dev/null +++ b/src/test/resources/dummy.tiny @@ -0,0 +1,5 @@ +tiny 2 0 intermediary official named + notice This is an example to test functionalities! +c net/fabricmc/mappingpoet/Outer a net/fabricmc/mappingpoet/Outer + m (Lnet/fabricmc/mappingpoet/Outer$MiddleTwo$InnerThree;)V eaten ate eat +c net/hackingmc/fightingpoet/ZombieTest b net/fabricmc/mappingpoet/SignaturesTest From 3276281628a808e5cecb17832c0148386bc98e78 Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Wed, 23 Dec 2020 17:59:40 +0000 Subject: [PATCH 02/43] Release via github actions --- .github/workflows/build.yml | 15 +++++++++++++++ .github/workflows/release.yml | 16 ++++++++++++++++ .gitignore | 2 +- Jenkinsfile | 8 -------- build.gradle | 10 +++++----- 5 files changed, 37 insertions(+), 14 deletions(-) create mode 100644 .github/workflows/build.yml create mode 100644 .github/workflows/release.yml delete mode 100644 Jenkinsfile diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..abfe06e --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,15 @@ +name: Build +on: [push, pull_request] +jobs: + build: + strategy: + matrix: + java: [11-jdk, 15-jdk] + runs-on: ubuntu-20.04 + container: + image: openjdk:${{ matrix.java }} + options: --user root + steps: + - uses: actions/checkout@v1 + - uses: gradle/wrapper-validation-action@v1 + - run: ./gradlew build test --stacktrace \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..de66787 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,16 @@ +name: Release +on: [workflow_dispatch] # Manual trigger +jobs: + build: + runs-on: ubuntu-20.04 + container: + image: openjdk:11-jdk + options: --user root + steps: + - uses: actions/checkout@v1 + - uses: gradle/wrapper-validation-action@v1 + - run: ./gradlew checkVersion build publish --stacktrace + env: + MAVEN_URL: ${{ secrets.MAVEN_URL }} + MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }} + MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }} diff --git a/.gitignore b/.gitignore index 4c3eb58..f5f7c31 100644 --- a/.gitignore +++ b/.gitignore @@ -14,4 +14,4 @@ !/settings.gradle !/LICENSE !/HEADER -!/Jenkinsfile \ No newline at end of file +!/.github \ No newline at end of file diff --git a/Jenkinsfile b/Jenkinsfile deleted file mode 100644 index e3b3600..0000000 --- a/Jenkinsfile +++ /dev/null @@ -1,8 +0,0 @@ -node { - stage 'Checkout' - checkout scm - - stage 'Build' - sh "chmod +x gradlew" - sh "./gradlew clean build publish --stacktrace" -} \ No newline at end of file diff --git a/build.gradle b/build.gradle index 4a3beca..c692ec4 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ group 'net.fabricmc' version '0.2.0' def ENV = System.getenv() -version = version + "+" + (ENV.BUILD_NUMBER ? ("build." + ENV.BUILD_NUMBER) : "local") +version = version + (ENV.GITHUB_ACTIONS ? "" : "+local") repositories { mavenCentral() @@ -73,12 +73,12 @@ publishing { // select the repositories you want to publish to repositories { - if (project.hasProperty('mavenPass')) { + if (ENV.MAVEN_URL) { maven { - url = "http://mavenupload.modmuss50.me/" + url ENV.MAVEN_URL credentials { - username = "buildslave" - password = project.getProperty('mavenPass') + username ENV.MAVEN_USERNAME + password ENV.MAVEN_PASSWORD } } } From 54e8ec2fd3b35b19e4d155b0fb3b63ff39d28185 Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Wed, 23 Dec 2020 18:00:33 +0000 Subject: [PATCH 03/43] Add checkVersion task --- build.gradle | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/build.gradle b/build.gradle index c692ec4..c01ae95 100644 --- a/build.gradle +++ b/build.gradle @@ -84,3 +84,17 @@ publishing { } } } + +// A task to ensure that the version being released has not already been released. +task checkVersion { + doFirst { + def xml = new URL("https://maven.fabricmc.net/net/fabricmc/mappingpoet/maven-metadata.xml").text + def metadata = new XmlSlurper().parseText(xml) + def versions = metadata.versioning.versions.version*.text(); + if (versions.contains(version)) { + throw new RuntimeException("${version} has already been released!") + } + } +} + +publish.mustRunAfter checkVersion \ No newline at end of file From 9abf2a8efe35fcad9f54469a1916ff6b96509ecb Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Wed, 23 Dec 2020 18:01:59 +0000 Subject: [PATCH 04/43] Make gradlew executable --- .github/workflows/build.yml | 1 + .github/workflows/release.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index abfe06e..40983ff 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,4 +12,5 @@ jobs: steps: - uses: actions/checkout@v1 - uses: gradle/wrapper-validation-action@v1 + - run: chmod +x ./gradlew - run: ./gradlew build test --stacktrace \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index de66787..96eae5f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -9,6 +9,7 @@ jobs: steps: - uses: actions/checkout@v1 - uses: gradle/wrapper-validation-action@v1 + - run: chmod +x ./gradlew - run: ./gradlew checkVersion build publish --stacktrace env: MAVEN_URL: ${{ secrets.MAVEN_URL }} From 757d21c16b569f0401fb990897cfcf3fb877de80 Mon Sep 17 00:00:00 2001 From: i509VCB Date: Wed, 23 Dec 2020 15:22:34 -0600 Subject: [PATCH 05/43] Mixin selector go brr --- src/main/java/net/fabricmc/mappingpoet/jd/MappingTaglet.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/net/fabricmc/mappingpoet/jd/MappingTaglet.java b/src/main/java/net/fabricmc/mappingpoet/jd/MappingTaglet.java index 98cbd34..a036a04 100644 --- a/src/main/java/net/fabricmc/mappingpoet/jd/MappingTaglet.java +++ b/src/main/java/net/fabricmc/mappingpoet/jd/MappingTaglet.java @@ -70,7 +70,7 @@ public String toString(List tags, Element element) { builder.append("Namespace\n"); builder.append("Name\n"); if (!typeDecl) { - builder.append("Mixin form\n"); + builder.append("Mixin selector\n"); } builder.append("\n"); builder.append("\n"); From 4c1c8b951fb2f9c777ae31fbbca2bdda25a71404 Mon Sep 17 00:00:00 2001 From: liach <7806504+liach@users.noreply.github.com> Date: Wed, 23 Dec 2020 16:48:28 -0600 Subject: [PATCH 06/43] Bump version, thanks i509vcb --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index c01ae95..381341d 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ plugins { } group 'net.fabricmc' -version '0.2.0' +version '0.2.1' def ENV = System.getenv() version = version + (ENV.GITHUB_ACTIONS ? "" : "+local") @@ -97,4 +97,4 @@ task checkVersion { } } -publish.mustRunAfter checkVersion \ No newline at end of file +publish.mustRunAfter checkVersion From 9b7e91c91c3a8bddb0edacca9356032b8eab635a Mon Sep 17 00:00:00 2001 From: altrisi Date: Thu, 24 Dec 2020 17:23:51 +0100 Subject: [PATCH 07/43] Make mappings table match javadoc style and remove deprecated attributes (#10) --- .../fabricmc/mappingpoet/jd/MappingTaglet.java | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/main/java/net/fabricmc/mappingpoet/jd/MappingTaglet.java b/src/main/java/net/fabricmc/mappingpoet/jd/MappingTaglet.java index a036a04..e7a2627 100644 --- a/src/main/java/net/fabricmc/mappingpoet/jd/MappingTaglet.java +++ b/src/main/java/net/fabricmc/mappingpoet/jd/MappingTaglet.java @@ -63,14 +63,13 @@ public String getName() { public String toString(List tags, Element element) { boolean typeDecl = element instanceof TypeElement; // means it's a class, itf, enum, etc. StringBuilder builder = new StringBuilder(); - builder.append("

Mapping data

\n"); - builder.append("\n"); - builder.append("\n"); + builder.append("

Mapping data

\n"); + builder.append("
\n"); builder.append("\n"); - builder.append("\n"); - builder.append("\n"); + builder.append("\n"); + builder.append("\n"); if (!typeDecl) { - builder.append("\n"); + builder.append("\n"); } builder.append("\n"); builder.append("\n"); @@ -79,10 +78,10 @@ public String toString(List tags, Element element) { String body = ((UnknownBlockTagTree) each).getContent().stream().map(t -> ((LiteralTree) t).getBody().getBody()).collect(Collectors.joining()); String[] ans = body.split(":", 3); builder.append("\n"); - builder.append(String.format("\n", escaped(ans[0]))); + builder.append(String.format("\n", escaped(ans[0]))); final int bound = typeDecl ? 2 : 3; for (int i = 1; i < bound; i++) { - builder.append(String.format("\n", escaped(ans[i]))); + builder.append(String.format("\n", escaped(ans[i]))); } builder.append("\n"); } From 982f4a0aead74e6f75ddcb85f5ec664feb5462c9 Mon Sep 17 00:00:00 2001 From: altrisi Date: Thu, 24 Dec 2020 17:32:54 +0100 Subject: [PATCH 08/43] Copy the mapping table items on click (#9) * Copy the mapping table items on click * Set title programatically, add cursor pointer effect --- .../mappingpoet/jd/MappingTaglet.java | 4 +-- src/main/resources/copy_on_click.js | 36 +++++++++---------- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/src/main/java/net/fabricmc/mappingpoet/jd/MappingTaglet.java b/src/main/java/net/fabricmc/mappingpoet/jd/MappingTaglet.java index e7a2627..3abaa57 100644 --- a/src/main/java/net/fabricmc/mappingpoet/jd/MappingTaglet.java +++ b/src/main/java/net/fabricmc/mappingpoet/jd/MappingTaglet.java @@ -81,7 +81,7 @@ public String toString(List tags, Element element) { builder.append(String.format("\n", escaped(ans[0]))); final int bound = typeDecl ? 2 : 3; for (int i = 1; i < bound; i++) { - builder.append(String.format("\n", escaped(ans[i]))); + builder.append(String.format("\n", escaped(ans[i]))); } builder.append("\n"); } @@ -89,7 +89,7 @@ public String toString(List tags, Element element) { builder.append("\n"); builder.append("
NamespaceNameNamespaceNameMixin selectorMixin selector
%s%s%s%s
%s%s%s
\n"); builder.append("\n"); return builder.toString(); } diff --git a/src/main/resources/copy_on_click.js b/src/main/resources/copy_on_click.js index a70c7e3..23abc57 100644 --- a/src/main/resources/copy_on_click.js +++ b/src/main/resources/copy_on_click.js @@ -1,19 +1,17 @@ -/* https://stackoverflow.com/a/45071478 */ -/* doesn't work yet */ -const items = document.querySelectorAll("span"); - -items.forEach(item => { - item.onclick = function() { - item.select(); - item.setSelectionRange(0, 1048576); - document.execCommand("copy"); - }; -}); - -items.forEach(item => { - item.addEventListener("copy", function(event) { - event.preventDefault(); - event.clipboardData.setData("text/plain", span.textContent); - console.log(event.clipboardData.getData("text")); - }) -}); +document.onreadystatechange = function() { + if(document.readyState == "complete") { + const items = document.querySelectorAll(".copyable"); + items.forEach(item => { + item.title = "Click to copy"; + item.style["cursor"] = "pointer"; + item.onclick = function() { + var range = document.createRange(); + range.selectNode(item); + window.getSelection().addRange(range); + document.execCommand("copy"); + window.getSelection().removeRange(range); + console.log("Copied to clipboard"); + }; + }); + } +}; From 01e9d6a8dd5c10240f0b09cc5807b2fd37bfd621 Mon Sep 17 00:00:00 2001 From: liach Date: Thu, 24 Dec 2020 17:39:07 -0600 Subject: [PATCH 09/43] 0.2.2 Update html class reference to that of java 15 include js only once each class page Signed-off-by: liach --- build.gradle | 2 +- .../mappingpoet/jd/MappingTaglet.java | 33 +++++++++++-------- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/build.gradle b/build.gradle index 381341d..8bc3fe7 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ plugins { } group 'net.fabricmc' -version '0.2.1' +version '0.2.2' def ENV = System.getenv() version = version + (ENV.GITHUB_ACTIONS ? "" : "+local") diff --git a/src/main/java/net/fabricmc/mappingpoet/jd/MappingTaglet.java b/src/main/java/net/fabricmc/mappingpoet/jd/MappingTaglet.java index 3abaa57..1e0ff27 100644 --- a/src/main/java/net/fabricmc/mappingpoet/jd/MappingTaglet.java +++ b/src/main/java/net/fabricmc/mappingpoet/jd/MappingTaglet.java @@ -63,34 +63,39 @@ public String getName() { public String toString(List tags, Element element) { boolean typeDecl = element instanceof TypeElement; // means it's a class, itf, enum, etc. StringBuilder builder = new StringBuilder(); - builder.append("

Mapping data

\n"); - builder.append("\n"); + builder.append("
Mappings:
\n"); + // Java 15 required for style consistency + builder.append("
\n"); builder.append("\n"); - builder.append("\n"); - builder.append("\n"); + builder.append("\n"); + builder.append("\n"); if (!typeDecl) { - builder.append("\n"); + builder.append("\n"); } builder.append("\n"); builder.append("\n"); + boolean altColor = true; for (DocTree each : tags) { String body = ((UnknownBlockTagTree) each).getContent().stream().map(t -> ((LiteralTree) t).getBody().getBody()).collect(Collectors.joining()); String[] ans = body.split(":", 3); - builder.append("\n"); - builder.append(String.format("\n", escaped(ans[0]))); - final int bound = typeDecl ? 2 : 3; - for (int i = 1; i < bound; i++) { - builder.append(String.format("\n", escaped(ans[i]))); + builder.append("\n"); + builder.append(String.format("\n", escaped(ans[0]))); + builder.append(String.format("\n", escaped(ans[1]))); + if (!typeDecl) { + builder.append(String.format("\n", escaped(ans[2]))); } builder.append("\n"); + altColor = !altColor; } builder.append("\n"); - builder.append("
NamespaceNameNamespaceNameMixin selectorMixin selector
%s%s
%s%s%s
\n"); - builder.append("\n"); + builder.append("\n"); + if (typeDecl) { + builder.append("\n"); + } return builder.toString(); } From 9ca22d4ab3a5504d34502aed270c5b67cbe586ad Mon Sep 17 00:00:00 2001 From: liach Date: Fri, 8 Jan 2021 00:39:33 -0600 Subject: [PATCH 10/43] Move the copy on click script to yarn Signed-off-by: liach --- build.gradle | 200 +++++++-------- .../mappingpoet/jd/MappingTaglet.java | 232 ++++++++---------- src/main/resources/copy_on_click.js | 17 -- 3 files changed, 203 insertions(+), 246 deletions(-) delete mode 100644 src/main/resources/copy_on_click.js diff --git a/build.gradle b/build.gradle index 8bc3fe7..e19cb4c 100644 --- a/build.gradle +++ b/build.gradle @@ -1,100 +1,100 @@ -plugins { - id 'java' - id 'java-library' - id 'maven-publish' - id("org.cadixdev.licenser") version "0.5.0" -} - -group 'net.fabricmc' -version '0.2.2' - -def ENV = System.getenv() -version = version + (ENV.GITHUB_ACTIONS ? "" : "+local") - -repositories { - mavenCentral() - maven { - name = 'Fabric' - url = 'https://maven.modmuss50.me/' - } -} - -dependencies { - implementation 'com.squareup:javapoet:1.13.0' - implementation 'net.fabricmc:tiny-mappings-parser:0.3.0+build.17' - runtimeOnly 'com.google.guava:guava:28.2-jre' - - implementation 'org.ow2.asm:asm:9.0' - implementation 'org.ow2.asm:asm-analysis:9.0' - implementation 'org.ow2.asm:asm-commons:9.0' - implementation 'org.ow2.asm:asm-tree:9.0' - implementation 'org.ow2.asm:asm-util:9.0' - - testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0' -} - -java { - withSourcesJar() - toolchain { - languageVersion.set(JavaLanguageVersion.of(11)) - } -} - -test { - useJUnitPlatform() -} - -tasks.withType(Jar) { - from("LICENSE") { - rename { "${it}_${project.archivesBaseName}" } - } -} - -jar { - manifest { - attributes 'Implementation-Title': 'MappingPoet', - 'Implementation-Version': archiveVersion, - 'Main-Class': "net.fabricmc.mappingpoet.Main" - } -} - -license { - header file("HEADER") - include '**/*.java' -} - -publishing { - publications { - mavenJava(MavenPublication) { - from components.java - } - } - - // select the repositories you want to publish to - repositories { - if (ENV.MAVEN_URL) { - maven { - url ENV.MAVEN_URL - credentials { - username ENV.MAVEN_USERNAME - password ENV.MAVEN_PASSWORD - } - } - } - } -} - -// A task to ensure that the version being released has not already been released. -task checkVersion { - doFirst { - def xml = new URL("https://maven.fabricmc.net/net/fabricmc/mappingpoet/maven-metadata.xml").text - def metadata = new XmlSlurper().parseText(xml) - def versions = metadata.versioning.versions.version*.text(); - if (versions.contains(version)) { - throw new RuntimeException("${version} has already been released!") - } - } -} - -publish.mustRunAfter checkVersion +plugins { + id 'java' + id 'java-library' + id 'maven-publish' + id("org.cadixdev.licenser") version "0.5.0" +} + +group 'net.fabricmc' +version '0.2.3' + +def ENV = System.getenv() +version = version + (ENV.GITHUB_ACTIONS ? "" : "+local") + +repositories { + mavenCentral() + maven { + name = 'Fabric' + url = 'https://maven.modmuss50.me/' + } +} + +dependencies { + implementation 'com.squareup:javapoet:1.13.0' + implementation 'net.fabricmc:tiny-mappings-parser:0.3.0+build.17' + runtimeOnly 'com.google.guava:guava:28.2-jre' + + implementation 'org.ow2.asm:asm:9.0' + implementation 'org.ow2.asm:asm-analysis:9.0' + implementation 'org.ow2.asm:asm-commons:9.0' + implementation 'org.ow2.asm:asm-tree:9.0' + implementation 'org.ow2.asm:asm-util:9.0' + + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0' +} + +java { + withSourcesJar() + toolchain { + languageVersion.set(JavaLanguageVersion.of(11)) + } +} + +test { + useJUnitPlatform() +} + +tasks.withType(Jar) { + from("LICENSE") { + rename { "${it}_${project.archivesBaseName}" } + } +} + +jar { + manifest { + attributes 'Implementation-Title': 'MappingPoet', + 'Implementation-Version': archiveVersion, + 'Main-Class': "net.fabricmc.mappingpoet.Main" + } +} + +license { + header file("HEADER") + include '**/*.java' +} + +publishing { + publications { + mavenJava(MavenPublication) { + from components.java + } + } + + // select the repositories you want to publish to + repositories { + if (ENV.MAVEN_URL) { + maven { + url ENV.MAVEN_URL + credentials { + username ENV.MAVEN_USERNAME + password ENV.MAVEN_PASSWORD + } + } + } + } +} + +// A task to ensure that the version being released has not already been released. +task checkVersion { + doFirst { + def xml = new URL("https://maven.fabricmc.net/net/fabricmc/mappingpoet/maven-metadata.xml").text + def metadata = new XmlSlurper().parseText(xml) + def versions = metadata.versioning.versions.version*.text(); + if (versions.contains(version)) { + throw new RuntimeException("${version} has already been released!") + } + } +} + +publish.mustRunAfter checkVersion diff --git a/src/main/java/net/fabricmc/mappingpoet/jd/MappingTaglet.java b/src/main/java/net/fabricmc/mappingpoet/jd/MappingTaglet.java index 1e0ff27..dc76b1e 100644 --- a/src/main/java/net/fabricmc/mappingpoet/jd/MappingTaglet.java +++ b/src/main/java/net/fabricmc/mappingpoet/jd/MappingTaglet.java @@ -1,129 +1,103 @@ -/* - * Copyright (c) 2020 FabricMC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.fabricmc.mappingpoet.jd; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.UncheckedIOException; -import java.nio.charset.StandardCharsets; -import java.util.EnumSet; -import java.util.List; -import java.util.Objects; -import java.util.Set; -import java.util.stream.Collectors; - -import javax.lang.model.element.Element; -import javax.lang.model.element.TypeElement; - -import com.sun.source.doctree.DocTree; -import com.sun.source.doctree.LiteralTree; -import com.sun.source.doctree.UnknownBlockTagTree; -import jdk.javadoc.doclet.Taglet; - -@SuppressWarnings("unused") -public final class MappingTaglet implements Taglet { - - private static final String JS_CONTENT; - - public MappingTaglet() { - // Required by javadoc - } - - @Override - public Set getAllowedLocations() { - return EnumSet.of(Location.TYPE, Location.CONSTRUCTOR, Location.METHOD, Location.FIELD); - } - - @Override - public boolean isInlineTag() { - return false; - } - - @Override - public String getName() { - return "mapping"; - } - - @Override - public String toString(List tags, Element element) { - boolean typeDecl = element instanceof TypeElement; // means it's a class, itf, enum, etc. - StringBuilder builder = new StringBuilder(); - builder.append("
Mappings:
\n"); - // Java 15 required for style consistency - builder.append("
\n"); - builder.append("\n"); - builder.append("\n"); - builder.append("\n"); - if (!typeDecl) { - builder.append("\n"); - } - builder.append("\n"); - builder.append("\n"); - - boolean altColor = true; - for (DocTree each : tags) { - String body = ((UnknownBlockTagTree) each).getContent().stream().map(t -> ((LiteralTree) t).getBody().getBody()).collect(Collectors.joining()); - String[] ans = body.split(":", 3); - builder.append("\n"); - builder.append(String.format("\n", escaped(ans[0]))); - builder.append(String.format("\n", escaped(ans[1]))); - if (!typeDecl) { - builder.append(String.format("\n", escaped(ans[2]))); - } - builder.append("\n"); - altColor = !altColor; - } - - builder.append("\n"); - builder.append("
NamespaceNameMixin selector
%s%s%s
\n"); - if (typeDecl) { - builder.append("\n"); - } - return builder.toString(); - } - - // I hate - private static String escaped(String original) { - StringBuilder builder = new StringBuilder(original.length()); - final int len = original.length(); - for (int i = 0; i < len; i++) { - char c = original.charAt(i); - if (c > 127 || c == '"' || c == '\'' || c == '<' || c == '>' || c == '&') { - builder.append("&#").append((int) c).append(";"); - } else { - builder.append(c); - } - } - return builder.toString(); - } - - static { - StringBuilder sb = new StringBuilder(); - try (BufferedReader reader = new BufferedReader(new InputStreamReader(Objects.requireNonNull(MappingTaglet.class.getResourceAsStream("/copy_on_click.js"), "copy_on_click.js stream"), StandardCharsets.UTF_8))) { - String line; - while ((line = reader.readLine()) != null) { - sb.append(line).append("\n"); - } - } catch (IOException ex) { - throw new UncheckedIOException(ex); - } - JS_CONTENT = sb.toString(); - } -} +/* + * Copyright (c) 2020 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.mappingpoet.jd; + +import java.util.EnumSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; + +import com.sun.source.doctree.DocTree; +import com.sun.source.doctree.LiteralTree; +import com.sun.source.doctree.UnknownBlockTagTree; +import jdk.javadoc.doclet.Taglet; + +@SuppressWarnings("unused") +public final class MappingTaglet implements Taglet { + + public MappingTaglet() { + // Required by javadoc + } + + @Override + public Set getAllowedLocations() { + return EnumSet.of(Location.TYPE, Location.CONSTRUCTOR, Location.METHOD, Location.FIELD); + } + + @Override + public boolean isInlineTag() { + return false; + } + + @Override + public String getName() { + return "mapping"; + } + + @Override + public String toString(List tags, Element element) { + boolean typeDecl = element instanceof TypeElement; // means it's a class, itf, enum, etc. + StringBuilder builder = new StringBuilder(); + builder.append("
Mappings:
\n"); + // Java 15 required for style consistency + builder.append("
\n"); + builder.append("\n"); + builder.append("\n"); + builder.append("\n"); + if (!typeDecl) { + builder.append("\n"); + } + builder.append("\n"); + builder.append("\n"); + + boolean altColor = true; + for (DocTree each : tags) { + String body = ((UnknownBlockTagTree) each).getContent().stream().map(t -> ((LiteralTree) t).getBody().getBody()).collect(Collectors.joining()); + String[] ans = body.split(":", 3); + builder.append("\n"); + builder.append(String.format("\n", escaped(ans[0]))); + builder.append(String.format("\n", escaped(ans[1]))); + if (!typeDecl) { + builder.append(String.format("\n", escaped(ans[2]))); + } + builder.append("\n"); + altColor = !altColor; + } + + builder.append("\n"); + builder.append("
NamespaceNameMixin selector
%s%s%s
\n"); + return builder.toString(); + } + + // I hate + private static String escaped(String original) { + StringBuilder builder = new StringBuilder(original.length()); + final int len = original.length(); + for (int i = 0; i < len; i++) { + char c = original.charAt(i); + if (c > 127 || c == '"' || c == '\'' || c == '<' || c == '>' || c == '&') { + builder.append("&#").append((int) c).append(";"); + } else { + builder.append(c); + } + } + return builder.toString(); + } +} diff --git a/src/main/resources/copy_on_click.js b/src/main/resources/copy_on_click.js deleted file mode 100644 index 23abc57..0000000 --- a/src/main/resources/copy_on_click.js +++ /dev/null @@ -1,17 +0,0 @@ -document.onreadystatechange = function() { - if(document.readyState == "complete") { - const items = document.querySelectorAll(".copyable"); - items.forEach(item => { - item.title = "Click to copy"; - item.style["cursor"] = "pointer"; - item.onclick = function() { - var range = document.createRange(); - range.selectNode(item); - window.getSelection().addRange(range); - document.execCommand("copy"); - window.getSelection().removeRange(range); - console.log("Copied to clipboard"); - }; - }); - } -}; From c3c3025b149b03a9f6481cf4356709ef06a592af Mon Sep 17 00:00:00 2001 From: liach Date: Sat, 9 Jan 2021 20:44:40 -0600 Subject: [PATCH 11/43] Put the copy on click and jd header bakc to mappingpoet. let yarn poll from jar Signed-off-by: liach --- build.gradle | 2 +- src/main/resources/copy_on_click.js | 17 +++++++++++++++++ src/main/resources/javadoc_header.txt | 1 + 3 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 src/main/resources/copy_on_click.js create mode 100644 src/main/resources/javadoc_header.txt diff --git a/build.gradle b/build.gradle index e19cb4c..046952c 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ plugins { } group 'net.fabricmc' -version '0.2.3' +version '0.2.4' def ENV = System.getenv() version = version + (ENV.GITHUB_ACTIONS ? "" : "+local") diff --git a/src/main/resources/copy_on_click.js b/src/main/resources/copy_on_click.js new file mode 100644 index 0000000..a8d140a --- /dev/null +++ b/src/main/resources/copy_on_click.js @@ -0,0 +1,17 @@ +document.onreadystatechange = function() { + if(document.readyState == "complete") { + const items = document.querySelectorAll(".copyable"); + items.forEach(item => { + item.title = "Click to copy"; + item.style["cursor"] = "pointer"; + item.onclick = function() { + var range = document.createRange(); + range.selectNode(item); + window.getSelection().addRange(range); + document.execCommand("copy"); + window.getSelection().removeRange(range); + console.log("Copied to clipboard"); + }; + }); + } +}; diff --git a/src/main/resources/javadoc_header.txt b/src/main/resources/javadoc_header.txt new file mode 100644 index 0000000..b71b01a --- /dev/null +++ b/src/main/resources/javadoc_header.txt @@ -0,0 +1 @@ + From 1d04eda64eac3f0c84db8abcd04a27d28ec4f81f Mon Sep 17 00:00:00 2001 From: liach Date: Wed, 20 Jan 2021 15:15:34 -0600 Subject: [PATCH 12/43] 0.2.5: Use builtin stylesheet (edited from that for fabricmc.net) Signed-off-by: liach --- build.gradle | 9 +- .../mappingpoet/jd/MappingTaglet.java | 203 +++++++++--------- src/main/resources/copy_on_click.js | 15 ++ src/main/resources/forms.css | 39 ++++ 4 files changed, 159 insertions(+), 107 deletions(-) create mode 100644 src/main/resources/forms.css diff --git a/build.gradle b/build.gradle index 046952c..86d7aac 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ plugins { } group 'net.fabricmc' -version '0.2.4' +version '0.2.5' def ENV = System.getenv() version = version + (ENV.GITHUB_ACTIONS ? "" : "+local") @@ -36,9 +36,10 @@ dependencies { java { withSourcesJar() - toolchain { - languageVersion.set(JavaLanguageVersion.of(11)) - } +} + +compileJava { + sourceCompatibility = targetCompatibility = JavaVersion.VERSION_1_11 } test { diff --git a/src/main/java/net/fabricmc/mappingpoet/jd/MappingTaglet.java b/src/main/java/net/fabricmc/mappingpoet/jd/MappingTaglet.java index dc76b1e..b2f07bd 100644 --- a/src/main/java/net/fabricmc/mappingpoet/jd/MappingTaglet.java +++ b/src/main/java/net/fabricmc/mappingpoet/jd/MappingTaglet.java @@ -1,103 +1,100 @@ -/* - * Copyright (c) 2020 FabricMC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.fabricmc.mappingpoet.jd; - -import java.util.EnumSet; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -import javax.lang.model.element.Element; -import javax.lang.model.element.TypeElement; - -import com.sun.source.doctree.DocTree; -import com.sun.source.doctree.LiteralTree; -import com.sun.source.doctree.UnknownBlockTagTree; -import jdk.javadoc.doclet.Taglet; - -@SuppressWarnings("unused") -public final class MappingTaglet implements Taglet { - - public MappingTaglet() { - // Required by javadoc - } - - @Override - public Set getAllowedLocations() { - return EnumSet.of(Location.TYPE, Location.CONSTRUCTOR, Location.METHOD, Location.FIELD); - } - - @Override - public boolean isInlineTag() { - return false; - } - - @Override - public String getName() { - return "mapping"; - } - - @Override - public String toString(List tags, Element element) { - boolean typeDecl = element instanceof TypeElement; // means it's a class, itf, enum, etc. - StringBuilder builder = new StringBuilder(); - builder.append("
Mappings:
\n"); - // Java 15 required for style consistency - builder.append("
\n"); - builder.append("\n"); - builder.append("\n"); - builder.append("\n"); - if (!typeDecl) { - builder.append("\n"); - } - builder.append("\n"); - builder.append("\n"); - - boolean altColor = true; - for (DocTree each : tags) { - String body = ((UnknownBlockTagTree) each).getContent().stream().map(t -> ((LiteralTree) t).getBody().getBody()).collect(Collectors.joining()); - String[] ans = body.split(":", 3); - builder.append("\n"); - builder.append(String.format("\n", escaped(ans[0]))); - builder.append(String.format("\n", escaped(ans[1]))); - if (!typeDecl) { - builder.append(String.format("\n", escaped(ans[2]))); - } - builder.append("\n"); - altColor = !altColor; - } - - builder.append("\n"); - builder.append("
NamespaceNameMixin selector
%s%s%s
\n"); - return builder.toString(); - } - - // I hate - private static String escaped(String original) { - StringBuilder builder = new StringBuilder(original.length()); - final int len = original.length(); - for (int i = 0; i < len; i++) { - char c = original.charAt(i); - if (c > 127 || c == '"' || c == '\'' || c == '<' || c == '>' || c == '&') { - builder.append("&#").append((int) c).append(";"); - } else { - builder.append(c); - } - } - return builder.toString(); - } -} +/* + * Copyright (c) 2020 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.mappingpoet.jd; + +import java.util.EnumSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; + +import com.sun.source.doctree.DocTree; +import com.sun.source.doctree.LiteralTree; +import com.sun.source.doctree.UnknownBlockTagTree; +import jdk.javadoc.doclet.Taglet; + +@SuppressWarnings("unused") +public final class MappingTaglet implements Taglet { + + public MappingTaglet() { + // Required by javadoc + } + + @Override + public Set getAllowedLocations() { + return EnumSet.of(Location.TYPE, Location.CONSTRUCTOR, Location.METHOD, Location.FIELD); + } + + @Override + public boolean isInlineTag() { + return false; + } + + @Override + public String getName() { + return "mapping"; + } + + @Override + public String toString(List tags, Element element) { + boolean typeDecl = element instanceof TypeElement; // means it's a class, itf, enum, etc. + StringBuilder builder = new StringBuilder(); + builder.append("
Mappings:
\n"); + builder.append("
\n"); + builder.append("\n"); + builder.append("\n"); + builder.append("\n"); + if (!typeDecl) { + builder.append("\n"); + } + builder.append("\n"); + builder.append("\n"); + + for (DocTree each : tags) { + String body = ((UnknownBlockTagTree) each).getContent().stream().map(t -> ((LiteralTree) t).getBody().getBody()).collect(Collectors.joining()); + String[] ans = body.split(":", 3); + builder.append("\n"); + builder.append(String.format("\n", escaped(ans[0]))); + builder.append(String.format("\n", escaped(ans[1]))); + if (!typeDecl) { + builder.append(String.format("\n", escaped(ans[2]))); + } + builder.append("\n"); + } + + builder.append("\n"); + builder.append("
NamespaceNameMixin selector
%s%s%s
\n"); + return builder.toString(); + } + + // I hate + private static String escaped(String original) { + StringBuilder builder = new StringBuilder(original.length()); + final int len = original.length(); + for (int i = 0; i < len; i++) { + char c = original.charAt(i); + if (c > 127 || c == '"' || c == '\'' || c == '<' || c == '>' || c == '&') { + builder.append("&#").append((int) c).append(";"); + } else { + builder.append(c); + } + } + return builder.toString(); + } +} diff --git a/src/main/resources/copy_on_click.js b/src/main/resources/copy_on_click.js index a8d140a..8326470 100644 --- a/src/main/resources/copy_on_click.js +++ b/src/main/resources/copy_on_click.js @@ -1,3 +1,18 @@ +/* + * Copyright (c) 2020 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ document.onreadystatechange = function() { if(document.readyState == "complete") { const items = document.querySelectorAll(".copyable"); diff --git a/src/main/resources/forms.css b/src/main/resources/forms.css new file mode 100644 index 0000000..bb1e311 --- /dev/null +++ b/src/main/resources/forms.css @@ -0,0 +1,39 @@ +.fabric { + font: 400 14px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; + color: #111; + background-color: #fdfdfd; + -webkit-text-size-adjust: 100%; + -webkit-font-feature-settings: "kern" 1; + -moz-font-feature-settings: "kern" 1; + -o-font-feature-settings: "kern" 1; + font-feature-settings: "kern" 1; + font-kerning: normal; + display: flex; + flex-direction: column; +} + +.fabric table { + width: 100%; + text-align: left; + color: #3f3f3f; + border-collapse: collapse; + border: 1px solid #e8e8e8; +} + +.fabric table tr:nth-child(even) { + background-color: #f7f7f7; +} + +.fabric table th, table td { + padding: 1px 10px; +} + +.fabric table th { + background-color: #f0f0f0; + border: 1px solid #dedede; + border-bottom-color: #c9c9c9; +} + +.fabric table td { + border: 1px solid #e8e8e8; +} From 527ce061e1548ae37f96574a105b99b27c23d3ec Mon Sep 17 00:00:00 2001 From: liach Date: Wed, 20 Jan 2021 15:21:54 -0600 Subject: [PATCH 13/43] typo --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 86d7aac..fdb9ad0 100644 --- a/build.gradle +++ b/build.gradle @@ -39,7 +39,7 @@ java { } compileJava { - sourceCompatibility = targetCompatibility = JavaVersion.VERSION_1_11 + sourceCompatibility = targetCompatibility = JavaVersion.VERSION_11 } test { From ba8e7f676a84843ea6747051a45fe5a4c7d83fbc Mon Sep 17 00:00:00 2001 From: liach Date: Wed, 20 Jan 2021 16:44:30 -0600 Subject: [PATCH 14/43] Fixes #12 Signed-off-by: liach --- build.gradle | 2 +- src/main/java/net/fabricmc/mappingpoet/MethodBuilder.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index fdb9ad0..eb9a513 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ plugins { } group 'net.fabricmc' -version '0.2.5' +version '0.2.6' def ENV = System.getenv() version = version + (ENV.GITHUB_ACTIONS ? "" : "+local") diff --git a/src/main/java/net/fabricmc/mappingpoet/MethodBuilder.java b/src/main/java/net/fabricmc/mappingpoet/MethodBuilder.java index 0530d42..4ab40f9 100644 --- a/src/main/java/net/fabricmc/mappingpoet/MethodBuilder.java +++ b/src/main/java/net/fabricmc/mappingpoet/MethodBuilder.java @@ -288,7 +288,7 @@ private void getParams(List paramTypes, boolean instance, Set } private void addExceptions() { - if (signature != null) { + if (signature != null && !signature.thrown.isEmpty()) { for (TypeName each : signature.thrown) { builder.addException(each); } From ccf6adf88d85d4a5bdbf118a18f8b6a313d5a3a4 Mon Sep 17 00:00:00 2001 From: liach Date: Wed, 20 Jan 2021 16:58:45 -0600 Subject: [PATCH 15/43] This appears to fix #13 Signed-off-by: liach --- src/main/java/net/fabricmc/mappingpoet/MappingsStore.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/fabricmc/mappingpoet/MappingsStore.java b/src/main/java/net/fabricmc/mappingpoet/MappingsStore.java index 40a61ac..bc01f5a 100644 --- a/src/main/java/net/fabricmc/mappingpoet/MappingsStore.java +++ b/src/main/java/net/fabricmc/mappingpoet/MappingsStore.java @@ -154,8 +154,13 @@ public void addMethodDoc(BiConsumer addJavadoc, Function Date: Mon, 22 Feb 2021 14:29:30 -0600 Subject: [PATCH 16/43] Fixes #14 --- build.gradle | 10 +++--- gradle/wrapper/gradle-wrapper.properties | 2 +- .../fabricmc/mappingpoet/MappingsStore.java | 33 ++++++++++--------- 3 files changed, 24 insertions(+), 21 deletions(-) diff --git a/build.gradle b/build.gradle index eb9a513..56582d1 100644 --- a/build.gradle +++ b/build.gradle @@ -24,11 +24,11 @@ dependencies { implementation 'net.fabricmc:tiny-mappings-parser:0.3.0+build.17' runtimeOnly 'com.google.guava:guava:28.2-jre' - implementation 'org.ow2.asm:asm:9.0' - implementation 'org.ow2.asm:asm-analysis:9.0' - implementation 'org.ow2.asm:asm-commons:9.0' - implementation 'org.ow2.asm:asm-tree:9.0' - implementation 'org.ow2.asm:asm-util:9.0' + implementation 'org.ow2.asm:asm:9.1' + implementation 'org.ow2.asm:asm-analysis:9.1' + implementation 'org.ow2.asm:asm-commons:9.1' + implementation 'org.ow2.asm:asm-tree:9.1' + implementation 'org.ow2.asm:asm-util:9.1' testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0' diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 4d9ca16..442d913 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/src/main/java/net/fabricmc/mappingpoet/MappingsStore.java b/src/main/java/net/fabricmc/mappingpoet/MappingsStore.java index bc01f5a..cf87506 100644 --- a/src/main/java/net/fabricmc/mappingpoet/MappingsStore.java +++ b/src/main/java/net/fabricmc/mappingpoet/MappingsStore.java @@ -25,7 +25,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.function.BiConsumer; import java.util.function.Function; import net.fabricmc.mapping.tree.ClassDef; @@ -78,23 +77,23 @@ public String getClassDoc(String className) { return classDef != null ? classDef.getComment() : null; } - private void addDoc(Mapped element, BiConsumer addJavadoc) { + private void addDoc(Mapped element, DocAdder adder) { String doc = element.getComment(); if (doc != null) { - addJavadoc.accept(doc, new Object[0]); + adder.addJavadoc("$L", doc); } } - public void addClassDoc(BiConsumer addJavadoc, String className) { + public void addClassDoc(DocAdder adder, String className) { ClassDef classDef = classes.get(className); if (classDef == null) { return; } - addDoc(classDef, addJavadoc); - addJavadoc.accept("\n", new Object[0]); + addDoc(classDef, adder); + adder.addJavadoc("\n"); for (String namespace : namespaces) { String transformedName = classDef.getName(namespace); - addJavadoc.accept("@mapping {@literal $L:$L}\n", new Object[] {namespace, transformedName}); + adder.addJavadoc("@mapping {@literal $L:$L}\n", namespace, transformedName); } } @@ -104,7 +103,7 @@ public String getFieldDoc(EntryTriple fieldEntry) { return fieldDef != null ? fieldDef.getComment() : null; } - public void addFieldDoc(BiConsumer addJavadoc, EntryTriple fieldEntry) { + public void addFieldDoc(DocAdder addJavadoc, EntryTriple fieldEntry) { FieldDef fieldDef = fields.get(fieldEntry); if (fieldDef == null) { return; @@ -112,11 +111,11 @@ public void addFieldDoc(BiConsumer addJavadoc, EntryTriple fie addDoc(fieldDef, addJavadoc); ClassDef owner = classes.get(fieldEntry.getOwner()); - addJavadoc.accept("\n", new Object[0]); + addJavadoc.addJavadoc("\n"); for (String namespace : namespaces) { String transformedName = fieldDef.getName(namespace); String mixinForm = "L" + owner.getName(namespace) + ";" + transformedName + ":" + fieldDef.getDescriptor(namespace); - addJavadoc.accept("@mapping {@literal $L:$L:$L}\n", new Object[] {namespace, transformedName, mixinForm}); + addJavadoc.addJavadoc("@mapping {@literal $L:$L:$L}\n", namespace, transformedName, mixinForm); } } @@ -147,7 +146,7 @@ public String getMethodDoc(Function> superGetters, En return null; } - public void addMethodDoc(BiConsumer addJavadoc, Function> superGetters, EntryTriple methodEntry) { + public void addMethodDoc(DocAdder adder, Function> superGetters, EntryTriple methodEntry) { Map.Entry found = searchMethod(superGetters, methodEntry); if (found == null) { return; @@ -156,16 +155,16 @@ public void addMethodDoc(BiConsumer addJavadoc, Function searchMethod(Function Date: Wed, 31 Mar 2021 21:27:03 -0500 Subject: [PATCH 17/43] Fixes #21, tries to fix #20 Signed-off-by: liach --- build.gradle | 2 +- .../fabricmc/mappingpoet/FieldBuilder.java | 34 +++++++++++++++---- .../java/net/fabricmc/mappingpoet/Main.java | 3 +- 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/build.gradle b/build.gradle index 56582d1..174dba8 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ plugins { } group 'net.fabricmc' -version '0.2.6' +version '0.2.7' def ENV = System.getenv() version = version + (ENV.GITHUB_ACTIONS ? "" : "+local") diff --git a/src/main/java/net/fabricmc/mappingpoet/FieldBuilder.java b/src/main/java/net/fabricmc/mappingpoet/FieldBuilder.java index 3488138..81fe104 100644 --- a/src/main/java/net/fabricmc/mappingpoet/FieldBuilder.java +++ b/src/main/java/net/fabricmc/mappingpoet/FieldBuilder.java @@ -391,27 +391,47 @@ private CodeBlock makeInitializer(String desc) { // fake initializers exclude fields from constant values switch (desc.charAt(0)) { case 'B': + if (fieldNode.value instanceof Integer) { + return CodeBlock.builder().add("(byte) $L", fieldNode.value).build(); + } + // fake initializer falls through case 'C': + if (fieldNode.value instanceof Integer) { + return CodeBlock.builder().add("(char) $L", fieldNode.value).build(); + } + // fake initializer falls through case 'D': + if (fieldNode.value instanceof Double) { + return CodeBlock.builder().add("$LD", fieldNode.value).build(); + } + // fake initializer falls through case 'I': + if (fieldNode.value instanceof Integer) { + return CodeBlock.builder().add("$L", fieldNode.value).build(); + } + // fake initializer falls through case 'J': + if (fieldNode.value instanceof Long) { + return CodeBlock.builder().add("$LL", fieldNode.value).build(); + } + // fake initializer falls through case 'S': - if (fieldNode.value != null) { - return CodeBlock.builder().add(String.valueOf(fieldNode.value)).build(); + if (fieldNode.value instanceof Integer) { + return CodeBlock.builder().add("(short) $L", fieldNode.value).build(); } return CodeBlock.builder().add("java.lang.Byte.parseByte(\"dummy\")").build(); case 'F': - if (fieldNode.value != null) { - return CodeBlock.builder().add(fieldNode.value + "f").build(); + if (fieldNode.value instanceof Float) { + return CodeBlock.builder().add("$LF", fieldNode.value).build(); } return CodeBlock.builder().add("java.lang.Float.parseFloat(\"dummy\")").build(); case 'Z': - if (fieldNode.value instanceof Number) { - return CodeBlock.builder().add(Boolean.toString(((Number) fieldNode.value).intValue() != 0)).build(); + if (fieldNode.value instanceof Integer) { + return CodeBlock.builder().add("$L", ((int) fieldNode.value) != 0).build(); } return CodeBlock.builder().add("java.lang.Boolean.parseBoolean(\"dummy\")").build(); } - if (fieldNode.value != null) { + if (desc.equals("Ljava/lang/String;") && fieldNode.value instanceof String) { return CodeBlock.builder().add("$S", fieldNode.value).build(); } return CodeBlock.builder().add(desc.equals("Ljava/lang/String;") ? "java.lang.String.valueOf(\"dummy\")" : "null").build(); diff --git a/src/main/java/net/fabricmc/mappingpoet/Main.java b/src/main/java/net/fabricmc/mappingpoet/Main.java index 1935428..4663c74 100644 --- a/src/main/java/net/fabricmc/mappingpoet/Main.java +++ b/src/main/java/net/fabricmc/mappingpoet/Main.java @@ -95,7 +95,8 @@ public static void generate(Path mappings, Path inputJar, Path outputDirectory, classes.values().stream() .filter(classBuilder -> !classBuilder.getClassName().contains("$")) .forEach(classBuilder -> { - JavaFile javaFile = JavaFile.builder(classBuilder.getClassName().replaceAll("/", ".").substring(0, classBuilder.getClassName().lastIndexOf("/")), classBuilder.build()) + int packageEnd = classBuilder.getClassName().lastIndexOf("/"); + JavaFile javaFile = JavaFile.builder(packageEnd == -1 ? "" : classBuilder.getClassName().substring(0, packageEnd).replaceAll("/", "."), classBuilder.build()) .build(); try { javaFile.writeTo(outputDirectory); From 8c5d438c91b5696cac46e69520e92056c0e2267a Mon Sep 17 00:00:00 2001 From: liach Date: Wed, 31 Mar 2021 22:50:35 -0500 Subject: [PATCH 18/43] Better char literals Signed-off-by: liach --- .../fabricmc/mappingpoet/FieldBuilder.java | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/fabricmc/mappingpoet/FieldBuilder.java b/src/main/java/net/fabricmc/mappingpoet/FieldBuilder.java index 81fe104..5386aad 100644 --- a/src/main/java/net/fabricmc/mappingpoet/FieldBuilder.java +++ b/src/main/java/net/fabricmc/mappingpoet/FieldBuilder.java @@ -397,7 +397,9 @@ private CodeBlock makeInitializer(String desc) { // fake initializer falls through case 'C': if (fieldNode.value instanceof Integer) { - return CodeBlock.builder().add("(char) $L", fieldNode.value).build(); + int value = (int) fieldNode.value; + char c = (char) value; + return printChar(CodeBlock.builder(), c, value).build(); } // fake initializer falls through case 'D': @@ -437,6 +439,34 @@ private CodeBlock makeInitializer(String desc) { return CodeBlock.builder().add(desc.equals("Ljava/lang/String;") ? "java.lang.String.valueOf(\"dummy\")" : "null").build(); } + + private static CodeBlock.Builder printChar(CodeBlock.Builder builder, char c, int value) { + if (!Character.isValidCodePoint(value) || !Character.isDefined(value)) { + return builder.add("(char) $L", value); + } + + // See https://docs.oracle.com/javase/specs/jls/se16/html/jls-3.html#jls-EscapeSequence + // ignore space or ", just use direct in those cases + switch (c) { + case '\b': + return builder.add("'\\b'"); + case '\t': + return builder.add("'\\t'"); + case '\n': + return builder.add("'\\n'"); + case '\f': + return builder.add("'\\f'"); + case '\r': + return builder.add("'\\r'"); + case '\'': + return builder.add("'\\''"); + case '\\': + return builder.add("'\\\\'"); + } + + return builder.add("'$L'", c); + } + private void addJavaDoc() { mappings.addFieldDoc(builder::addJavadoc, new EntryTriple(classNode.name, fieldNode.name, fieldNode.desc)); } From 02a53b57d63084a270358b759e41da2ec43d5b36 Mon Sep 17 00:00:00 2001 From: liach Date: Thu, 13 May 2021 20:12:12 -0500 Subject: [PATCH 19/43] Update dependencies --- build.gradle | 8 ++++---- gradle/wrapper/gradle-wrapper.properties | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/build.gradle b/build.gradle index 174dba8..116bfb1 100644 --- a/build.gradle +++ b/build.gradle @@ -22,7 +22,7 @@ repositories { dependencies { implementation 'com.squareup:javapoet:1.13.0' implementation 'net.fabricmc:tiny-mappings-parser:0.3.0+build.17' - runtimeOnly 'com.google.guava:guava:28.2-jre' + runtimeOnly 'com.google.guava:guava:30.1.1-jre' implementation 'org.ow2.asm:asm:9.1' implementation 'org.ow2.asm:asm-analysis:9.1' @@ -30,8 +30,8 @@ dependencies { implementation 'org.ow2.asm:asm-tree:9.1' implementation 'org.ow2.asm:asm-util:9.1' - testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.1' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.1' } java { @@ -39,7 +39,7 @@ java { } compileJava { - sourceCompatibility = targetCompatibility = JavaVersion.VERSION_11 + sourceCompatibility = targetCompatibility = JavaVersion.VERSION_16 } test { diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 442d913..e5338d3 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From 94c1480aef92f79aa236692e433ab1ab105edc56 Mon Sep 17 00:00:00 2001 From: liach Date: Thu, 13 May 2021 20:58:47 -0500 Subject: [PATCH 20/43] Fix redundant public modifier for inner classes, migrate to modern java Signed-off-by: liach --- build.gradle | 2 +- .../fabricmc/mappingpoet/ClassBuilder.java | 13 ++-- .../java/net/fabricmc/mappingpoet/Main.java | 2 +- .../fabricmc/mappingpoet/MethodBuilder.java | 10 +-- .../mappingpoet/signature/ClassSignature.java | 11 +-- .../signature/ClassStaticContext.java | 2 +- .../signature/MethodSignature.java | 14 +--- .../signature/PoetTypeSignatureWriter.java | 20 ++---- .../fabricmc/mappingpoet/SignaturesTest.java | 68 +++++++++---------- 9 files changed, 60 insertions(+), 82 deletions(-) diff --git a/build.gradle b/build.gradle index 116bfb1..cbe1a8e 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ plugins { } group 'net.fabricmc' -version '0.2.7' +version '0.2.8' def ENV = System.getenv() version = version + (ENV.GITHUB_ACTIONS ? "" : "+local") diff --git a/src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java b/src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java index a4c13ff..b687abf 100644 --- a/src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java +++ b/src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java @@ -146,15 +146,15 @@ private TypeSpec.Builder setupBuilder() { builder = TypeSpec.enumBuilder(name); } else { builder = TypeSpec.classBuilder(name) - .superclass(signature.superclass); + .superclass(signature.superclass()); } - if (!signature.generics.isEmpty()) { - builder.addTypeVariables(signature.generics); + if (!signature.generics().isEmpty()) { + builder.addTypeVariables(signature.generics()); StringBuilder sb = new StringBuilder(); sb.append(classNode.name); sb.append("<"); - for (TypeVariableName each : signature.generics) { + for (TypeVariableName each : signature.generics()) { sb.append("T").append(each.name).append(";"); } sb.append(">"); @@ -170,7 +170,7 @@ private void addInterfaces() { return; } if (signature != null) { - builder.addSuperinterfaces(signature.superinterfaces); + builder.addSuperinterfaces(signature.superinterfaces()); return; } if (classNode.interfaces.isEmpty()) return; @@ -284,6 +284,7 @@ public void addInnerClass(ClassBuilder classBuilder) { classBuilder.builder.addModifiers(javax.lang.model.element.Modifier.PUBLIC); classBuilder.builder.addModifiers(javax.lang.model.element.Modifier.STATIC); } else { + classBuilder.builder.modifiers.remove(javax.lang.model.element.Modifier.PUBLIC); // this modifier may come from class access classBuilder.builder.addModifiers(new ModifierBuilder(innerClassNode.access).getModifiers(classBuilder.enumClass ? ModifierBuilder.Type.ENUM : ModifierBuilder.Type.CLASS)); if (!Modifier.isStatic(innerClassNode.access)) { classBuilder.instanceInner = true; @@ -295,7 +296,7 @@ public void addInnerClass(ClassBuilder classBuilder) { sb.append(this.receiverSignature).append("."); // like O. for O sb.append(innerClassNode.innerName); // append simple name - List innerClassGenerics = classBuilder.signature.generics; + List innerClassGenerics = classBuilder.signature.generics(); if (!innerClassGenerics.isEmpty()) { sb.append("<"); for (TypeVariableName each : innerClassGenerics) { diff --git a/src/main/java/net/fabricmc/mappingpoet/Main.java b/src/main/java/net/fabricmc/mappingpoet/Main.java index 4663c74..d07c56b 100644 --- a/src/main/java/net/fabricmc/mappingpoet/Main.java +++ b/src/main/java/net/fabricmc/mappingpoet/Main.java @@ -166,7 +166,7 @@ private static void forEachClass(Path jar, ClassNodeConsumer classNodeConsumer, private static void scanInnerClasses(Map instanceInnerClasses, Path librariesDir) { try { - Files.walkFileTree(librariesDir, new SimpleFileVisitor() { + Files.walkFileTree(librariesDir, new SimpleFileVisitor<>() { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { if (!file.getFileName().toString().endsWith(".jar")) { diff --git a/src/main/java/net/fabricmc/mappingpoet/MethodBuilder.java b/src/main/java/net/fabricmc/mappingpoet/MethodBuilder.java index 4ab40f9..8c3b181 100644 --- a/src/main/java/net/fabricmc/mappingpoet/MethodBuilder.java +++ b/src/main/java/net/fabricmc/mappingpoet/MethodBuilder.java @@ -159,7 +159,7 @@ private MethodSpec.Builder createBuilder() { if (methodNode.signature != null) { signature = AnnotationAwareSignatures.parseMethodSignature(methodNode.signature, typeAnnotations, context); - builder.addTypeVariables(signature.generics); + builder.addTypeVariables(signature.generics()); } return builder; @@ -187,7 +187,7 @@ private void setReturnType() { TypeName typeName; if (signature != null) { - typeName = signature.result; + typeName = signature.result(); } else { String returnDesc = methodNode.desc.substring(methodNode.desc.lastIndexOf(")") + 1); typeName = AnnotationAwareDescriptors.parseDesc(returnDesc, typeAnnotations.getBank(TypeReference.newTypeReference(TypeReference.METHOD_RETURN)), context); @@ -257,7 +257,7 @@ private void getParams(List paramTypes, boolean instance, Set } index++; // consume '(' - Iterator signatureParamIterator = signature == null ? Collections.emptyIterator() : signature.parameters.iterator(); + Iterator signatureParamIterator = signature == null ? Collections.emptyIterator() : signature.parameters().iterator(); while (desc.charAt(index) != ')') { int oldIndex = index; Map.Entry parsedParam = FieldBuilder.parseType(desc, index); @@ -288,8 +288,8 @@ private void getParams(List paramTypes, boolean instance, Set } private void addExceptions() { - if (signature != null && !signature.thrown.isEmpty()) { - for (TypeName each : signature.thrown) { + if (signature != null && !signature.thrown().isEmpty()) { + for (TypeName each : signature.thrown()) { builder.addException(each); } return; diff --git a/src/main/java/net/fabricmc/mappingpoet/signature/ClassSignature.java b/src/main/java/net/fabricmc/mappingpoet/signature/ClassSignature.java index e3b5df5..11b0004 100644 --- a/src/main/java/net/fabricmc/mappingpoet/signature/ClassSignature.java +++ b/src/main/java/net/fabricmc/mappingpoet/signature/ClassSignature.java @@ -22,14 +22,7 @@ import com.squareup.javapoet.TypeVariableName; // no more a class signature but general super info about class -public final class ClassSignature { - public final List generics; - public final TypeName superclass; - public final List superinterfaces; +public record ClassSignature(List generics, TypeName superclass, + List superinterfaces) { - public ClassSignature(List generics, TypeName superclass, List superinterfaces) { - this.generics = generics; - this.superclass = superclass; - this.superinterfaces = superinterfaces; - } } diff --git a/src/main/java/net/fabricmc/mappingpoet/signature/ClassStaticContext.java b/src/main/java/net/fabricmc/mappingpoet/signature/ClassStaticContext.java index 1ba5c49..c1933e5 100644 --- a/src/main/java/net/fabricmc/mappingpoet/signature/ClassStaticContext.java +++ b/src/main/java/net/fabricmc/mappingpoet/signature/ClassStaticContext.java @@ -27,7 +27,7 @@ public interface ClassStaticContext { /** * Returns if this class is an instance inner class. * - *

For example, a top-level class is not so. A static inner + *

For example, a top-level class is not so. A static nested * class, such as {@code Map.Entry}, is not as well.

* * @param internalName the JVM name of the class diff --git a/src/main/java/net/fabricmc/mappingpoet/signature/MethodSignature.java b/src/main/java/net/fabricmc/mappingpoet/signature/MethodSignature.java index 20cfe16..6976241 100644 --- a/src/main/java/net/fabricmc/mappingpoet/signature/MethodSignature.java +++ b/src/main/java/net/fabricmc/mappingpoet/signature/MethodSignature.java @@ -21,16 +21,8 @@ import com.squareup.javapoet.TypeName; import com.squareup.javapoet.TypeVariableName; -public final class MethodSignature { - public final List generics; - public final List parameters; - public final TypeName result; - public final List thrown; +public record MethodSignature(List generics, + List parameters, TypeName result, + List thrown) { - public MethodSignature(List generics, List parameters, TypeName result, List thrown) { - this.generics = generics; - this.parameters = parameters; - this.result = result; - this.thrown = thrown; - } } diff --git a/src/main/java/net/fabricmc/mappingpoet/signature/PoetTypeSignatureWriter.java b/src/main/java/net/fabricmc/mappingpoet/signature/PoetTypeSignatureWriter.java index bf5014f..1d36b73 100644 --- a/src/main/java/net/fabricmc/mappingpoet/signature/PoetTypeSignatureWriter.java +++ b/src/main/java/net/fabricmc/mappingpoet/signature/PoetTypeSignatureWriter.java @@ -150,20 +150,12 @@ public void visitInnerClassType(String name) { private void collectLastTypeArgument() { if (activeTypeArgument != null) { TypeName hold = activeTypeArgument.compute(); - TypeName used; - switch (activeTypeArgumentKind) { - case SignatureVisitor.EXTENDS: - used = WildcardTypeName.subtypeOf(hold); - break; - case SignatureVisitor.SUPER: - used = WildcardTypeName.supertypeOf(hold); - break; - case SignatureVisitor.INSTANCEOF: - used = hold; - break; - default: - throw new IllegalStateException(String.format("Illegal type argument wildcard %s", activeTypeArgumentKind)); - } + TypeName used = switch (activeTypeArgumentKind) { + case SignatureVisitor.EXTENDS -> WildcardTypeName.subtypeOf(hold); + case SignatureVisitor.SUPER -> WildcardTypeName.supertypeOf(hold); + case SignatureVisitor.INSTANCEOF -> hold; + default -> throw new IllegalStateException(String.format("Illegal type argument wildcard %s", activeTypeArgumentKind)); + }; used = AnnotationAwareDescriptors.annotate(used, storage.advance(TypePath.TYPE_ARGUMENT, params.size())); params.addLast(used); diff --git a/src/test/java/net/fabricmc/mappingpoet/SignaturesTest.java b/src/test/java/net/fabricmc/mappingpoet/SignaturesTest.java index 026c10a..a2fd452 100644 --- a/src/test/java/net/fabricmc/mappingpoet/SignaturesTest.java +++ b/src/test/java/net/fabricmc/mappingpoet/SignaturesTest.java @@ -118,9 +118,9 @@ public void testClassDeeSignature() { Assertions.assertEquals("java.util.function.UnaryOperator>>", dBound.getValue().toString()); ClassSignature parsed = Signatures.parseClassSignature(classSig); - Assertions.assertIterableEquals(Collections.singleton(TypeVariableName.get("D")), parsed.generics); - Assertions.assertEquals(ClassName.OBJECT, parsed.superclass); - Assertions.assertIterableEquals(Collections.emptyList(), parsed.superinterfaces); + Assertions.assertIterableEquals(Collections.singleton(TypeVariableName.get("D")), parsed.generics()); + Assertions.assertEquals(ClassName.OBJECT, parsed.superclass()); + Assertions.assertIterableEquals(Collections.emptyList(), parsed.superinterfaces()); } @Test @@ -131,9 +131,9 @@ public void testClassDeeSignatureVisitor() { PoetClassMethodSignatureVisitor visitor = new PoetClassMethodSignatureVisitor(TypeAnnotationMapping.EMPTY, s -> false, true); new SignatureReader(classSig).accept(visitor); ClassSignature parsed = visitor.collectClass(); - Assertions.assertIterableEquals(Collections.singleton(TypeVariableName.get("D")), parsed.generics); - Assertions.assertEquals(ClassName.OBJECT, parsed.superclass); - Assertions.assertIterableEquals(Collections.emptyList(), parsed.superinterfaces); + Assertions.assertIterableEquals(Collections.singleton(TypeVariableName.get("D")), parsed.generics()); + Assertions.assertEquals(ClassName.OBJECT, parsed.superclass()); + Assertions.assertIterableEquals(Collections.emptyList(), parsed.superinterfaces()); } @Test @@ -141,10 +141,10 @@ public void testCollectionIntFunctionToArraySignature() { // signature (Ljava/util/function/IntFunction<[TT;>;)[TT; String methodSignature = "(Ljava/util/function/IntFunction<[TT;>;)[TT;"; MethodSignature parsed = Signatures.parseMethodSignature(methodSignature); - Assertions.assertIterableEquals(Collections.singleton(TypeVariableName.get("T")), parsed.generics); - Assertions.assertEquals(ArrayTypeName.of(TypeVariableName.get("T")), parsed.result); - Assertions.assertIterableEquals(Collections.emptyList(), parsed.thrown); - Assertions.assertIterableEquals(Collections.singleton(ParameterizedTypeName.get(ClassName.get(IntFunction.class), ArrayTypeName.of(TypeVariableName.get("T")))), parsed.parameters); + Assertions.assertIterableEquals(Collections.singleton(TypeVariableName.get("T")), parsed.generics()); + Assertions.assertEquals(ArrayTypeName.of(TypeVariableName.get("T")), parsed.result()); + Assertions.assertIterableEquals(Collections.emptyList(), parsed.thrown()); + Assertions.assertIterableEquals(Collections.singleton(ParameterizedTypeName.get(ClassName.get(IntFunction.class), ArrayTypeName.of(TypeVariableName.get("T")))), parsed.parameters()); } @Test @@ -152,10 +152,10 @@ public void testCollectionArrayToArraySignature() { // signature ([TT;)[TT; String methodSignature = "([TT;)[TT;"; MethodSignature parsed = Signatures.parseMethodSignature(methodSignature); - Assertions.assertIterableEquals(Collections.singleton(TypeVariableName.get("T")), parsed.generics); - Assertions.assertEquals(ArrayTypeName.of(TypeVariableName.get("T")), parsed.result); - Assertions.assertIterableEquals(Collections.emptyList(), parsed.thrown); - Assertions.assertIterableEquals(Collections.singleton(ArrayTypeName.of(TypeVariableName.get("T"))), parsed.parameters); + Assertions.assertIterableEquals(Collections.singleton(TypeVariableName.get("T")), parsed.generics()); + Assertions.assertEquals(ArrayTypeName.of(TypeVariableName.get("T")), parsed.result()); + Assertions.assertIterableEquals(Collections.emptyList(), parsed.thrown()); + Assertions.assertIterableEquals(Collections.singleton(ArrayTypeName.of(TypeVariableName.get("T"))), parsed.parameters()); } @Test @@ -165,10 +165,10 @@ public void testCollectionArrayToArraySignatureVisitor() { PoetClassMethodSignatureVisitor visitor = new PoetClassMethodSignatureVisitor(TypeAnnotationMapping.EMPTY, s -> false, false); new SignatureReader(methodSignature).accept(visitor); MethodSignature parsed = visitor.collectMethod(); - Assertions.assertIterableEquals(Collections.singleton(TypeVariableName.get("T")), parsed.generics); - Assertions.assertEquals(ArrayTypeName.of(TypeVariableName.get("T")), parsed.result); - Assertions.assertIterableEquals(Collections.emptyList(), parsed.thrown); - Assertions.assertIterableEquals(Collections.singleton(ArrayTypeName.of(TypeVariableName.get("T"))), parsed.parameters); + Assertions.assertIterableEquals(Collections.singleton(TypeVariableName.get("T")), parsed.generics()); + Assertions.assertEquals(ArrayTypeName.of(TypeVariableName.get("T")), parsed.result()); + Assertions.assertIterableEquals(Collections.emptyList(), parsed.thrown()); + Assertions.assertIterableEquals(Collections.singleton(ArrayTypeName.of(TypeVariableName.get("T"))), parsed.parameters()); } @Test @@ -176,12 +176,12 @@ public void testTweakLastSignature() { // signature (Ljava/util/function/UnaryOperator;)V String methodSignature = "(Ljava/util/function/UnaryOperator;)V"; MethodSignature parsed = Signatures.parseMethodSignature(methodSignature); - Assertions.assertTrue(parsed.generics.isEmpty()); - Assertions.assertEquals(TypeName.VOID, parsed.result); - Assertions.assertIterableEquals(Collections.emptyList(), parsed.thrown); + Assertions.assertTrue(parsed.generics().isEmpty()); + Assertions.assertEquals(TypeName.VOID, parsed.result()); + Assertions.assertIterableEquals(Collections.emptyList(), parsed.thrown()); ClassName unaryOperatorClass = ClassName.get(UnaryOperator.class); ClassName typeNameClass = ClassName.get(TypeName.class); - Assertions.assertIterableEquals(Collections.singleton(ParameterizedTypeName.get(unaryOperatorClass, typeNameClass)), parsed.parameters); + Assertions.assertIterableEquals(Collections.singleton(ParameterizedTypeName.get(unaryOperatorClass, typeNameClass)), parsed.parameters()); } @Test @@ -191,12 +191,12 @@ public void testTweakLastSignatureVisitor() { PoetClassMethodSignatureVisitor visitor = new PoetClassMethodSignatureVisitor(TypeAnnotationMapping.EMPTY, s -> false, false); new SignatureReader(methodSignature).accept(visitor); MethodSignature parsed = visitor.collectMethod(); - Assertions.assertTrue(parsed.generics.isEmpty()); - Assertions.assertEquals(TypeName.VOID, parsed.result); - Assertions.assertIterableEquals(Collections.emptyList(), parsed.thrown); + Assertions.assertTrue(parsed.generics().isEmpty()); + Assertions.assertEquals(TypeName.VOID, parsed.result()); + Assertions.assertIterableEquals(Collections.emptyList(), parsed.thrown()); ClassName unaryOperatorClass = ClassName.get(UnaryOperator.class); ClassName typeNameClass = ClassName.get(TypeName.class); - Assertions.assertIterableEquals(Collections.singleton(ParameterizedTypeName.get(unaryOperatorClass, typeNameClass)), parsed.parameters); + Assertions.assertIterableEquals(Collections.singleton(ParameterizedTypeName.get(unaryOperatorClass, typeNameClass)), parsed.parameters()); } @Test @@ -204,11 +204,11 @@ public void testCheckHeadSignature() { // signature (Lnet/fabricmc/mappingpoet/Signatures$HeadChecker;)V^TE; String raw = "(Lnet/fabricmc/mappingpoet/Signatures$HeadChecker;)V^TE;"; MethodSignature parsed = Signatures.parseMethodSignature(raw); - Assertions.assertIterableEquals(Collections.singleton(TypeVariableName.get("E", ClassName.get(Throwable.class))), parsed.generics); + Assertions.assertIterableEquals(Collections.singleton(TypeVariableName.get("E", ClassName.get(Throwable.class))), parsed.generics()); ClassName headCheckerClass = ClassName.get(Signatures.class).nestedClass("HeadChecker"); - Assertions.assertIterableEquals(Collections.singleton(ParameterizedTypeName.get(headCheckerClass, TypeVariableName.get("E"))), parsed.parameters); - Assertions.assertEquals(TypeName.VOID, parsed.result); - Assertions.assertIterableEquals(Collections.singleton(TypeVariableName.get("E")), parsed.thrown); + Assertions.assertIterableEquals(Collections.singleton(ParameterizedTypeName.get(headCheckerClass, TypeVariableName.get("E"))), parsed.parameters()); + Assertions.assertEquals(TypeName.VOID, parsed.result()); + Assertions.assertIterableEquals(Collections.singleton(TypeVariableName.get("E")), parsed.thrown()); } @Test @@ -218,11 +218,11 @@ public void testCheckHeadSignatureVisitor() { PoetClassMethodSignatureVisitor visitor = new PoetClassMethodSignatureVisitor(TypeAnnotationMapping.EMPTY, s -> false, false); new SignatureReader(raw).accept(visitor); MethodSignature parsed = visitor.collectMethod(); - Assertions.assertIterableEquals(Collections.singleton(TypeVariableName.get("E", ClassName.get(Throwable.class))), parsed.generics); + Assertions.assertIterableEquals(Collections.singleton(TypeVariableName.get("E", ClassName.get(Throwable.class))), parsed.generics()); ClassName headCheckerClass = ClassName.get(Signatures.class).nestedClass("HeadChecker"); - Assertions.assertIterableEquals(Collections.singleton(ParameterizedTypeName.get(headCheckerClass, TypeVariableName.get("E"))), parsed.parameters); - Assertions.assertEquals(TypeName.VOID, parsed.result); - Assertions.assertIterableEquals(Collections.singleton(TypeVariableName.get("E")), parsed.thrown); + Assertions.assertIterableEquals(Collections.singleton(ParameterizedTypeName.get(headCheckerClass, TypeVariableName.get("E"))), parsed.parameters()); + Assertions.assertEquals(TypeName.VOID, parsed.result()); + Assertions.assertIterableEquals(Collections.singleton(TypeVariableName.get("E")), parsed.thrown()); } @Test From 35ee303afad66f36eb0dbb84966e817a2dbc6391 Mon Sep 17 00:00:00 2001 From: liach Date: Thu, 13 May 2021 21:04:06 -0500 Subject: [PATCH 21/43] Forgot to bump this Signed-off-by: liach --- .github/workflows/build.yml | 3 +-- .github/workflows/release.yml | 3 +-- gradlew | 0 gradlew.bat | 0 4 files changed, 2 insertions(+), 4 deletions(-) mode change 100644 => 100755 gradlew mode change 100644 => 100755 gradlew.bat diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 40983ff..22de066 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -4,7 +4,7 @@ jobs: build: strategy: matrix: - java: [11-jdk, 15-jdk] + java: [16-jdk] runs-on: ubuntu-20.04 container: image: openjdk:${{ matrix.java }} @@ -12,5 +12,4 @@ jobs: steps: - uses: actions/checkout@v1 - uses: gradle/wrapper-validation-action@v1 - - run: chmod +x ./gradlew - run: ./gradlew build test --stacktrace \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 96eae5f..c9c8719 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -4,12 +4,11 @@ jobs: build: runs-on: ubuntu-20.04 container: - image: openjdk:11-jdk + image: openjdk:16-jdk options: --user root steps: - uses: actions/checkout@v1 - uses: gradle/wrapper-validation-action@v1 - - run: chmod +x ./gradlew - run: ./gradlew checkVersion build publish --stacktrace env: MAVEN_URL: ${{ secrets.MAVEN_URL }} diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 diff --git a/gradlew.bat b/gradlew.bat old mode 100644 new mode 100755 From 7f47cd7c7a5659d02d2239402e9bba309c3464a9 Mon Sep 17 00:00:00 2001 From: liach Date: Thu, 13 May 2021 21:07:45 -0500 Subject: [PATCH 22/43] So we never published the readme --- .gitignore | 3 ++- readme.md | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 readme.md diff --git a/.gitignore b/.gitignore index f5f7c31..579fd33 100644 --- a/.gitignore +++ b/.gitignore @@ -14,4 +14,5 @@ !/settings.gradle !/LICENSE !/HEADER -!/.github \ No newline at end of file +!/.github +!/readme.md diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..1996aeb --- /dev/null +++ b/readme.md @@ -0,0 +1,2 @@ +# MappingPoet +Generates minimal source structure from bytecode so javadoc can generate documentation. From 24d0ec723c8e90298b365b73e843d4667579aee9 Mon Sep 17 00:00:00 2001 From: liach Date: Sat, 18 Sep 2021 12:11:32 -0500 Subject: [PATCH 23/43] Update gradle, use forked javapoet Signed-off-by: liach --- .github/workflows/build.yml | 7 +- .github/workflows/release.yml | 4 +- .gitignore | 1 - build.gradle | 31 ++- gradle/wrapper/gradle-wrapper.jar | Bin 59203 -> 59536 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 257 ++++++++++++++--------- 7 files changed, 183 insertions(+), 119 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 22de066..3079640 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -4,7 +4,7 @@ jobs: build: strategy: matrix: - java: [16-jdk] + java: [17-jdk] runs-on: ubuntu-20.04 container: image: openjdk:${{ matrix.java }} @@ -12,4 +12,7 @@ jobs: steps: - uses: actions/checkout@v1 - uses: gradle/wrapper-validation-action@v1 - - run: ./gradlew build test --stacktrace \ No newline at end of file + - run: ./gradlew build test --stacktrace + env: + GITHUB_ACTOR: ${{ github.actor }} + GITHUB_TOKEN: ${{ github.token }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c9c8719..760ffaf 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -4,7 +4,7 @@ jobs: build: runs-on: ubuntu-20.04 container: - image: openjdk:16-jdk + image: openjdk:17-jdk options: --user root steps: - uses: actions/checkout@v1 @@ -14,3 +14,5 @@ jobs: MAVEN_URL: ${{ secrets.MAVEN_URL }} MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }} MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }} + GITHUB_ACTOR: ${{ github.actor }} + GITHUB_TOKEN: ${{ github.token }} diff --git a/.gitignore b/.gitignore index 579fd33..e5ad366 100644 --- a/.gitignore +++ b/.gitignore @@ -8,7 +8,6 @@ !/.gitignore !/.editorconfig !/build.gradle -!/gradle.properties !/gradlew !/gradlew.bat !/settings.gradle diff --git a/build.gradle b/build.gradle index cbe1a8e..b256cc8 100644 --- a/build.gradle +++ b/build.gradle @@ -1,8 +1,7 @@ plugins { id 'java' - id 'java-library' id 'maven-publish' - id("org.cadixdev.licenser") version "0.5.0" + id 'org.cadixdev.licenser' version '0.6.1' } group 'net.fabricmc' @@ -17,18 +16,29 @@ repositories { name = 'Fabric' url = 'https://maven.modmuss50.me/' } + maven { + name = "GitHub" + url = uri("https://maven.pkg.github.com/liachmodded/javapoet") + credentials { + // any user can generate an access token at https://github.com/settings/tokens as password + // just need the read:packages permission + username = findProperty('github_user') ?: ENV.GITHUB_ACTOR + password = findProperty('github_read_key') ?: ENV.GITHUB_TOKEN + } + } } dependencies { - implementation 'com.squareup:javapoet:1.13.0' + //implementation 'com.squareup:javapoet:1.13.0' + implementation 'com.github.liachmodded:javapoet:0.0.3' implementation 'net.fabricmc:tiny-mappings-parser:0.3.0+build.17' runtimeOnly 'com.google.guava:guava:30.1.1-jre' - implementation 'org.ow2.asm:asm:9.1' - implementation 'org.ow2.asm:asm-analysis:9.1' - implementation 'org.ow2.asm:asm-commons:9.1' - implementation 'org.ow2.asm:asm-tree:9.1' - implementation 'org.ow2.asm:asm-util:9.1' + implementation 'org.ow2.asm:asm:9.2' + implementation 'org.ow2.asm:asm-analysis:9.2' + implementation 'org.ow2.asm:asm-commons:9.2' + implementation 'org.ow2.asm:asm-tree:9.2' + implementation 'org.ow2.asm:asm-util:9.2' testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.1' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.1' @@ -38,8 +48,9 @@ java { withSourcesJar() } -compileJava { - sourceCompatibility = targetCompatibility = JavaVersion.VERSION_16 +tasks.withType(JavaCompile) { + options.release = 17 + options.encoding = "UTF-8" } test { diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e708b1c023ec8b20f512888fe07c5bd3ff77bb8f..7454180f2ae8848c63b8b4dea2cb829da983f2fa 100644 GIT binary patch delta 18435 zcmY&<19zBR)MXm8v2EM7ZQHi-#I|kQZfv7Tn#Q)%81v4zX3d)U4d4 zYYc!v@NU%|U;_sM`2z(4BAilWijmR>4U^KdN)D8%@2KLcqkTDW%^3U(Wg>{qkAF z&RcYr;D1I5aD(N-PnqoEeBN~JyXiT(+@b`4Pv`;KmkBXYN48@0;iXuq6!ytn`vGp$ z6X4DQHMx^WlOek^bde&~cvEO@K$oJ}i`T`N;M|lX0mhmEH zuRpo!rS~#&rg}ajBdma$$}+vEhz?JAFUW|iZEcL%amAg_pzqul-B7Itq6Y_BGmOCC zX*Bw3rFz3R)DXpCVBkI!SoOHtYstv*e-May|+?b80ZRh$MZ$FerlC`)ZKt} zTd0Arf9N2dimjs>mg5&@sfTPsRXKXI;0L~&t+GH zkB<>wxI9D+k5VHHcB7Rku{Z>i3$&hgd9Mt_hS_GaGg0#2EHzyV=j=u5xSyV~F0*qs zW{k9}lFZ?H%@4hII_!bzao!S(J^^ZZVmG_;^qXkpJb7OyR*sPL>))Jx{K4xtO2xTr@St!@CJ=y3q2wY5F`77Tqwz8!&Q{f7Dp zifvzVV1!Dj*dxG%BsQyRP6${X+Tc$+XOG zzvq5xcC#&-iXlp$)L=9t{oD~bT~v^ZxQG;FRz|HcZj|^L#_(VNG)k{=_6|6Bs-tRNCn-XuaZ^*^hpZ@qwi`m|BxcF6IWc?_bhtK_cDZRTw#*bZ2`1@1HcB
`mLUmo_>@2R&nj7&CiH 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 B8dv}T delta 17845 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 X49Luk)baa85H9$5YCsTPT`SVRWMtMW diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e5338d3..ffed3a2 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 4f906e0..c53aefa 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,67 +17,101 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +APP_BASE_NAME=${0##*/} # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -106,80 +140,95 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" From d6765adc05b1a5549490af69ab78a8b0962ec850 Mon Sep 17 00:00:00 2001 From: liach Date: Sat, 18 Sep 2021 13:31:17 -0500 Subject: [PATCH 24/43] Preliminary work on getting records and sealed classes right Signed-off-by: liach --- .../fabricmc/mappingpoet/ClassBuilder.java | 86 ++- .../fabricmc/mappingpoet/FieldBuilder.java | 532 +++++++++--------- .../java/net/fabricmc/mappingpoet/Main.java | 35 +- .../fabricmc/mappingpoet/ModifierBuilder.java | 44 +- 4 files changed, 404 insertions(+), 293 deletions(-) diff --git a/src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java b/src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java index b687abf..1a1d0b1 100644 --- a/src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java +++ b/src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java @@ -16,34 +16,45 @@ package net.fabricmc.mappingpoet; -import static net.fabricmc.mappingpoet.FieldBuilder.parseAnnotation; - -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.function.Function; - import com.squareup.javapoet.AnnotationSpec; import com.squareup.javapoet.ClassName; +import com.squareup.javapoet.ParameterSpec; import com.squareup.javapoet.TypeSpec; import com.squareup.javapoet.TypeVariableName; +import net.fabricmc.mappingpoet.signature.AnnotationAwareDescriptors; +import net.fabricmc.mappingpoet.signature.AnnotationAwareSignatures; +import net.fabricmc.mappingpoet.signature.ClassSignature; +import net.fabricmc.mappingpoet.signature.ClassStaticContext; +import net.fabricmc.mappingpoet.signature.TypeAnnotationMapping; +import net.fabricmc.mappingpoet.signature.TypeAnnotationStorage; +import org.objectweb.asm.Handle; import org.objectweb.asm.Opcodes; import org.objectweb.asm.TypeReference; +import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.AnnotationNode; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.FieldNode; import org.objectweb.asm.tree.InnerClassNode; +import org.objectweb.asm.tree.InvokeDynamicInsnNode; import org.objectweb.asm.tree.MethodNode; -import net.fabricmc.mappingpoet.signature.AnnotationAwareDescriptors; -import net.fabricmc.mappingpoet.signature.AnnotationAwareSignatures; -import net.fabricmc.mappingpoet.signature.ClassSignature; -import net.fabricmc.mappingpoet.signature.ClassStaticContext; -import net.fabricmc.mappingpoet.signature.TypeAnnotationMapping; -import net.fabricmc.mappingpoet.signature.TypeAnnotationStorage; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.function.Function; +import java.util.function.Predicate; + +import static net.fabricmc.mappingpoet.FieldBuilder.parseAnnotation; public class ClassBuilder { + static final Handle OBJ_MTH_BOOTSTRAP = new Handle( + Opcodes.H_INVOKESTATIC, + "java/lang/runtime/ObjectMethods", + "bootstrap", + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/TypeDescriptor;Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;", + false + ); private final MappingsStore mappings; private final ClassNode classNode; @@ -51,21 +62,24 @@ public class ClassBuilder { private final TypeSpec.Builder builder; private final List innerClasses = new ArrayList<>(); private final Function> superGetter; + private final Predicate sealChecker; private final ClassStaticContext context; private final ClassSignature signature; // not really signature private final TypeAnnotationMapping typeAnnotations; private boolean annotationClass; private boolean enumClass; + private boolean recordClass; private boolean instanceInner = false; // only nonnull if any class in the inner class chain creates a generic decl // omits L and ; private String receiverSignature; - public ClassBuilder(MappingsStore mappings, ClassNode classNode, Function> superGetter, ClassStaticContext context) { + public ClassBuilder(MappingsStore mappings, ClassNode classNode, Function> superGetter, Predicate sealChecker, ClassStaticContext context) { this.mappings = mappings; this.classNode = classNode; this.superGetter = superGetter; + this.sealChecker = sealChecker; this.context = context; this.typeAnnotations = setupAnnotations(); this.signature = setupSignature(); @@ -144,6 +158,9 @@ private TypeSpec.Builder setupBuilder() { } else if (classNode.superName.equals("java/lang/Enum")) { enumClass = true; builder = TypeSpec.enumBuilder(name); + } else if (classNode.superName.equals("java/lang/Record")) { + recordClass = true; + builder = TypeSpec.recordBuilder(name); } else { builder = TypeSpec.classBuilder(name) .superclass(signature.superclass()); @@ -162,7 +179,10 @@ private TypeSpec.Builder setupBuilder() { } return builder - .addModifiers(new ModifierBuilder(classNode.access).getModifiers(enumClass ? ModifierBuilder.Type.ENUM : ModifierBuilder.Type.CLASS)); + .addModifiers(new ModifierBuilder(classNode.access) + .checkUnseal(classNode, sealChecker) + .getModifiers(ModifierBuilder.getType(enumClass, recordClass)) + ); } private void addInterfaces() { @@ -197,6 +217,7 @@ private void addDirectAnnotations(List regularAnnotations) { private void addMethods() { if (classNode.methods == null) return; + methodsLoop: for (MethodNode method : classNode.methods) { if ((method.access & Opcodes.ACC_SYNTHETIC) != 0 || (method.access & Opcodes.ACC_MANDATED) != 0) { continue; @@ -217,6 +238,21 @@ private void addMethods() { formalParamStartIndex = 2; // 0 String 1 int } } + if (recordClass) { + // skip record sugars + if (method.name.equals("equals") && method.desc.equals("(Ljava/lang/Object;)Z") + || method.name.equals("toString") && method.desc.equals("()Ljava/lang/String;") + || method.name.equals("hashCode") && method.desc.equals("()I")) { + for (AbstractInsnNode insn : method.instructions) { + if (insn instanceof InvokeDynamicInsnNode indy + && indy.bsm.equals(OBJ_MTH_BOOTSTRAP) + && indy.name.equals(method.name)) + continue methodsLoop; + } + } + + // todo test component getters + } if (instanceInner) { if (method.name.equals("")) { formalParamStartIndex = 1; // 0 this$0 @@ -229,6 +265,19 @@ private void addMethods() { private void addFields() { if (classNode.fields == null) return; for (FieldNode field : classNode.fields) { + if (recordClass && !Modifier.isStatic(field.access)) { + if (!Modifier.isFinal(field.access) || !Modifier.isPrivate(field.access)) { + System.out.println("abnormal instance field " + field.name + " in record " + getClassName() + ", skipping"); + } else { + var fieldBuilder = new FieldBuilder(mappings, classNode, field, context); + var paramBuilder = ParameterSpec.builder(fieldBuilder.calculateType(), field.name); + fieldBuilder.addJavaDoc(paramBuilder); + fieldBuilder.addDirectAnnotations(paramBuilder); + builder.addRecordComponent(paramBuilder.build()); + } + + continue; + } if ((field.access & Opcodes.ACC_SYNTHETIC) != 0 || (field.access & Opcodes.ACC_MANDATED) != 0) { continue; // hide synthetic stuff } @@ -285,7 +334,10 @@ public void addInnerClass(ClassBuilder classBuilder) { classBuilder.builder.addModifiers(javax.lang.model.element.Modifier.STATIC); } else { classBuilder.builder.modifiers.remove(javax.lang.model.element.Modifier.PUBLIC); // this modifier may come from class access - classBuilder.builder.addModifiers(new ModifierBuilder(innerClassNode.access).getModifiers(classBuilder.enumClass ? ModifierBuilder.Type.ENUM : ModifierBuilder.Type.CLASS)); + classBuilder.builder.addModifiers(new ModifierBuilder(innerClassNode.access) + .checkUnseal(classBuilder.classNode, sealChecker) + .getModifiers(ModifierBuilder.getType(classBuilder.enumClass, classBuilder.recordClass)) + ); if (!Modifier.isStatic(innerClassNode.access)) { classBuilder.instanceInner = true; } diff --git a/src/main/java/net/fabricmc/mappingpoet/FieldBuilder.java b/src/main/java/net/fabricmc/mappingpoet/FieldBuilder.java index 5386aad..c069c67 100644 --- a/src/main/java/net/fabricmc/mappingpoet/FieldBuilder.java +++ b/src/main/java/net/fabricmc/mappingpoet/FieldBuilder.java @@ -16,20 +16,21 @@ package net.fabricmc.mappingpoet; -import java.util.AbstractMap; -import java.util.ArrayDeque; -import java.util.Deque; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - import com.squareup.javapoet.AnnotationSpec; import com.squareup.javapoet.ArrayTypeName; import com.squareup.javapoet.ClassName; import com.squareup.javapoet.CodeBlock; import com.squareup.javapoet.FieldSpec; +import com.squareup.javapoet.ParameterSpec; import com.squareup.javapoet.TypeName; import com.squareup.javapoet.TypeSpec; +import net.fabricmc.mapping.util.EntryTriple; +import net.fabricmc.mappingpoet.signature.AnnotationAwareDescriptors; +import net.fabricmc.mappingpoet.signature.AnnotationAwareSignatures; +import net.fabricmc.mappingpoet.signature.ClassStaticContext; +import net.fabricmc.mappingpoet.signature.TypeAnnotationBank; +import net.fabricmc.mappingpoet.signature.TypeAnnotationMapping; +import net.fabricmc.mappingpoet.signature.TypeAnnotationStorage; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.TypePath; @@ -38,19 +39,18 @@ import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.FieldNode; -import net.fabricmc.mapping.util.EntryTriple; -import net.fabricmc.mappingpoet.signature.AnnotationAwareDescriptors; -import net.fabricmc.mappingpoet.signature.AnnotationAwareSignatures; -import net.fabricmc.mappingpoet.signature.ClassStaticContext; -import net.fabricmc.mappingpoet.signature.TypeAnnotationBank; -import net.fabricmc.mappingpoet.signature.TypeAnnotationMapping; -import net.fabricmc.mappingpoet.signature.TypeAnnotationStorage; +import java.util.AbstractMap; +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.Iterator; +import java.util.List; +import java.util.Map; public class FieldBuilder { private final MappingsStore mappings; private final ClassNode classNode; private final FieldNode fieldNode; - private final FieldSpec.Builder builder; + private final FieldSpec.Builder builder; // todo extract interface to build both record param/field easily private final TypeAnnotationMapping annotations; private final ClassStaticContext context; @@ -129,90 +129,90 @@ public static Map.Entry parseType(final String desc, final in TypeName current; switch (desc.charAt(index)) { - case 'B': { - current = TypeName.BYTE; - index++; - break; - } - case 'C': { - current = TypeName.CHAR; - index++; - break; - } - case 'D': { - current = TypeName.DOUBLE; - index++; - break; - } - case 'F': { - current = TypeName.FLOAT; - index++; - break; - } - case 'I': { - current = TypeName.INT; - index++; - break; - } - case 'J': { - current = TypeName.LONG; - index++; - break; - } - case 'S': { - current = TypeName.SHORT; - index++; - break; - } - case 'Z': { - current = TypeName.BOOLEAN; - index++; - break; - } - case 'V': { - current = TypeName.VOID; - index++; - break; - } - case 'L': { - int classNameSeparator = index; - index++; - int nameStart = index; - ClassName currentClassName = null; - - char ch; - do { - ch = desc.charAt(index); - - if (ch == '$' || ch == ';') { - // collect class name - if (currentClassName == null) { - String packageName = nameStart < classNameSeparator ? desc.substring(nameStart, classNameSeparator).replace('/', '.') : ""; - String simpleName = desc.substring(classNameSeparator + 1, index); - currentClassName = ClassName.get(packageName, simpleName); - } else { - String simpleName = desc.substring(classNameSeparator + 1, index); - currentClassName = currentClassName.nestedClass(simpleName); + case 'B': { + current = TypeName.BYTE; + index++; + break; + } + case 'C': { + current = TypeName.CHAR; + index++; + break; + } + case 'D': { + current = TypeName.DOUBLE; + index++; + break; + } + case 'F': { + current = TypeName.FLOAT; + index++; + break; + } + case 'I': { + current = TypeName.INT; + index++; + break; + } + case 'J': { + current = TypeName.LONG; + index++; + break; + } + case 'S': { + current = TypeName.SHORT; + index++; + break; + } + case 'Z': { + current = TypeName.BOOLEAN; + index++; + break; + } + case 'V': { + current = TypeName.VOID; + index++; + break; + } + case 'L': { + int classNameSeparator = index; + index++; + int nameStart = index; + ClassName currentClassName = null; + + char ch; + do { + ch = desc.charAt(index); + + if (ch == '$' || ch == ';') { + // collect class name + if (currentClassName == null) { + String packageName = nameStart < classNameSeparator ? desc.substring(nameStart, classNameSeparator).replace('/', '.') : ""; + String simpleName = desc.substring(classNameSeparator + 1, index); + currentClassName = ClassName.get(packageName, simpleName); + } else { + String simpleName = desc.substring(classNameSeparator + 1, index); + currentClassName = currentClassName.nestedClass(simpleName); + } } - } - if (ch == '/' || ch == '$') { - // Start of simple name - classNameSeparator = index; - } + if (ch == '/' || ch == '$') { + // Start of simple name + classNameSeparator = index; + } - index++; - } while (ch != ';'); + index++; + } while (ch != ';'); - if (currentClassName == null) { - throw invalidDesc(desc, index); - } + if (currentClassName == null) { + throw invalidDesc(desc, index); + } - current = currentClassName; - break; - } - default: - throw invalidDesc(desc, index); + current = currentClassName; + break; + } + default: + throw invalidDesc(desc, index); } for (int i = 0; i < arrayLevel; i++) { @@ -233,101 +233,101 @@ public static Map.Entry parseAnnotatedType(final String desc, TypeName current; switch (desc.charAt(index)) { - case 'B': { - current = TypeName.BYTE; - index++; - break; - } - case 'C': { - current = TypeName.CHAR; - index++; - break; - } - case 'D': { - current = TypeName.DOUBLE; - index++; - break; - } - case 'F': { - current = TypeName.FLOAT; - index++; - break; - } - case 'I': { - current = TypeName.INT; - index++; - break; - } - case 'J': { - current = TypeName.LONG; - index++; - break; - } - case 'S': { - current = TypeName.SHORT; - index++; - break; - } - case 'Z': { - current = TypeName.BOOLEAN; - index++; - break; - } - case 'V': { - current = TypeName.VOID; - index++; - break; - } - case 'L': { - int classNameSeparator = index; - index++; - int nameStart = index; - ClassName currentClassName = null; - boolean instanceInner = false; - - char ch; - do { - ch = desc.charAt(index); - - if (ch == '$' || ch == ';') { - // collect class name - if (currentClassName == null) { - String packageName = nameStart < classNameSeparator ? desc.substring(nameStart, classNameSeparator).replace('/', '.') : ""; - String simpleName = desc.substring(classNameSeparator + 1, index); - currentClassName = ClassName.get(packageName, simpleName); - } else { - String simpleName = desc.substring(classNameSeparator + 1, index); - - if (!instanceInner && context.isInstanceInner(desc.substring(nameStart, index))) { - instanceInner = true; + case 'B': { + current = TypeName.BYTE; + index++; + break; + } + case 'C': { + current = TypeName.CHAR; + index++; + break; + } + case 'D': { + current = TypeName.DOUBLE; + index++; + break; + } + case 'F': { + current = TypeName.FLOAT; + index++; + break; + } + case 'I': { + current = TypeName.INT; + index++; + break; + } + case 'J': { + current = TypeName.LONG; + index++; + break; + } + case 'S': { + current = TypeName.SHORT; + index++; + break; + } + case 'Z': { + current = TypeName.BOOLEAN; + index++; + break; + } + case 'V': { + current = TypeName.VOID; + index++; + break; + } + case 'L': { + int classNameSeparator = index; + index++; + int nameStart = index; + ClassName currentClassName = null; + boolean instanceInner = false; + + char ch; + do { + ch = desc.charAt(index); + + if (ch == '$' || ch == ';') { + // collect class name + if (currentClassName == null) { + String packageName = nameStart < classNameSeparator ? desc.substring(nameStart, classNameSeparator).replace('/', '.') : ""; + String simpleName = desc.substring(classNameSeparator + 1, index); + currentClassName = ClassName.get(packageName, simpleName); + } else { + String simpleName = desc.substring(classNameSeparator + 1, index); + + if (!instanceInner && context.isInstanceInner(desc.substring(nameStart, index))) { + instanceInner = true; + } + + currentClassName = currentClassName.nestedClass(simpleName); + + if (instanceInner) { + currentClassName = AnnotationAwareDescriptors.annotate(currentClassName, annotations); + annotations = annotations.advance(TypePath.INNER_TYPE, 0); + } } + } - currentClassName = currentClassName.nestedClass(simpleName); - - if (instanceInner) { - currentClassName = AnnotationAwareDescriptors.annotate(currentClassName, annotations); - annotations = annotations.advance(TypePath.INNER_TYPE, 0); - } + if (ch == '/' || ch == '$') { + // Start of simple name + classNameSeparator = index; } - } - if (ch == '/' || ch == '$') { - // Start of simple name - classNameSeparator = index; - } + index++; + } while (ch != ';'); - index++; - } while (ch != ';'); + if (currentClassName == null) { + throw invalidDesc(desc, index); + } - if (currentClassName == null) { - throw invalidDesc(desc, index); + current = currentClassName; + break; } - - current = currentClassName; - break; - } - default: - throw invalidDesc(desc, index); + default: + throw invalidDesc(desc, index); } while (!arrayAnnos.isEmpty()) { @@ -348,24 +348,24 @@ private static IllegalArgumentException invalidDesc(String desc, int index) { @Deprecated // use typeFromDesc, non-recursive public static TypeName getFieldType(String desc) { switch (desc) { - case "B": - return TypeName.BYTE; - case "C": - return TypeName.CHAR; - case "S": - return TypeName.SHORT; - case "Z": - return TypeName.BOOLEAN; - case "I": - return TypeName.INT; - case "J": - return TypeName.LONG; - case "F": - return TypeName.FLOAT; - case "D": - return TypeName.DOUBLE; - case "V": - return TypeName.VOID; + case "B": + return TypeName.BYTE; + case "C": + return TypeName.CHAR; + case "S": + return TypeName.SHORT; + case "Z": + return TypeName.BOOLEAN; + case "I": + return TypeName.INT; + case "J": + return TypeName.LONG; + case "F": + return TypeName.FLOAT; + case "D": + return TypeName.DOUBLE; + case "V": + return TypeName.VOID; } if (desc.startsWith("[")) { return ArrayTypeName.of(getFieldType(desc.substring(1))); @@ -390,48 +390,48 @@ private FieldSpec.Builder createBuilder() { private CodeBlock makeInitializer(String desc) { // fake initializers exclude fields from constant values switch (desc.charAt(0)) { - case 'B': - if (fieldNode.value instanceof Integer) { - return CodeBlock.builder().add("(byte) $L", fieldNode.value).build(); - } - // fake initializer falls through - case 'C': - if (fieldNode.value instanceof Integer) { - int value = (int) fieldNode.value; - char c = (char) value; - return printChar(CodeBlock.builder(), c, value).build(); - } - // fake initializer falls through - case 'D': - if (fieldNode.value instanceof Double) { - return CodeBlock.builder().add("$LD", fieldNode.value).build(); - } - // fake initializer falls through - case 'I': - if (fieldNode.value instanceof Integer) { - return CodeBlock.builder().add("$L", fieldNode.value).build(); - } - // fake initializer falls through - case 'J': - if (fieldNode.value instanceof Long) { - return CodeBlock.builder().add("$LL", fieldNode.value).build(); - } - // fake initializer falls through - case 'S': - if (fieldNode.value instanceof Integer) { - return CodeBlock.builder().add("(short) $L", fieldNode.value).build(); - } - return CodeBlock.builder().add("java.lang.Byte.parseByte(\"dummy\")").build(); - case 'F': - if (fieldNode.value instanceof Float) { - return CodeBlock.builder().add("$LF", fieldNode.value).build(); - } - return CodeBlock.builder().add("java.lang.Float.parseFloat(\"dummy\")").build(); - case 'Z': - if (fieldNode.value instanceof Integer) { - return CodeBlock.builder().add("$L", ((int) fieldNode.value) != 0).build(); - } - return CodeBlock.builder().add("java.lang.Boolean.parseBoolean(\"dummy\")").build(); + case 'B': + if (fieldNode.value instanceof Integer) { + return CodeBlock.builder().add("(byte) $L", fieldNode.value).build(); + } + // fake initializer falls through + case 'C': + if (fieldNode.value instanceof Integer) { + int value = (int) fieldNode.value; + char c = (char) value; + return printChar(CodeBlock.builder(), c, value).build(); + } + // fake initializer falls through + case 'D': + if (fieldNode.value instanceof Double) { + return CodeBlock.builder().add("$LD", fieldNode.value).build(); + } + // fake initializer falls through + case 'I': + if (fieldNode.value instanceof Integer) { + return CodeBlock.builder().add("$L", fieldNode.value).build(); + } + // fake initializer falls through + case 'J': + if (fieldNode.value instanceof Long) { + return CodeBlock.builder().add("$LL", fieldNode.value).build(); + } + // fake initializer falls through + case 'S': + if (fieldNode.value instanceof Integer) { + return CodeBlock.builder().add("(short) $L", fieldNode.value).build(); + } + return CodeBlock.builder().add("java.lang.Byte.parseByte(\"dummy\")").build(); + case 'F': + if (fieldNode.value instanceof Float) { + return CodeBlock.builder().add("$LF", fieldNode.value).build(); + } + return CodeBlock.builder().add("java.lang.Float.parseFloat(\"dummy\")").build(); + case 'Z': + if (fieldNode.value instanceof Integer) { + return CodeBlock.builder().add("$L", ((int) fieldNode.value) != 0).build(); + } + return CodeBlock.builder().add("java.lang.Boolean.parseBoolean(\"dummy\")").build(); } if (desc.equals("Ljava/lang/String;") && fieldNode.value instanceof String) { return CodeBlock.builder().add("$S", fieldNode.value).build(); @@ -448,20 +448,20 @@ private static CodeBlock.Builder printChar(CodeBlock.Builder builder, char c, in // See https://docs.oracle.com/javase/specs/jls/se16/html/jls-3.html#jls-EscapeSequence // ignore space or ", just use direct in those cases switch (c) { - case '\b': - return builder.add("'\\b'"); - case '\t': - return builder.add("'\\t'"); - case '\n': - return builder.add("'\\n'"); - case '\f': - return builder.add("'\\f'"); - case '\r': - return builder.add("'\\r'"); - case '\'': - return builder.add("'\\''"); - case '\\': - return builder.add("'\\\\'"); + case '\b': + return builder.add("'\\b'"); + case '\t': + return builder.add("'\\t'"); + case '\n': + return builder.add("'\\n'"); + case '\f': + return builder.add("'\\f'"); + case '\r': + return builder.add("'\\r'"); + case '\'': + return builder.add("'\\''"); + case '\\': + return builder.add("'\\\\'"); } return builder.add("'$L'", c); @@ -471,6 +471,10 @@ private void addJavaDoc() { mappings.addFieldDoc(builder::addJavadoc, new EntryTriple(classNode.name, fieldNode.name, fieldNode.desc)); } + void addJavaDoc(ParameterSpec.Builder paramBuilder) { + mappings.addFieldDoc(paramBuilder::addJavadoc, new EntryTriple(classNode.name, fieldNode.name, fieldNode.desc)); + } + private void addDirectAnnotations() { addDirectAnnotations(fieldNode.invisibleAnnotations); addDirectAnnotations(fieldNode.visibleAnnotations); @@ -485,7 +489,21 @@ private void addDirectAnnotations(List regularAnnotations) { } } - private TypeName calculateType() { + void addDirectAnnotations(ParameterSpec.Builder paramBuilder) { + addDirectAnnotations(paramBuilder, fieldNode.invisibleAnnotations); + addDirectAnnotations(paramBuilder, fieldNode.visibleAnnotations); + } + + private void addDirectAnnotations(ParameterSpec.Builder paramBuilder, List regularAnnotations) { + if (regularAnnotations == null) { + return; + } + for (AnnotationNode annotation : regularAnnotations) { + paramBuilder.addAnnotation(parseAnnotation(annotation)); + } + } + + TypeName calculateType() { if (fieldNode.signature != null) { return AnnotationAwareSignatures.parseFieldSignature(fieldNode.signature, annotations, context); } diff --git a/src/main/java/net/fabricmc/mappingpoet/Main.java b/src/main/java/net/fabricmc/mappingpoet/Main.java index d07c56b..31a83cf 100644 --- a/src/main/java/net/fabricmc/mappingpoet/Main.java +++ b/src/main/java/net/fabricmc/mappingpoet/Main.java @@ -16,6 +16,14 @@ package net.fabricmc.mappingpoet; +import com.squareup.javapoet.JavaFile; +import net.fabricmc.mappingpoet.signature.ClassStaticContext; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.InnerClassNode; + import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -33,22 +41,16 @@ import java.util.Comparator; import java.util.Enumeration; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; +import java.util.function.Predicate; import java.util.jar.JarEntry; import java.util.jar.JarFile; -import com.squareup.javapoet.JavaFile; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.ClassNode; -import org.objectweb.asm.tree.InnerClassNode; - -import net.fabricmc.mappingpoet.signature.ClassStaticContext; - public class Main { public static void main(String[] args) { @@ -90,7 +92,7 @@ public static void main(String[] args) { public static void generate(Path mappings, Path inputJar, Path outputDirectory, Path librariesDir) { final MappingsStore mapping = new MappingsStore(mappings); Map classes = new HashMap<>(); - forEachClass(inputJar, (superGetter, classNode, context) -> writeClass(mapping, classNode, classes, superGetter, context), librariesDir); + forEachClass(inputJar, (superGetter, classNode, context, sealChecker) -> writeClass(mapping, classNode, classes, superGetter, sealChecker, context), librariesDir); classes.values().stream() .filter(classBuilder -> !classBuilder.getClassName().contains("$")) @@ -111,6 +113,7 @@ public static void generate(Path mappings, Path inputJar, Path outputDirectory, private static void forEachClass(Path jar, ClassNodeConsumer classNodeConsumer, Path librariesDir) { List classes = new ArrayList<>(); Map> supers = new HashMap<>(); + Set sealedClasses = new HashSet<>(); // their subclsses/impls need non-sealed modifier Map instanceInnerClasses = new ConcurrentHashMap<>(); @@ -149,6 +152,10 @@ private static void forEachClass(Path jar, ClassNodeConsumer classNodeConsumer, } } + if (classNode.permittedSubclasses != null) { + sealedClasses.add(classNode.name); + } + classes.add(classNode); } } @@ -161,7 +168,7 @@ private static void forEachClass(Path jar, ClassNodeConsumer classNodeConsumer, ClassStaticContext innerClassContext = new InnerClassStats(instanceInnerClasses); Function> superGetter = k -> supers.getOrDefault(k, Collections.emptyList()); - classes.forEach(node -> classNodeConsumer.accept(superGetter, node, innerClassContext)); + classes.forEach(node -> classNodeConsumer.accept(superGetter, node, innerClassContext, sealedClasses::contains)); } private static void scanInnerClasses(Map instanceInnerClasses, Path librariesDir) { @@ -218,7 +225,7 @@ private static boolean isDigit(char ch) { return ch >= '0' && ch <= '9'; } - private static void writeClass(MappingsStore mappings, ClassNode classNode, Map existingClasses, Function> superGetter, ClassStaticContext context) { + private static void writeClass(MappingsStore mappings, ClassNode classNode, Map existingClasses, Function> superGetter, Predicate sealChecker, ClassStaticContext context) { String name = classNode.name; { //Block anonymous class and their nested classes @@ -232,7 +239,7 @@ private static void writeClass(MappingsStore mappings, ClassNode classNode, Map< } } - ClassBuilder classBuilder = new ClassBuilder(mappings, classNode, superGetter, context); + ClassBuilder classBuilder = new ClassBuilder(mappings, classNode, superGetter, sealChecker, context); if (name.contains("$")) { String parentClass = name.substring(0, name.lastIndexOf("$")); @@ -249,7 +256,7 @@ private static void writeClass(MappingsStore mappings, ClassNode classNode, Map< @FunctionalInterface private interface ClassNodeConsumer { - void accept(Function> superGetter, ClassNode node, ClassStaticContext staticContext); + void accept(Function> superGetter, ClassNode node, ClassStaticContext staticContext, Predicate sealedChecker); } private static final class InnerClassStats implements ClassStaticContext { diff --git a/src/main/java/net/fabricmc/mappingpoet/ModifierBuilder.java b/src/main/java/net/fabricmc/mappingpoet/ModifierBuilder.java index dad1d81..dcc7c79 100644 --- a/src/main/java/net/fabricmc/mappingpoet/ModifierBuilder.java +++ b/src/main/java/net/fabricmc/mappingpoet/ModifierBuilder.java @@ -16,19 +16,44 @@ package net.fabricmc.mappingpoet; -import java.util.ArrayList; -import java.util.List; +import org.objectweb.asm.tree.ClassNode; import javax.lang.model.element.Modifier; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Predicate; public class ModifierBuilder { private final int access; + private boolean needsUnseal; public ModifierBuilder(int access) { this.access = access; } + public ModifierBuilder checkUnseal(ClassNode node, Predicate sealChecker) { + if (java.lang.reflect.Modifier.isFinal(node.access)) { + return this; + } + + if (node.interfaces != null) { + for (String itf : node.interfaces) { + if (sealChecker.test(itf)) { + needsUnseal = true; + return this; + } + } + } + + if (node.superName != null && sealChecker.test(node.superName)) { + needsUnseal = true; + } + + + return this; + } + public Modifier[] getModifiers(Type type) { List modifiers = new ArrayList<>(); @@ -36,7 +61,7 @@ public Modifier[] getModifiers(Type type) { if (java.lang.reflect.Modifier.isFinal(access)) { modifiers.add(Modifier.FINAL); } - return modifiers.toArray(new Modifier[] {}); + return modifiers.toArray(new Modifier[]{}); } if (java.lang.reflect.Modifier.isPublic(access)) { @@ -57,7 +82,7 @@ public Modifier[] getModifiers(Type type) { modifiers.add(Modifier.DEFAULT); } - if (java.lang.reflect.Modifier.isFinal(access) && type != Type.ENUM) { + if (java.lang.reflect.Modifier.isFinal(access) && type != Type.ENUM && type != Type.RECORD) { modifiers.add(Modifier.FINAL); } if (java.lang.reflect.Modifier.isTransient(access) && type == Type.FIELD) { @@ -76,12 +101,21 @@ public Modifier[] getModifiers(Type type) { modifiers.add(Modifier.STRICTFP); } - return modifiers.toArray(new Modifier[] {}); + if (needsUnseal && type == Type.CLASS) { + modifiers.add(Modifier.NON_SEALED); + } + + return modifiers.toArray(new Modifier[]{}); + } + + public static Type getType(boolean enumType, boolean recordType) { + return enumType ? Type.ENUM : recordType ? Type.RECORD : Type.CLASS; } public enum Type { CLASS, ENUM, + RECORD, METHOD, FIELD, PARAM From 512c27eb30486bc675a5ec8db90b6d1f6bf3a656 Mon Sep 17 00:00:00 2001 From: liach Date: Sun, 19 Sep 2021 11:26:23 -0500 Subject: [PATCH 25/43] It works. Bump to 0.2.9, don't expose the github dependency (requires github login, pita) --- build.gradle | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index b256cc8..59e6fb6 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ plugins { } group 'net.fabricmc' -version '0.2.8' +version '0.2.9' def ENV = System.getenv() version = version + (ENV.GITHUB_ACTIONS ? "" : "+local") @@ -28,9 +28,17 @@ repositories { } } +configurations { + ship + runtimeClasspath.extendsFrom ship + compileOnly.extendsFrom ship + testRuntimeClasspath.extendsFrom ship + testCompileOnly.extendsFrom ship +} + dependencies { //implementation 'com.squareup:javapoet:1.13.0' - implementation 'com.github.liachmodded:javapoet:0.0.3' + ship 'com.github.liachmodded:javapoet:0.0.3' implementation 'net.fabricmc:tiny-mappings-parser:0.3.0+build.17' runtimeOnly 'com.google.guava:guava:30.1.1-jre' @@ -64,6 +72,11 @@ tasks.withType(Jar) { } jar { + from { + configurations.ship.collect { + it.isDirectory() ? it : zipTree(it) + } + } manifest { attributes 'Implementation-Title': 'MappingPoet', 'Implementation-Version': archiveVersion, From e871a21c1b6ef3285877c9a98d652ae97e0ed8df Mon Sep 17 00:00:00 2001 From: liach Date: Thu, 23 Sep 2021 15:24:50 -0500 Subject: [PATCH 26/43] Consider package private final fields in record as components for proguard Signed-off-by: liach --- build.gradle | 2 +- src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 59e6fb6..758fb0d 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ plugins { } group 'net.fabricmc' -version '0.2.9' +version '0.2.10' def ENV = System.getenv() version = version + (ENV.GITHUB_ACTIONS ? "" : "+local") diff --git a/src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java b/src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java index 1a1d0b1..b81c85f 100644 --- a/src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java +++ b/src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java @@ -266,7 +266,8 @@ private void addFields() { if (classNode.fields == null) return; for (FieldNode field : classNode.fields) { if (recordClass && !Modifier.isStatic(field.access)) { - if (!Modifier.isFinal(field.access) || !Modifier.isPrivate(field.access)) { + // proguard elevates record field access for direct record field gets + if (!Modifier.isFinal(field.access) || Modifier.isProtected(field.access) || Modifier.isPublic(field.access)) { System.out.println("abnormal instance field " + field.name + " in record " + getClassName() + ", skipping"); } else { var fieldBuilder = new FieldBuilder(mappings, classNode, field, context); From 03eb545fd46c4a12c8264a26ee6367d4b0a2872e Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Wed, 27 Oct 2021 19:00:01 +0100 Subject: [PATCH 27/43] Build against fabric's javapoet fork --- build.gradle | 31 +++++-------------------------- 1 file changed, 5 insertions(+), 26 deletions(-) diff --git a/build.gradle b/build.gradle index 758fb0d..1c5400a 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ plugins { } group 'net.fabricmc' -version '0.2.10' +version '0.3.0' def ENV = System.getenv() version = version + (ENV.GITHUB_ACTIONS ? "" : "+local") @@ -16,29 +16,10 @@ repositories { name = 'Fabric' url = 'https://maven.modmuss50.me/' } - maven { - name = "GitHub" - url = uri("https://maven.pkg.github.com/liachmodded/javapoet") - credentials { - // any user can generate an access token at https://github.com/settings/tokens as password - // just need the read:packages permission - username = findProperty('github_user') ?: ENV.GITHUB_ACTOR - password = findProperty('github_read_key') ?: ENV.GITHUB_TOKEN - } - } -} - -configurations { - ship - runtimeClasspath.extendsFrom ship - compileOnly.extendsFrom ship - testRuntimeClasspath.extendsFrom ship - testCompileOnly.extendsFrom ship } dependencies { - //implementation 'com.squareup:javapoet:1.13.0' - ship 'com.github.liachmodded:javapoet:0.0.3' + implementation 'net.fabricmc:javapoet:0.1.0' implementation 'net.fabricmc:tiny-mappings-parser:0.3.0+build.17' runtimeOnly 'com.google.guava:guava:30.1.1-jre' @@ -56,6 +37,9 @@ java { withSourcesJar() } +sourceCompatibility = 17 +targetCompatibility = 17 + tasks.withType(JavaCompile) { options.release = 17 options.encoding = "UTF-8" @@ -72,11 +56,6 @@ tasks.withType(Jar) { } jar { - from { - configurations.ship.collect { - it.isDirectory() ? it : zipTree(it) - } - } manifest { attributes 'Implementation-Title': 'MappingPoet', 'Implementation-Version': archiveVersion, From 56ddd7f09580d9a6a3b3c2f6dd3873dc77ff994d Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Wed, 27 Oct 2021 19:21:36 +0100 Subject: [PATCH 28/43] Remove default modifier from private interface methods. --- src/main/java/net/fabricmc/mappingpoet/MethodBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/net/fabricmc/mappingpoet/MethodBuilder.java b/src/main/java/net/fabricmc/mappingpoet/MethodBuilder.java index 8c3b181..4968448 100644 --- a/src/main/java/net/fabricmc/mappingpoet/MethodBuilder.java +++ b/src/main/java/net/fabricmc/mappingpoet/MethodBuilder.java @@ -153,7 +153,7 @@ static String suggestName(TypeName type) { private MethodSpec.Builder createBuilder() { MethodSpec.Builder builder = MethodSpec.methodBuilder(methodNode.name) .addModifiers(new ModifierBuilder(methodNode.access).getModifiers(ModifierBuilder.Type.METHOD)); - if (methodNode.name.equals("") || !java.lang.reflect.Modifier.isInterface(classNode.access)) { + if (methodNode.name.equals("") || !java.lang.reflect.Modifier.isInterface(classNode.access) || java.lang.reflect.Modifier.isPrivate(methodNode.access)) { builder.modifiers.remove(Modifier.DEFAULT); } From e87bc5c63ab41194defacfbe0451dd2cc522a55a Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Wed, 27 Oct 2021 19:45:02 +0100 Subject: [PATCH 29/43] Skip over anonymous records to fix generation failure. @liach you might be better suited to take a better look at this. Can we move inline classes/records into their method? If so would the javadoc work for that? --- src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java b/src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java index b81c85f..5989657 100644 --- a/src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java +++ b/src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java @@ -324,6 +324,12 @@ public void addInnerClass(ClassBuilder classBuilder) { if (classNode.innerClasses != null) { for (InnerClassNode node : classNode.innerClasses) { if (node.name.equals(classBuilder.classNode.name)) { + if (node.outerName == null && classBuilder.recordClass) { + // Inline anonymous record. + // TODO look into moving this into the method that defines it. + return; + } + innerClassNode = node; break; } From f4b8811ad298519d1d69436c7b9640d0fc34940b Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Wed, 27 Oct 2021 20:05:58 +0100 Subject: [PATCH 30/43] Remove github token from actions. --- .github/workflows/build.yml | 5 +---- .github/workflows/release.yml | 2 -- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3079640..5a2abc1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,7 +12,4 @@ jobs: steps: - uses: actions/checkout@v1 - uses: gradle/wrapper-validation-action@v1 - - run: ./gradlew build test --stacktrace - env: - GITHUB_ACTOR: ${{ github.actor }} - GITHUB_TOKEN: ${{ github.token }} + - run: ./gradlew build test --stacktrace \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 760ffaf..8e8fd21 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -14,5 +14,3 @@ jobs: MAVEN_URL: ${{ secrets.MAVEN_URL }} MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }} MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }} - GITHUB_ACTOR: ${{ github.actor }} - GITHUB_TOKEN: ${{ github.token }} From 15aeb4c52b3de1ab5610a98ee7d5992d248605ae Mon Sep 17 00:00:00 2001 From: liach Date: Wed, 17 Nov 2021 17:34:41 -0600 Subject: [PATCH 31/43] This looks like why it was problematic Signed-off-by: liach --- .../java/net/fabricmc/mappingpoet/ClassBuilder.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java b/src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java index 5989657..98d0a53 100644 --- a/src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java +++ b/src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java @@ -324,22 +324,22 @@ public void addInnerClass(ClassBuilder classBuilder) { if (classNode.innerClasses != null) { for (InnerClassNode node : classNode.innerClasses) { if (node.name.equals(classBuilder.classNode.name)) { - if (node.outerName == null && classBuilder.recordClass) { - // Inline anonymous record. - // TODO look into moving this into the method that defines it. - return; - } - innerClassNode = node; break; } } } + if (innerClassNode == null) { // fallback classBuilder.builder.addModifiers(javax.lang.model.element.Modifier.PUBLIC); classBuilder.builder.addModifiers(javax.lang.model.element.Modifier.STATIC); } else { + if (innerClassNode.outerName == null) { + // skip local classes and records, which have null outerName + return; + } + classBuilder.builder.modifiers.remove(javax.lang.model.element.Modifier.PUBLIC); // this modifier may come from class access classBuilder.builder.addModifiers(new ModifierBuilder(innerClassNode.access) .checkUnseal(classBuilder.classNode, sealChecker) From 9c306040600ae42011538e100b2cff5798426106 Mon Sep 17 00:00:00 2001 From: liach Date: Thu, 18 Nov 2021 16:55:59 -0600 Subject: [PATCH 32/43] Add taglet for putting up record stripping warnings Signed-off-by: liach --- build.gradle | 2 +- .../fabricmc/mappingpoet/ClassBuilder.java | 5 ++ .../mappingpoet/jd/RecordWarningTaglet.java | 55 +++++++++++++++++++ src/main/resources/record_warning.txt | 7 +++ 4 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 src/main/java/net/fabricmc/mappingpoet/jd/RecordWarningTaglet.java create mode 100644 src/main/resources/record_warning.txt diff --git a/build.gradle b/build.gradle index 1c5400a..d407eec 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ plugins { } group 'net.fabricmc' -version '0.3.0' +version '0.3.1' def ENV = System.getenv() version = version + (ENV.GITHUB_ACTIONS ? "" : "+local") diff --git a/src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java b/src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java index 98d0a53..11382cc 100644 --- a/src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java +++ b/src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java @@ -317,6 +317,11 @@ private void addDirectAnnotations(TypeSpec.Builder builder, List private void addJavaDoc() { mappings.addClassDoc(builder::addJavadoc, classNode.name); + + // record warning text block + if (recordClass) { + builder.addJavadoc("@fabricRecordWarning\n"); + } } public void addInnerClass(ClassBuilder classBuilder) { diff --git a/src/main/java/net/fabricmc/mappingpoet/jd/RecordWarningTaglet.java b/src/main/java/net/fabricmc/mappingpoet/jd/RecordWarningTaglet.java new file mode 100644 index 0000000..69b90bb --- /dev/null +++ b/src/main/java/net/fabricmc/mappingpoet/jd/RecordWarningTaglet.java @@ -0,0 +1,55 @@ +package net.fabricmc.mappingpoet.jd; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.UncheckedIOException; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import javax.lang.model.element.Element; + +import com.sun.source.doctree.DocTree; +import jdk.javadoc.doclet.Taglet; + +public final class RecordWarningTaglet implements Taglet { + + private final String warningText; + + public RecordWarningTaglet() { + try (InputStream stream = RecordWarningTaglet.class.getResourceAsStream("/record_warning.txt")) { + if (stream == null) { + throw new IllegalStateException("Cannot find record_warning.txt file!"); + } + + try (BufferedReader reader = new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8))) { + this.warningText = reader.lines().collect(Collectors.joining("\n")); + } + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + } + + @Override + public Set getAllowedLocations() { + return Set.of(Location.TYPE); + } + + @Override + public boolean isInlineTag() { + return false; + } + + @Override + public String getName() { + return "fabricRecordWarning"; + } + + @Override + public String toString(List tags, Element element) { + return this.warningText; + } +} diff --git a/src/main/resources/record_warning.txt b/src/main/resources/record_warning.txt new file mode 100644 index 0000000..0deb2b5 --- /dev/null +++ b/src/main/resources/record_warning.txt @@ -0,0 +1,7 @@ + From 9ca92a1a36f76f3ff1abbe282bb8c19821bff050 Mon Sep 17 00:00:00 2001 From: liach Date: Thu, 18 Nov 2021 16:58:47 -0600 Subject: [PATCH 33/43] license --- .../mappingpoet/jd/RecordWarningTaglet.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/main/java/net/fabricmc/mappingpoet/jd/RecordWarningTaglet.java b/src/main/java/net/fabricmc/mappingpoet/jd/RecordWarningTaglet.java index 69b90bb..82f5402 100644 --- a/src/main/java/net/fabricmc/mappingpoet/jd/RecordWarningTaglet.java +++ b/src/main/java/net/fabricmc/mappingpoet/jd/RecordWarningTaglet.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2020 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package net.fabricmc.mappingpoet.jd; import java.io.BufferedReader; From 1fda8f9c3408668ec6589c3949ed09df86794235 Mon Sep 17 00:00:00 2001 From: liach Date: Mon, 22 Nov 2021 18:09:17 -0600 Subject: [PATCH 34/43] Revert "license" This reverts commit 9ca92a1a36f76f3ff1abbe282bb8c19821bff050. Revert "Add taglet for putting up record stripping warnings" This reverts commit 9c306040600ae42011538e100b2cff5798426106. --- build.gradle | 2 +- .../fabricmc/mappingpoet/ClassBuilder.java | 5 -- .../mappingpoet/jd/RecordWarningTaglet.java | 71 ------------------- src/main/resources/record_warning.txt | 7 -- 4 files changed, 1 insertion(+), 84 deletions(-) delete mode 100644 src/main/java/net/fabricmc/mappingpoet/jd/RecordWarningTaglet.java delete mode 100644 src/main/resources/record_warning.txt diff --git a/build.gradle b/build.gradle index d407eec..1c5400a 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ plugins { } group 'net.fabricmc' -version '0.3.1' +version '0.3.0' def ENV = System.getenv() version = version + (ENV.GITHUB_ACTIONS ? "" : "+local") diff --git a/src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java b/src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java index 11382cc..98d0a53 100644 --- a/src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java +++ b/src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java @@ -317,11 +317,6 @@ private void addDirectAnnotations(TypeSpec.Builder builder, List private void addJavaDoc() { mappings.addClassDoc(builder::addJavadoc, classNode.name); - - // record warning text block - if (recordClass) { - builder.addJavadoc("@fabricRecordWarning\n"); - } } public void addInnerClass(ClassBuilder classBuilder) { diff --git a/src/main/java/net/fabricmc/mappingpoet/jd/RecordWarningTaglet.java b/src/main/java/net/fabricmc/mappingpoet/jd/RecordWarningTaglet.java deleted file mode 100644 index 82f5402..0000000 --- a/src/main/java/net/fabricmc/mappingpoet/jd/RecordWarningTaglet.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2020 FabricMC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.fabricmc.mappingpoet.jd; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.UncheckedIOException; -import java.nio.charset.StandardCharsets; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -import javax.lang.model.element.Element; - -import com.sun.source.doctree.DocTree; -import jdk.javadoc.doclet.Taglet; - -public final class RecordWarningTaglet implements Taglet { - - private final String warningText; - - public RecordWarningTaglet() { - try (InputStream stream = RecordWarningTaglet.class.getResourceAsStream("/record_warning.txt")) { - if (stream == null) { - throw new IllegalStateException("Cannot find record_warning.txt file!"); - } - - try (BufferedReader reader = new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8))) { - this.warningText = reader.lines().collect(Collectors.joining("\n")); - } - } catch (IOException ex) { - throw new UncheckedIOException(ex); - } - } - - @Override - public Set getAllowedLocations() { - return Set.of(Location.TYPE); - } - - @Override - public boolean isInlineTag() { - return false; - } - - @Override - public String getName() { - return "fabricRecordWarning"; - } - - @Override - public String toString(List tags, Element element) { - return this.warningText; - } -} diff --git a/src/main/resources/record_warning.txt b/src/main/resources/record_warning.txt deleted file mode 100644 index 0deb2b5..0000000 --- a/src/main/resources/record_warning.txt +++ /dev/null @@ -1,7 +0,0 @@ -
Warning: This class is not a record at runtime! -
Due to Proguard processing, This class is not a record at - runtime when inspected by reflection. In addition, if this record has any type parameter, - inspecting generic types through reflection may have unexpected results or throw exceptions. - See - The Fabric Wiki for more details.
-
From 93a57cfd6a8536b5bdd199b5e89b3df6a4f6e188 Mon Sep 17 00:00:00 2001 From: liach Date: Sun, 20 Mar 2022 14:57:08 -0500 Subject: [PATCH 35/43] Do not dump local class by checking EnclosingMethod attribute --- src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java b/src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java index 98d0a53..51a92cc 100644 --- a/src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java +++ b/src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java @@ -340,6 +340,11 @@ public void addInnerClass(ClassBuilder classBuilder) { return; } + if (classBuilder.classNode.outerMethod != null) { + // local class per EnclosingMethod attribute + return; + } + classBuilder.builder.modifiers.remove(javax.lang.model.element.Modifier.PUBLIC); // this modifier may come from class access classBuilder.builder.addModifiers(new ModifierBuilder(innerClassNode.access) .checkUnseal(classBuilder.classNode, sealChecker) From bed78ea0a093a4f68bd276a446db682fb3d72c9f Mon Sep 17 00:00:00 2001 From: liach Date: Sun, 20 Mar 2022 14:58:15 -0500 Subject: [PATCH 36/43] Update gradle, bump version --- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.jar | Bin 59536 -> 59821 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 10 +++++----- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/build.gradle b/build.gradle index 1c5400a..d407eec 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ plugins { } group 'net.fabricmc' -version '0.3.0' +version '0.3.1' def ENV = System.getenv() version = version + (ENV.GITHUB_ACTIONS ? "" : "+local") diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 7454180f2ae8848c63b8b4dea2cb829da983f2fa..41d9927a4d4fb3f96a785543079b8df6723c946b 100644 GIT binary patch delta 8958 zcmY+KWl$VIlZIh&f(Hri?gR<$?iyT!TL`X;1^2~W7YVSq1qtqM!JWlDxLm%}UESUM zndj}Uny%^UnjhVhFb!8V3s(a#fIy>`VW15{5nuy;_V&a5O#0S&!a4dSkUMz_VHu3S zGA@p9Q$T|Sj}tYGWdjH;Mpp8m&yu&YURcrt{K;R|kM~(*{v%QwrBJIUF+K1kX5ZmF zty3i{d`y0;DgE+de>vN@yYqFPe1Ud{!&G*Q?iUc^V=|H%4~2|N zW+DM)W!`b&V2mQ0Y4u_)uB=P@-2`v|Wm{>CxER1P^ z>c}ZPZ)xxdOCDu59{X^~2id7+6l6x)U}C4Em?H~F`uOxS1?}xMxTV|5@}PlN%Cg$( zwY6c}r60=z5ZA1L zTMe;84rLtYvcm?M(H~ZqU;6F7Evo{P7!LGcdwO|qf1w+)MsnvK5^c@Uzj<{ zUoej1>95tuSvDJ|5K6k%&UF*uE6kBn47QJw^yE&#G;u^Z9oYWrK(+oL97hBsUMc_^ z;-lmxebwlB`Er_kXp2$`&o+rPJAN<`WX3ws2K{q@qUp}XTfV{t%KrsZ5vM!Q#4{V& zq>iO$MCiLq#%wXj%`W$_%FRg_WR*quv65TdHhdpV&jlq<=K^K`&!Kl5mA6p4n~p3u zWE{20^hYpn1M}}VmSHBXl1*-)2MP=0_k)EPr#>EoZukiXFDz?Di1I>2@Z^P$pvaF+ zN+qUy63jek2m59;YG)`r^F3-O)0RDIXPhf)XOOdkmu`3SMMSW(g+`Ajt{=h1dt~ks ztrhhP|L4G%5x79N#kwAHh5N){@{fzE7n&%dnisCm65Za<8r_hKvfx4Bg*`%-*-Mvn zFvn~)VP@}1sAyD+B{{8l{EjD10Av&Mz9^Xff*t`lU=q=S#(|>ls520;n3<}X#pyh& z*{CJf7$*&~!9jMnw_D~ikUKJ2+UnXmN6qak{xx%W;BKuXt7@ky!LPI1qk?gDwG@@o zkY+BkIie>{{q==5)kXw(*t#I?__Kwi>`=+s?Gq6X+vtSsaAO&Tf+Bl$vKnzc&%BHM z=loWOQq~n}>l=EL(5&6((ESsQC3^@4jlO5Od{qN#sWV)vqXw}aA>*uvwZopNN(|-T zRTF%5Y_k1R$;(d-)n;hWex{;7b6KgdAVE@&0pd(*qDzBO#YZV%kh%pYt1`hnQ(Fa& zYiDrOTDqk5M7hzp9kI2h!PxNnuJ&xl*zF8sx6!67bA49R1bmUF5bpK&&{eI0U~cH}PM z3aW1$lRb|ItkG5~_eBNu$|I|vYIdAA9a!pVq<+UTx*M}fG`23zxXp&E=FfnY- zEzKj;Cu_s4v>leO7M2-mE(UzKHL4c$c`3dS*19OpLV^4NI*hWWnJQ9lvzP4c;c?do zqrcsKT*i~eIHl0D3r4N{)+RsB6XhrC^;sp2cf_Eq#6*CV;t8v=V!ISe>>9kPgh}NI z=1UZutslxcT$Ad;_P^;Oouoa(cs!Ctpvi>%aQ+Zp=1d|h{W9Wmf7JWxa(~<#tSZ?C%wu4_5F!fc!<@PIBeJ)Nr^$bB6!_Gic_7}c3J{QI~Gg5g5jTp9}V6KYgrgaX>pJt}7$!wOht&KO|+z{Iw@YL|@~D zMww}+lG}rm2^peNx>58ME||ZQxFQeVSX8iogHLq_vXb`>RnoEKaTWBF-$JD#Q4BMv zt2(2Qb*x-?ur1Y(NsW8AdtX0#rDB?O(Vs4_xA(u-o!-tBG03OI!pQD+2UytbL5>lG z*(F)KacHqMa4?dxa(Vcrw>IIAeB$3cx#;;5r2X;HE8|}eYdAgCw#tpXNy7C3w1q`9 zGxZ6;@1G%8shz9e+!K2MO*{_RjO}Jo6eL3{TSZ>nY7)Qs`Dhi5><@oh0r)gT7H-?3 zLDsd^@m%JvrS8sta5`QiZNs^*GT}Hiy^zjK2^Ni%`Z|ma)D2 zuyumbvw$M8$haCTI~6M%d4+P)uX%u{Sfg4Al+F7c6;O-*)DKI7E8izSOKB#FcV{M+ zEvY0FBkq!$J0EW$Cxl}3{JwV^ki-T?q6C30Y5e&p@8Rd?$ST-Ghn*-`tB{k54W<>F z5I)TFpUC!E9298=sk>m#FI4sUDy_!8?51FqqW!9LN1(zuDnB3$!pEUjL>N>RNgAG~-9Xm|1lqHseW(%v&6K(DZ3Pano(1-Qe?3%J&>0`~w^Q-p&@ zg@HjvhJk?*hpF7$9P|gkzz`zBz_5Z!C4_-%fCcAgiSilzFQef!@amHDrW!YZS@?7C zs2Y9~>yqO+rkih?kXztzvnB^6W=f52*iyuZPv$c42$WK7>PHb z6%MYIr5D32KPdwL1hJf{_#jn?`k(taW?mwmZVvrr=y~fNcV$`}v(8};o9AjOJumS4 z`889O91^pkF+|@$d9wVoZ3;^j;^sUs&Ubo_qD&MTL%O z&*SE0ujG~zm;?x)8TLC&ft))nyI zcg44@*Q{cYT+qGrA=In_X{NNCD+B0w#;@g)jvBU;_8od6U>;7HIo@F*=g8CQUo(u^ z3r4FJ7#<@)MXO&5+DgKE&^>^`r!loe7CWE*1k0*0wLFzSOV8jvlX~WOQ?$1v zk$Or}!;ix0g78^6W;+<=J>z@CBs!<<)HvF(Ls-&`matpesJ5kkjC)6nGB@b{ii6-Uoho$BT%iJgugTOeZ$5Xo4D7Pd< zC*LJh5V@2#5%aBZCgzlQi3@<_!VfiL07ywc)ZbwKPfcR|ElQoS(8x|a7#IR}7#Io= zwg4$8S{egr-NffD)Fg&X9bJSoM25pF&%hf>(T&9bI}=#dPQyNYz;ZZ7EZ=u1n701SWKkZ9n(-qU ztN`sdWL1uxQ1mKS@x11;O|@^AD9!NeoPx}?EKIr!2>1Qq4gjfGU)tr6?Z5l7JAS3j zZeq{vG{rb%DFE4%$szK}d2UzB{4>L?Tv+NAlE*&Nq6g+XauaSI+N2Y8PJLw+aNg1p zbxr|hI8wcMP&&+(Cu|%+Jq|r>+BHk@{AvfBXKiVldN)@}TBS0LdIpnANCVE26WL-} zV}HJ^?m&$Rkq;Zf*i-hoasnpJVyTH__dbGWrB_R55d*>pTyl6(?$EO@>RCmTX1Hzr zT2)rOng?D4FfZ_C49hjMV*UonG2DlG$^+k=Y%|?Dqae4}JOU=8=fgY4Uh!pa9eEqf zFX&WLPu!jArN*^(>|H>dj~g`ONZhaaD%h_HHrHkk%d~TR_RrX{&eM#P@3x=S^%_6h zh=A)A{id16$zEFq@-D7La;kTuE!oopx^9{uA3y<}9 z^bQ@U<&pJV6kq7LRF47&!UAvgkBx=)KS_X!NY28^gQr27P=gKh0+E>$aCx&^vj2uc}ycsfSEP zedhTgUwPx%?;+dESs!g1z}5q9EC+fol}tAH9#fhZQ?q1GjyIaR@}lGCSpM-014T~l zEwriqt~ftwz=@2tn$xP&-rJt?nn5sy8sJ5Roy;pavj@O+tm}d_qmAlvhG(&k>(arz z;e|SiTr+0<&6(-An0*4{7akwUk~Yf4M!!YKj^swp9WOa%al`%R>V7mi z+5+UodFAaPdi4(8_FO&O!Ymb#@yxkuVMrog(7gkj$G@FLA#ENMxG)4f<}S%Fn?Up$+C%{02AgMKa^ z4SFGWp6U>{Q6VRJV}yjxXT*e`1XaX}(dW1F&RNhpTzvCtzuu;LMhMfJ2LBEy?{^GHG!OF!! zDvs64TG)?MX&9NCE#H3(M0K>O>`ca0WT2YR>PTe&tn?~0FV!MRtdb@v?MAUG&Ef7v zW%7>H(;Mm)RJkt18GXv!&np z?RUxOrCfs;m{fBz5MVlq59idhov21di5>WXWD-594L-X5;|@kyWi@N+(jLuh=o+5l zGGTi~)nflP_G}Yg5Pi%pl88U4+^*ihDoMP&zA*^xJE_X*Ah!jODrijCqQ^{=&hD7& z^)qv3;cu?olaT3pc{)Kcy9jA2E8I)#Kn8qO>70SQ5P8YSCN=_+_&)qg)OYBg|-k^d3*@jRAeB?;yd-O1A0wJ z?K*RDm|wE<(PBz~+C%2CTtzCTUohxP2*1kE8Of~{KRAvMrO_}NN&@P7SUO{;zx0iK z@or9R8ydYOFZf(cHASCAatL%;62IL27~SmASr(7F&NMr+#gNw@z1VM z_ALFwo3)SoANEwRerBdRV`>y`t72#aF2ConmWQp(Xy|msN9$yxhZ1jAQ67lq{vbC5 zujj|MlGo`6Bfn0TfKgi(k=gq0`K~W+X(@GzYlPI4g0M;owH3yG14rhK>lG8lS{`!K z+Nc@glT-DGz?Ym?v#Hq|_mEdPAlHH5jZuh*6glq!+>Lk$S%ED2@+ea6CE@&1-9a?s znglt|fmIK}fg<9@XgHe4*q!aO<-;Xj$T?IzB-{&2`#eA6rdtCi80mpP&vw(Uytxu$#YzNI_cB>LS zmim>ys;ir;*Dzbr22ZDxO2s;671&J0U<9(n1yj)J zHFNz=ufPcQVEG+ePjB<5C;=H0{>Mi*xD>hQq8`Vi7TjJ$V04$`h3EZGL|}a07oQdR z?{cR(z+d>arn^AUug&voOzzi$ZqaS)blz-z3zr;10x;oP2)|Cyb^WtN2*wNn`YX!Y z+$Pji<7|!XyMCEw4so}xXLU)p)BA~2fl>y2Tt}o9*BPm?AXA8UE8a;>rOgyCwZBFa zyl42y`bc3}+hiZL_|L_LY29vVerM+BVE@YxK>TGm@dHi@Uw*7AIq?QA9?THL603J% zIBJ4y3n8OFzsOI;NH%DZ!MDwMl<#$)d9eVVeqVl(5ZX$PPbt*p_(_9VSXhaUPa9Qu z7)q4vqYKX7ieVSjOmVEbLj4VYtnDpe*0Y&+>0dS^bJ<8s*eHq3tjRAw^+Mu4W^-E= z4;&namG4G;3pVDyPkUw#0kWEO1;HI6M51(1<0|*pa(I!sj}F^)avrE`ShVMKBz}nE zzKgOPMSEp6M>hJzyTHHcjV%W*;Tdb}1xJjCP#=iQuBk_Eho6yCRVp&e!}4IBJ&?ksVc&u#g3+G$oNlJ?mWfADjeBS-Ph3`DKk-~Z70XugH8sq2eba@4 zIC1H_J$`9b$K`J)sGX3d!&>OmC@@rx1TL~NinQOYy72Q_+^&Mg>Ku(fTgaXdr$p_V z#gav1o{k~c>#)u3r@~6v^o)Lf=C{rAlL@!s457pq)pO;Cojx7U{urO4cvXP|E>+dV zmr2?!-5)tk-&*ap^D^2x7NG6nOop2zNFQ9v8-EZ{WCz-h36C)<^|f{V#R_WE^@(T0+d-at5hXX{U?zak*ac-XnyINo+yBD~~3O1I=a z99|CI>502&s-Qi5bv>^2#cQ%ut<4d7KgQ^kE|=%6#VlGiY8$rdJUH{sra;P~cyb_i zeX(kS%w0C?mjhJl9TZp8RS;N~y3(EXEz13oPhOSE4WaTljGkVXWd~|#)vsG6_76I)Kb z8ro?;{j^lxNsaxE-cfP;g(e;mhh3)&ba}li?woV2#7ByioiD>s%L_D;?#;C#z;a(N z-_WY<=SH42m9bFQ>Nb z@4K$@4l8pD7AKxCR>t0%`Qoy9=hA?<<^Vcj8;-E+oBe3ReW1`el8np8E$k{LgFQ}2 z2t8a`wOXFdJ9!5$&mEfD1CnJ)TB+RJih88-Zos9@HZ# zL#{qfbF0ARTXkR@G{lwlOH~nnL)1jcyu!qv2`57S&%oKz0}r{~l9U_UHaJ5!8#nrs z?2FrL`mxnzu&{bweD&62)ilz*?pYIvt`T!XFVVA78})p1YEy7 z8fK#s?b~Yo$n7&_a?EBdXH-_W)Z44?!;DFx6pZ?~RArtBI*Qm4~6nX6Z_T*i$bQPE;Qz?DAPstpGSqr-AJ zo%m9cA`oDDm?&dTaoh_>@F>a?!y4qt_;NGN9Z<%SS;fX-cSu|>+Pba22`CRb#|HZa z;{)yHE>M-pc1C0mrnT~80!u&dvVTYFV8xTQ#g;6{c<9d!FDqU%TK5T6h*w*p980D~ zUyCb`y3{-?(mJFP)0*-Nt;mI$-gc4VQumh|rs&j_^R{sgTPF`1Xja2YWstsKFuQ(d zmZMxV$p$|qQUXchu&8%J(9|)B?`~rIx&)LqDS>ob5%gTeTP#Sbny#y*rnJ&?(l=!( zoV~}LJ1DPLnF8oyM(2ScrQ0{Q4m4-BWnS4wilgCW-~~;}pw=&<+HggRD_3c@3RQIr z9+-%!%}u_{`YS=&>h%kPO3ce}>y!d-zqiniNR-b5r97u;+K6HA2tS>Z#cV{+eFI`* zd8RMGAUtX1KWfPV;q<-5JAykS+2sY$2~UX+4461a(%{P#{rwFPu0xpIuYlbgD{C7C z=U{FUarVTYX6ZUq3wE@G^QT4H2Re;n$Fz9cJ>hABl)9T8pozqbA1)H-%1=WKm^QMu zjnUZ&Pu>q+X&6Co*y#@pxc-4waKMInEPGmE_>3@Ym3S*dedSradmc5mlJn`i0vMW6 zhBnGQD^Z;&S0lnS0curqDO@({J7kTtRE+Ra?nl^HP9<)W&C>~`!258f$XDbyQOQXG zP8hhySnarOpgu8xv8@WlXnm(Uk~)_3$Sg0vTbU3 z{W!5B(L3{Yy3K5PN<@jEarAtja`}@KYva&zFRF*s+_%jIXh$T(S=an8?=Ry3H*NRqWgsM`&!#|@kf1>=4q%bFw7^Rhz!z5I zyI^zU8_R1WN9`88Z=n>pIZQ`Ixr~_9G%Q}@A7rd#*%y7G zXl^Id=^ZL?Rx}}gWXCqzj9C6;x(~mAH|$JteXa1MH<6UQig@!Hf~t}B%tP0I|H&;y zO6N0}svOa1a^PyP9N5?4W6VF%=Bj{qHUgc8@siw4bafT=UPFSoQqKgyUX>sXTBZ=x zOh^Ad!{kOM9v{%5y}`-8u*T&C7Vq6mD%GR}UeU(*epO&qgC-CkD;%=l)ZuinSzHM` z{@`j&_vC6dDe{Yb9k@1zeV_K6!l(@=6ucoI=R^cH=6{i71%4W3$J-?<8Qn#$-DMtA z6Qqi)t?4ifrt%3jSA#6ji#{f(($KBL-iQh-xrC||3U3lq`9>r)>X%oLvtimuHW-)} zy}>9~|M>w4eES`g7;iBM%Se5-OP%1U6gNWp3AZqT8C6OlFFfQ$|7LL;tBV)(qlp4K zruar^K8FnJN3@_}B;G`a~H`t|3+6d>q3#`ctTkE-D^1#d9NalQ04lH*qUW2!V zhk7#z8OwHhSl8w14;KctfO8ubZJ4$dEdpXE78wABz=n5*=q9ex3S}`e7x~~V-jmHOhtX2*n+pBslo3uosdE7xABK=V#-t{1Hd~?i z{i~%Bw6NYF+F$aK$M`r#xe=NxhA5=p%i7!$);sd>Q}#`G?Q~fygrMXmZw?0#5#17W}6Tj+&kFexG{!mYl5FoA99}3G9l;3lVQ^ z48^~gsVppE*x91WheqI(A%F0Z#$#1UJP1R12Mj9r)y(A?a+iquX+d8WD4WAQJ_!oq z9rTISr7bPd(GTP57xm$}C}&kjMivi;zi^Y9g3&X0A;ovdJ?{%_wHgt%%9P&N4H z^XzV(uNA4 zAP`hgP6BEN5`YXh|DF~6Pud?~gWfhUKoPX4>z|}0aocC&K+AoV%|SX*N!wGq3|y< zg4lP(04XIPmt6}$N!dTk+pZv>u;MTB{L4hp9uXk7>aS!6jqM2lVr%{)H3$O127TSZ z0x9hi0k-P?nWFdQ0K`pykqUIT&jD~B0tHP{ffS(}fZ(aW$oBWTSfHO!A^><6vA?qar%tzN-5NQO zL&|F{nGiQyzNJ+bM$Y`n=Lx^3wTG^o2bGB@cwr1eb+6c-1tN=U+Db;bc~eJ!hwM{SbI=#g?$!PjDB+) zPgU_2EIxocr*EOJG52-~!gml&|D|C2OQ3Y(zAhL}iae4-Ut0F*!z!VEdfw8#`LAi# zhJ_EM*~;S|FMV6y%-SduHjPOI3cFM(GpH|HES<}*=vqY+64%dJYc|k?n6Br7)D#~# zEqO(xepfaf2F{>{E2`xb=AO%A<7RtUq6kU_Iu0m?@0K(+<}u3gVw5fy=Y4CC*{IE3 zLP3YBJ7x+U(os5=&NT%gKi23bbaZ`@;%ln)wp4GpDUT$J8NtFDHJzIe_-t}{!HAsh zJ4<^WovY};)9IKAskSebdQiXv$y5}THuJZ}ouoElIZRui=6lrupV|_Jz=9^&;@HwL;J#@23k?A;k`0Bgf;ioO>W`IQ+4? z7A)eKoY4%+g%=w;=Vm8}H>@U*=*AWNtPqgWRqib#5RTGA@Q=43FrQn3J`GkTUV5yp0U`EOTqjfp+-9;0F8!dMEwwcK%(6`8sDD^aR04 zd6O5vh|Xk?&3dy4f|1QK&Ulf{h6Iq;d-&*ti#Ck>wZFG;GHwc?b;X~eBITx49>2d8 z4HcK&1&DvEGT6kXdzAm4oO8%c}8OBt~8H956_;YP-ss*uMf==a+%w~F>Qkm7r)IAuxuoX}h92$gHqbFUun#8m zWHdy`Zrm#=Pa98x8cO0vd@Tgkr*lm0{dky+Gocr0P8y%HGEI#c3qLqIRc`Oq_C%*; zG+QTr(#Q|yHKv6R@!DmLlwJQ3FAB)Yor-I4zyDyqM4yp5n2TrQH>gRt*Zw0+WI-Sj`EgmYHh=t9! zF6lz^xpqGGpo6!5`sc0a^FVhy_Uxq|@~(1@IIzV)nTpY9sY`CV!?8e&bB8=M&sYEb z2i}fvKdhp9Hs68Y-!QJ<=wE(iQ5+49tqt;Rh|jhYrI5VW-mIz|UY{h8E=rC5sh#DU z?wGgk-Tn!I?+Zer7pHlF_Z^!Kd1qkS3&lv#%s6-<5Y%jQL${cge5=G5Ab?D&|9$Y~ zf%rJC2+=2vg;y0-SJb3<@3%}BO$T$C66q$L_H33a`VUbgW~N(4B=v5(<=My|#|J7q z*Ox4wL4kbJd_~EjLTABSu4U7Jk#`y(6O*U6(k6XxM}CtGZB(H@3~kh*zaGRXM}Iwp zQ%xFk2>@wiZrVCV_G4G~v;NebCQ%T7{SDyPpSv&dT@Cn)Mx@IK*IdNrj{*4pkV4wv z)y0J538h>cpB7iPSzA~x24T`{dzNkpvGIqvt1Dvdq@o-`B=$hkczX8$yFMhsWNK-X zxr$kR$tMD0@W)Vxe1^t9qVmsg&K^F@u84)(n2dttIEAZFN6VD$&tskpG%SI7whGL3 z)DeRiwe&?8m7U{G`oW8!SCi*dM>oYL%UKQnKxV_0RXAEBQg1kStExGEUVwLJ0orGGwb7uv+kPDl7_E2*iD|J*=8A@;XCvwq0aw5oJYN*Yh&o=l} z2z8YKb-fIAH5spql4eXqp*)o2*b>#1@DSt?zZi{GPj0gH&Nm+EI<3^z0w%YTEV4xw zI6$+=Faa|Y4o5i0zm5lOg|&tmnJ806DBovU@Ll6XsA;NRrTK~t*AAJIAS=v-UZ%Pr z$oddI@NRir&erzCwq|)ciJemr-E061j{0Vc@Ys7K(mW|JYj*$+i1Q8XlIK8T?TYS(AXu$`2U zQ@fHxc=AVHl_}cRZQ)w0anMEoqRKKIvS^`<-aMf*FM`NsG&Uowneo+Ji$7DUDYc7*Hjg;-&aHM%3 zXO6cz$$G};Uqh+iY7Wpme>PHG4cu(q;xyskNLs$^uRRMfEg?8Cj~aE-ajM%CXkx0F z>C?g3tIA#9sBQOpe`J+04{q7^TqhFk^F1jFtk4JDRO*`d-fx`GYHb=&(JiaM1b?Y^ zO3Kj3sj76ieol|N$;>j@t#tKj=@*gP+mv}KwlTcPYgR$+)2(gk)2JNE=jSauPq!$< z<|?Sb%W)wS)b>b6i{8!x!^!xIdU3{CJFVnTcw0j{M%DUCF=_>eYYEUWnA-|B(+KYL z_W_`JI&&u^@t0})@DH^1LDuT0s3dMpCHIbYBgOT4Zh_4yHbSqRbtIKndeT4Q*Jg91 z@>rO!^t-G~*AIW;FQ$3J=b;oGg8?CTa~qNCb>&cgp@e;?0AqA&paz~(%PYO+QBo4( zp?}ZdSMWx0iJm7HVNk9A#^9Osa#GPJ!_pYEW}($8>&2}fbr@&ygZ?${A7_9?X$(&5 z#~-hxdPQwCNEpf=^+WH-3`2LxrrBMTa}~qJC9S;VzhG!On^JLyW6WkF{8aAE$sM+( zxr8xLW(KIjI`Rm(24r3OJBk<3GF=G!uSP0-G&AY32mLm8q=#Xom&Pqv=1C{d3>1^ zAjsmV@XZ%BKq^eUfBpa8KvO8ob|F3hAjJv*yo2Bhl0)KUus{qA9m8jf)KnOGGTa6~4>3@J_VzkL|vYPl*uL+Ot*Q7W!f5rJw5+AsjP_IfL+-S*2p| zB7!FhjvkUTxQkGWGSg{X;h~dK>gAJivW?88Nu!3o>ySDaABn$rAYt086#27fbjPQS zhq>55ASvm*60qRdVOY9=bU^+{Pi#!OaZwENN;zy5?EztOHK-Q5;rCuiFl}BSc1YaQ zC-S{=KsGDz@Ji9O5W;XxE0xI|@3o6(2~i4b8Ii9VT;^G$*dRw(V?=br)D&q^XkeBX z+gl~+R@rVD-Hwv@7RHV?Bip5KMI)aV^&snt?H<$Nt=OPx#VxF&BGi?2A2+lNOYywNUGMeGL;|(=UjGDtLG0sN&LpGx;|U;xa13s z;W_|SPk^G}!M9_^pO zA3bt3-tca%^42sHeDtfcC0S3w3H1ny!Bxpa=*k?XRPpx9Bb-gx1J9Yvx)4J(8cG+q z(iCPZ9dsf3#QVyZgD_MW#G#qgV)olu$59&3(PzQfw@%4uZ~<5J=ABvdY43(Qnp{;G zHg3>@T#>DbTuhFl3)fb3TFqdh)V2aq7!;&JOHseTWukvA7}(iGUq;v-{2J0iHSNHq z;+)h!p6Ok^+Sp8-jgL($n6Qu47xyE`cFO5SdZR6;R!FET`tm#0D37z339Suxjpv+s z*=%2-N$N?X&0?x_uut3erF@aBGj;9$k9?3FlbDO{RQa1_qtxrh4!4#fjp4x~akvdTp@ zos?^Q&XE;3N93s4rHQGPrV7+au1$$aB6$hLy*Yz_kN$~dweb9PcB!eYVQTGjFuJP> zZCEwBtb>TIgIO^qAzq@Bv-qud_ZD-2W<_at&ml-gv`tPt$@DF5`HlA zM>DmmMkpv&Zm-8)Y#0bLQf4MpD4_-7M8eu6rh(tL8dq8onHs#R9J~dGd2IaXXMC~h z91pKhnQa%Fsn29nAA1;x(%oC zhca~qQDJaMf?wFrl-Pj;e$bZMYmMF!Y3Lv&Sb?Sjn#!NVx&NDyc^$b4uYyo2OmERa zRz;yDGd@JTykzFLe|Wk-y7#3x`6$wt$zR8r48mdUvfbeL+4D|Z``~7$PrE@qc7rZe zVsIoIbCwzjLZ@_M1*bD{HaYn();Z1-q*-I{tEnTZ(}Zmk&%MXSNBX>o| z-u*RNkAyKC-Srp7c-=@5f)xMWg>o2WWl}j6j9=8+D8;T z>0*0q#;qw8%U8i;6s0fu#I*%(g*@@a2Er@@nyI}{=@W{Z-;`=wN4N~>6Xrh&z#g}l zN1g5}0-#(nHUTv_rl2{yUZ;h#t&Fd?tY!7L%ClY)>uH-Ny2ET$lW$S)IQiN79H)D^ zb&0AXYkupy0~w8)*>Sj_p9}4L?lGTq%VG|2p`nWGhnM^!g|j-|O{%9Q%swOq63|*W zw$(N_laI}`ilB+o!a-wl?er~;;3+)$_akSQ!8YO_&-e*SI7n^(QQ;X0ZE`{4f!gAl z5$d+9CKVNonM!NO_frREICIAxOv)wm>}-k?iRisM`R7;=lyo|E_YR~FpS&PS`Lg0f zl-ON<0S%Uix8J%#yZdkCz4YNhcec<|7*P(JsM#>-L>+tYg_71q9~70FAc^6KW5jql zw!crdgVLH1G_eET=|SEc977;)ezVC|{PJZfra|}@rD;0s&@61mTEBJtILllg{%{vN zfhb&lq0yChaLhnJ-Qb62MB7`>M;|_ceHKZAeeh@#8tbrK!ArP6oXIhMK;dhEJTY`@ z0Tq>MIe0`7tGv)N*F0IGYSJv0vN?Az8g+4K9S!pW2~9F4W(_U_T=jCZrzuZ3*|__T zONp_UWmyePv8C~rckc?Xji;Z5OEqg zC*Um)i;Wh4TEwqReQdVVbUKT^2>Tpi6z_^-uF*adUFug4i@JhzpWT^Sk&E>CyP2?H zWf6x}ehuTs6wvzCnTU&gYzT029Nz19(In1WC z`(1IGmi!O%2AR|BjQa4Q0~u)kM%}?xQyjWuQ16^Gp++;`vr7!k--UZWM*~7Zl|ceO@I3`OpaRhD;YoCuo5IC0uHx>9 z478hu@H|e0Zlo)Zj@01#;8BDs@991xe~^9uG2}UXLM(m7fa}AMwX*tjioBeV&Q8Gx zSq$6wZFkRBK`cMI>R(@W@+lo2t)L+4q-negWRLWZBz*|%=W4v62JrmzNuOtA*x)QE z5L%=OH#@KMdB%Jp^r?0tE}5-*6oP`-lO7Sf)0)n*e<{HA=&qhLR)oD8-+V}Z4=md) z+k9lKf64DB2hAT)UaCP~di?-V3~JBH7itYyk~L6hrnxM%?RKntqd`=!b|e7eFnAcu z3*V;g{xr7TSTm$}DY%~SMpl>m{Sj!We+WfxSEor?YeiAxYUy25pn(?T()E>ByP^c@ zipwvWrhIK((R((VU+;@LmOnDu)ZXB3YArzzin!Z^0;PyJWnlfflo|q8(QY;o1*5CO z##hnkO{uynTMdk`~DOC#1 zdiYxQoy}=@7(ke#A8$YZZVtk4wo$8x28&I;cY3Ro-|kW=*yiiHgCLZeAr)UtVx>Tu z|LvL0hq|1-jC0I4x#>&QZCfrVB=zT!nR|~Uz`9%~2 znl{uZ{VEszW`Fad^q_HB!K9*|U-stK%?~;g?&&+12A}Rq$z($Bzuk^2X(Y=hF?-dQ ztc3DsQKI;qhWIV`99Q#R3xnU0AvY!i*BECj-z9l74|%O=V@nlv|qqC^r^-~C?E zGW%c|uYgnfJ(gjsTm_cIqcv*mYM{+i+&@F@+69ZQOK&u#v4oxUSQJ=tvqQ3W=*m;| z>SkBi8LYb-qRY7Sthh*0%3XAC%$z1rhOJzuX=PkTOa=DlocZUpE#KxVNH5)_4n=T( zGi3YrH7e~sPNYVBd~Grcq#CF~rN{p9Zza-Ntnwfma@TB)=3g36*0lSZg#ixEjFe%+ zX=&LDZ5zqculZ`=RYc^ln(~;nN|Qh6gN=!6f9-N2h+3NWbIxYud&;4SX*tWf5slk4 z{q@@l71UAZgj~*6edXb57fBUxvAS7s(RI=X868JM0+^DCn2yC>;v%S;qPOjB>YVsz(Zx9a>>BK&M zIQK>7_n)4ud0X5YM}^i*keH{ehLsiy9@NvOpsFeQjdI6anLGvVbBw_*fU1TzdVS$i z*4j7z!I5RF#rSz|8ibi$;qE{4`aqWYik7QB5U&F5C*;TO_x+gtzPGpzNt!7~nsBT7)Ckc(K~%uv&{{6A`mmBJVAk-{s~52Vu|HbCH7_W1~ZCX^RflOakGg=jo2Z z<*s;5-J+2@^LRDZ-7EV&Pq+FTErw@pfFqvx^i%E7Fx#^n(E`m2(c>K-O5`M`Yek9el zzTGs5qD6*G;y#~xu3>qWuO?-amKYtvRA}I9z#UspEeM;wOERYeot_n_EUMJf$4_u?E!6X~?q)tPoZb^_;8Y_Ox2h1m<+Le-fsRd|T8db<8#$bqez zua^Z|>h%zdnuU^ww$#-dZ9NTM`FN+!IlLkz*FqWb!x^Z|C{KyGjZ+>G;;7Mb@LY|H zc+Gp`L((Dw7pnDlHNm&;SfHedhx*kad$I^uGz{`0BYelq0yEUHpNKSkvj$|dpvY3{7*YGyhXA^LP0&wOw9oNoC=QoVx1<2Dne8qqZL zm>nFh5DX(-RnQwvHCZQwn^#Z=E!SPVlaRJ78Bo@}!!9dRt^qZy?-*`Pt4WSmgucJv zV1yFkcjlEM^uz-;b#Q7ZCP@Lk)m}uPX={R4B=56k7WNh11BN~0T*vr@!!ow^B0hOR zQ)4)&(e%>bNNL%bm<&8H{*l_L7s0$2GUgX2Vd;=4d9Dm2v3TaL+;L>{K7h7 zV#k?xDPm(NDE31$ z<}|X)pEY6myjK+^gaIMk&Yj2~F0rSKemNqlsVm4c|N7mp_C*L01s;GNx#D-*&gk!qQr}^?_r@q!8fuXw!)fA7xkd} zb>vHvdx~H$5qqAWrow7}+8zBM65-JOt5z za=T6f7MK`XJuQog8kIEboPdhcaVJeHy)5z7EBLK5NRr()E|#K0L0N^JD@pUA^Czb` zbUZ_558y+vqAGeyHCbrvOvLD67Ph}06959VzQ_|>RrXQAqE+AQ(-AaKdxoWaF8hdt z{O3W@b^*o#-f1VuU>YMV03ELF7zkCN4Q&b#prz%3Nne0lSbRo@@ z^ihv%oIl~Qyl6Q;a#$*jOC%x0_;eis*)J7=f@Ct*)xF5 zo}u~@-I}2|$b%5L7>@+Z?4o+1r&v6ceIy+vroK&jCQ<4q&45HP2wCol4hVm3pZtjf zHz1D7oyaSKJ~T{Gx}7ONLA)D5k(%%`WswrDyzX*rn}i}}TB4^y#@mAwPzoC)`?rYv zHgx|trUN#mu*VzUV~8TnJM2Qh*ZM5B{x&y>5An`(M7=Z*Q>TdiH@j*2=moNuOtvpz z+G`@~-`%~+AgPKgke@XiRPgndh@bp*-HRsh;HTtz@-y_uhb%7ylVOTqG0#u?Vn5c5 zEp*XRo|8hcgG^$#{$O9CJ&NE;TrfRpSnLmes&MO{m=N%zc`}gb!eQ7odl$oy1%PI} z#AIxx%oRVy&{O~9xnK4$EY>(eQj}!HKIV$Fz*H=-=Kn)N0D6u`(;iO|VraI4fu_W` z;b5{7;Lyx4za}DU#+U7}=H0dAS#YJJ&g2!P@Htu-AL&w=-)*%P9h2{wR|@?Ff9~)b z^+e_3Hetq7W%ls{!?<6&Y$Z;NNB41pvrv)|MET6AZXFXJeFqbFW5@i5WGzl?bP+~? z*&_puH;wKv2)9T_d+P`bLvJFqX#j&xa*-;0nGBbQf0DC>o~=J_Wmtf*2SZQr?{i~X z9-IbRH8{iy?<0v9Ir1?$66+igy|yDQ5J~A9sFX@Pe<*kCY8+MwH?I z`P}zfQ6l^AO8ehZ=l^ZR;R%uu4;BK*=?W9t|0{+-at(MQZ(CtG=EJFNaFMlKCMXu30(gJUqj5+ z`GM|!keqcj;FKTa_qq;{*dHRXAq157hlB@kL#8%yAm2AgfU|*rDKX@FLlp=HL8ddv zAWLCHe@DcDeB2}fl7#=0+#<05c3=VqM*O3bkr@9X4nO|)q0hU;Gye{L8ZN*NH8Id@mP-u;Fmb8YuorjLrW&ndip8CN%_qp982r w1WEnz9^$&s1hkp_3#lPJQ~!HI7WYYjA7>z!`?f%npAh2%rB@vD|Lau$2O)#1n*aa+ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ffed3a2..41dfb87 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index c53aefa..1b6c787 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright © 2015-2021 the original authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -32,10 +32,10 @@ # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # From ddd25e1a77627203ab8154e0b49f97fae3a7ef0d Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Thu, 20 Oct 2022 16:36:57 +0100 Subject: [PATCH 37/43] Bump version --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index d407eec..7d3829f 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ plugins { } group 'net.fabricmc' -version '0.3.1' +version '0.3.2' def ENV = System.getenv() version = version + (ENV.GITHUB_ACTIONS ? "" : "+local") From 4a8d35d741a2c860deef735cb8f140389d9f3a56 Mon Sep 17 00:00:00 2001 From: liach Date: Fri, 5 May 2023 17:04:07 -0500 Subject: [PATCH 38/43] 0.4.0 Migrate to mapping io, use spotless still need to work on inner class handling, need named jar inspection first --- HEADER | 28 +-- build.gradle | 22 +-- .../fabricmc/mappingpoet/ClassBuilder.java | 29 ++-- .../net/fabricmc/mappingpoet/Environment.java | 54 ++++++ .../fabricmc/mappingpoet/FieldBuilder.java | 8 +- .../java/net/fabricmc/mappingpoet/Main.java | 68 ++++---- .../fabricmc/mappingpoet/MappingsStore.java | 163 +++++++----------- .../fabricmc/mappingpoet/MethodBuilder.java | 59 +++---- .../fabricmc/mappingpoet/ModifierBuilder.java | 10 +- .../net/fabricmc/mappingpoet/Signatures.java | 1 - .../mappingpoet/jd/MappingTaglet.java | 1 - .../signature/AnnotationAwareDescriptors.java | 1 - .../signature/AnnotationAwareSignatures.java | 1 - .../mappingpoet/signature/ClassSignature.java | 1 - .../signature/ClassStaticContext.java | 1 - .../signature/MethodSignature.java | 1 - .../PoetClassMethodSignatureVisitor.java | 23 ++- .../signature/PoetTypeSignatureWriter.java | 9 +- .../signature/TypeAnnotationBank.java | 1 - .../signature/TypeAnnotationMapping.java | 1 - .../signature/TypeAnnotationStorage.java | 1 - .../net/fabricmc/mappingpoet/BorkAnno.java | 1 - .../fabricmc/mappingpoet/SignaturesTest.java | 1 - .../net/fabricmc/mappingpoet/TestAnno.java | 1 - .../net/fabricmc/mappingpoet/TestOuter.java | 1 - 25 files changed, 229 insertions(+), 258 deletions(-) create mode 100644 src/main/java/net/fabricmc/mappingpoet/Environment.java diff --git a/HEADER b/HEADER index 3bed386..f56c506 100644 --- a/HEADER +++ b/HEADER @@ -1,13 +1,15 @@ -Copyright (c) 2020 FabricMC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. \ No newline at end of file +/* + * Copyright (c) $YEAR FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ diff --git a/build.gradle b/build.gradle index 7d3829f..81c1cb9 100644 --- a/build.gradle +++ b/build.gradle @@ -1,11 +1,11 @@ plugins { id 'java' id 'maven-publish' - id 'org.cadixdev.licenser' version '0.6.1' + id 'com.diffplug.spotless' version '5.8.2' } group 'net.fabricmc' -version '0.3.2' +version '0.4.0' def ENV = System.getenv() version = version + (ENV.GITHUB_ACTIONS ? "" : "+local") @@ -20,8 +20,7 @@ repositories { dependencies { implementation 'net.fabricmc:javapoet:0.1.0' - implementation 'net.fabricmc:tiny-mappings-parser:0.3.0+build.17' - runtimeOnly 'com.google.guava:guava:30.1.1-jre' + implementation 'net.fabricmc:mapping-io:0.4.0' implementation 'org.ow2.asm:asm:9.2' implementation 'org.ow2.asm:asm-analysis:9.2' @@ -35,11 +34,11 @@ dependencies { java { withSourcesJar() + toolchain { + languageVersion = JavaLanguageVersion.of(17) + } } -sourceCompatibility = 17 -targetCompatibility = 17 - tasks.withType(JavaCompile) { options.release = 17 options.encoding = "UTF-8" @@ -63,9 +62,12 @@ jar { } } -license { - header file("HEADER") - include '**/*.java' +import com.diffplug.spotless.LineEnding +spotless { + lineEndings = LineEnding.UNIX + java { + licenseHeaderFile(file("HEADER")).yearSeparator(", ") + } } publishing { diff --git a/src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java b/src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java index 51a92cc..0aa9bf3 100644 --- a/src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java +++ b/src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package net.fabricmc.mappingpoet; import com.squareup.javapoet.AnnotationSpec; @@ -24,7 +23,6 @@ import net.fabricmc.mappingpoet.signature.AnnotationAwareDescriptors; import net.fabricmc.mappingpoet.signature.AnnotationAwareSignatures; import net.fabricmc.mappingpoet.signature.ClassSignature; -import net.fabricmc.mappingpoet.signature.ClassStaticContext; import net.fabricmc.mappingpoet.signature.TypeAnnotationMapping; import net.fabricmc.mappingpoet.signature.TypeAnnotationStorage; import org.objectweb.asm.Handle; @@ -40,10 +38,7 @@ import java.lang.reflect.Modifier; import java.util.ArrayList; -import java.util.Collection; import java.util.List; -import java.util.function.Function; -import java.util.function.Predicate; import static net.fabricmc.mappingpoet.FieldBuilder.parseAnnotation; @@ -61,9 +56,7 @@ public class ClassBuilder { private final TypeSpec.Builder builder; private final List innerClasses = new ArrayList<>(); - private final Function> superGetter; - private final Predicate sealChecker; - private final ClassStaticContext context; + private final Environment environment; private final ClassSignature signature; // not really signature private final TypeAnnotationMapping typeAnnotations; @@ -75,12 +68,10 @@ public class ClassBuilder { // omits L and ; private String receiverSignature; - public ClassBuilder(MappingsStore mappings, ClassNode classNode, Function> superGetter, Predicate sealChecker, ClassStaticContext context) { + public ClassBuilder(MappingsStore mappings, ClassNode classNode, Environment environment) { this.mappings = mappings; this.classNode = classNode; - this.superGetter = superGetter; - this.sealChecker = sealChecker; - this.context = context; + this.environment = environment; this.typeAnnotations = setupAnnotations(); this.signature = setupSignature(); this.builder = setupBuilder(); @@ -141,8 +132,8 @@ public void addMembers() { private ClassSignature setupSignature() { return classNode.signature == null ? - AnnotationAwareDescriptors.parse(classNode.superName, classNode.interfaces, typeAnnotations, context) : - AnnotationAwareSignatures.parseClassSignature(classNode.signature, typeAnnotations, context); + AnnotationAwareDescriptors.parse(classNode.superName, classNode.interfaces, typeAnnotations, environment) : + AnnotationAwareSignatures.parseClassSignature(classNode.signature, typeAnnotations, environment); } private TypeSpec.Builder setupBuilder() { @@ -180,7 +171,7 @@ private TypeSpec.Builder setupBuilder() { return builder .addModifiers(new ModifierBuilder(classNode.access) - .checkUnseal(classNode, sealChecker) + .checkUnseal(classNode, environment) .getModifiers(ModifierBuilder.getType(enumClass, recordClass)) ); } @@ -258,7 +249,7 @@ private void addMethods() { formalParamStartIndex = 1; // 0 this$0 } } - builder.addMethod(new MethodBuilder(mappings, classNode, method, superGetter, context, receiverSignature, formalParamStartIndex).build()); + builder.addMethod(new MethodBuilder(mappings, classNode, method, environment, receiverSignature, formalParamStartIndex).build()); } } @@ -270,7 +261,7 @@ private void addFields() { if (!Modifier.isFinal(field.access) || Modifier.isProtected(field.access) || Modifier.isPublic(field.access)) { System.out.println("abnormal instance field " + field.name + " in record " + getClassName() + ", skipping"); } else { - var fieldBuilder = new FieldBuilder(mappings, classNode, field, context); + var fieldBuilder = new FieldBuilder(mappings, classNode, field, environment); var paramBuilder = ParameterSpec.builder(fieldBuilder.calculateType(), field.name); fieldBuilder.addJavaDoc(paramBuilder); fieldBuilder.addDirectAnnotations(paramBuilder); @@ -283,7 +274,7 @@ private void addFields() { continue; // hide synthetic stuff } if ((field.access & Opcodes.ACC_ENUM) == 0) { - builder.addField(new FieldBuilder(mappings, classNode, field, context).build()); + builder.addField(new FieldBuilder(mappings, classNode, field, environment).build()); } else { TypeSpec.Builder enumBuilder = TypeSpec.anonymousClassBuilder(""); // jd @@ -347,7 +338,7 @@ public void addInnerClass(ClassBuilder classBuilder) { classBuilder.builder.modifiers.remove(javax.lang.model.element.Modifier.PUBLIC); // this modifier may come from class access classBuilder.builder.addModifiers(new ModifierBuilder(innerClassNode.access) - .checkUnseal(classBuilder.classNode, sealChecker) + .checkUnseal(classBuilder.classNode, environment) .getModifiers(ModifierBuilder.getType(classBuilder.enumClass, classBuilder.recordClass)) ); if (!Modifier.isStatic(innerClassNode.access)) { diff --git a/src/main/java/net/fabricmc/mappingpoet/Environment.java b/src/main/java/net/fabricmc/mappingpoet/Environment.java new file mode 100644 index 0000000..5355634 --- /dev/null +++ b/src/main/java/net/fabricmc/mappingpoet/Environment.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2020 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package net.fabricmc.mappingpoet; + +import com.squareup.javapoet.ClassName; +import net.fabricmc.mappingpoet.signature.ClassStaticContext; + +import java.util.Collection; +import java.util.Map; +import java.util.Set; + +/** + * Represents an overall runtime environment, knows all inner class, + * super class, etc. information. + */ +public record Environment( + Map> superTypes, + Set sealedClasses, + // declaring classes keep track of namable inner classes + // and local/anon classes in whole codebase + Map declaringClasses +) implements ClassStaticContext { + public record NestedClassInfo(String declaringClass, boolean instanceInner, String simpleName) { + // two strings are nullable + } + + public record ClassNamePointer(String simple, String outerClass) { + public ClassName toClassName(ClassName outerClassName) { + if (simple == null) + return null; + + return outerClassName.nestedClass(simple); + } + } + + @Override + public boolean isInstanceInner(String internalName) { + var info = declaringClasses.get(internalName); + return info != null && info.declaringClass != null && info.instanceInner; + } +} diff --git a/src/main/java/net/fabricmc/mappingpoet/FieldBuilder.java b/src/main/java/net/fabricmc/mappingpoet/FieldBuilder.java index c069c67..1bf98c9 100644 --- a/src/main/java/net/fabricmc/mappingpoet/FieldBuilder.java +++ b/src/main/java/net/fabricmc/mappingpoet/FieldBuilder.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package net.fabricmc.mappingpoet; import com.squareup.javapoet.AnnotationSpec; @@ -24,7 +23,6 @@ import com.squareup.javapoet.ParameterSpec; import com.squareup.javapoet.TypeName; import com.squareup.javapoet.TypeSpec; -import net.fabricmc.mapping.util.EntryTriple; import net.fabricmc.mappingpoet.signature.AnnotationAwareDescriptors; import net.fabricmc.mappingpoet.signature.AnnotationAwareSignatures; import net.fabricmc.mappingpoet.signature.ClassStaticContext; @@ -69,7 +67,7 @@ public FieldBuilder(MappingsStore mappings, ClassNode classNode, FieldNode field } static void addFieldJavaDoc(TypeSpec.Builder enumBuilder, MappingsStore mappings, ClassNode classNode, FieldNode fieldNode) { - mappings.addFieldDoc(enumBuilder::addJavadoc, new EntryTriple(classNode.name, fieldNode.name, fieldNode.desc)); + mappings.addFieldDoc(enumBuilder::addJavadoc, classNode.name, fieldNode.name, fieldNode.desc); } public static AnnotationSpec parseAnnotation(AnnotationNode annotation) { @@ -468,11 +466,11 @@ private static CodeBlock.Builder printChar(CodeBlock.Builder builder, char c, in } private void addJavaDoc() { - mappings.addFieldDoc(builder::addJavadoc, new EntryTriple(classNode.name, fieldNode.name, fieldNode.desc)); + mappings.addFieldDoc(builder::addJavadoc, classNode.name, fieldNode.name, fieldNode.desc); } void addJavaDoc(ParameterSpec.Builder paramBuilder) { - mappings.addFieldDoc(paramBuilder::addJavadoc, new EntryTriple(classNode.name, fieldNode.name, fieldNode.desc)); + mappings.addFieldDoc(paramBuilder::addJavadoc, classNode.name, fieldNode.name, fieldNode.desc); } private void addDirectAnnotations() { diff --git a/src/main/java/net/fabricmc/mappingpoet/Main.java b/src/main/java/net/fabricmc/mappingpoet/Main.java index 31a83cf..83c614b 100644 --- a/src/main/java/net/fabricmc/mappingpoet/Main.java +++ b/src/main/java/net/fabricmc/mappingpoet/Main.java @@ -13,10 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package net.fabricmc.mappingpoet; +import com.squareup.javapoet.ClassName; import com.squareup.javapoet.JavaFile; +import net.fabricmc.mappingpoet.Environment.ClassNamePointer; +import net.fabricmc.mappingpoet.Environment.NestedClassInfo; import net.fabricmc.mappingpoet.signature.ClassStaticContext; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; @@ -37,7 +39,6 @@ import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.Comparator; import java.util.Enumeration; import java.util.HashMap; @@ -46,8 +47,6 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Function; -import java.util.function.Predicate; import java.util.jar.JarEntry; import java.util.jar.JarFile; @@ -65,15 +64,16 @@ public static void main(String[] args) { try { if (Files.exists(outputDirectory)) { - Files.walk(outputDirectory) - .sorted(Comparator.reverseOrder()) - .map(Path::toFile) - .forEach(File::delete); + try (var stream = Files.walk(outputDirectory)) { + stream.sorted(Comparator.reverseOrder()) + .map(Path::toFile) + .forEach(File::delete); + } } Files.createDirectories(outputDirectory); } catch (IOException e) { - e.printStackTrace(); + throw new UncheckedIOException(e); } if (!Files.exists(mappings)) { @@ -92,7 +92,7 @@ public static void main(String[] args) { public static void generate(Path mappings, Path inputJar, Path outputDirectory, Path librariesDir) { final MappingsStore mapping = new MappingsStore(mappings); Map classes = new HashMap<>(); - forEachClass(inputJar, (superGetter, classNode, context, sealChecker) -> writeClass(mapping, classNode, classes, superGetter, sealChecker, context), librariesDir); + forEachClass(inputJar, (classNode, environment) -> writeClass(mapping, classNode, classes, environment), librariesDir); classes.values().stream() .filter(classBuilder -> !classBuilder.getClassName().contains("$")) @@ -115,10 +115,11 @@ private static void forEachClass(Path jar, ClassNodeConsumer classNodeConsumer, Map> supers = new HashMap<>(); Set sealedClasses = new HashSet<>(); // their subclsses/impls need non-sealed modifier - Map instanceInnerClasses = new ConcurrentHashMap<>(); + Map nestedClasses = new ConcurrentHashMap<>(); + Map classNames = new ConcurrentHashMap<>(); if (librariesDir != null) { - scanInnerClasses(instanceInnerClasses, librariesDir); + scanNestedClasses(classNames, nestedClasses, librariesDir); } try (final JarFile jarFile = new JarFile(jar.toFile())) { @@ -148,7 +149,10 @@ private static void forEachClass(Path jar, ClassNodeConsumer classNodeConsumer, if (classNode.innerClasses != null) { for (InnerClassNode e : classNode.innerClasses) { - instanceInnerClasses.put(e.name, !Modifier.isStatic(e.access)); + if (e.outerName != null) { + // null -> declared in method/initializer + nestedClasses.put(e.name, new NestedClassInfo(e.outerName, !Modifier.isStatic(e.access), e.innerName)); + } } } @@ -166,12 +170,10 @@ private static void forEachClass(Path jar, ClassNodeConsumer classNodeConsumer, //Sort all the classes making sure that inner classes come after the parent classes classes.sort(Comparator.comparing(o -> o.name)); - ClassStaticContext innerClassContext = new InnerClassStats(instanceInnerClasses); - Function> superGetter = k -> supers.getOrDefault(k, Collections.emptyList()); - classes.forEach(node -> classNodeConsumer.accept(superGetter, node, innerClassContext, sealedClasses::contains)); + classes.forEach(node -> classNodeConsumer.accept(node, new Environment(supers, sealedClasses, nestedClasses))); } - private static void scanInnerClasses(Map instanceInnerClasses, Path librariesDir) { + private static void scanNestedClasses(Map classNames, Map instanceInnerClasses, Path librariesDir) { try { Files.walkFileTree(librariesDir, new SimpleFileVisitor<>() { @Override @@ -194,8 +196,11 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IO ClassReader reader = new ClassReader(is); reader.accept(new ClassVisitor(Opcodes.ASM8) { @Override - public void visitInnerClass(String name, String outerName, String innerName, int access) { - instanceInnerClasses.put(name, !Modifier.isStatic(access)); + public void visitInnerClass(String name, String outerName, String simpleName, int access) { + instanceInnerClasses.put(name, new Environment.NestedClassInfo(outerName, !Modifier.isStatic(access), simpleName)); + if (outerName != null) { + classNames.put(name, new ClassNamePointer(simpleName, outerName)); + } } }, ClassReader.SKIP_CODE); } @@ -225,7 +230,8 @@ private static boolean isDigit(char ch) { return ch >= '0' && ch <= '9'; } - private static void writeClass(MappingsStore mappings, ClassNode classNode, Map existingClasses, Function> superGetter, Predicate sealChecker, ClassStaticContext context) { + private static void writeClass(MappingsStore mappings, ClassNode classNode, Map existingClasses, Environment environment) { + // TODO make sure named jar has valid InnerClasses, use that info instead String name = classNode.name; { //Block anonymous class and their nested classes @@ -239,7 +245,8 @@ private static void writeClass(MappingsStore mappings, ClassNode classNode, Map< } } - ClassBuilder classBuilder = new ClassBuilder(mappings, classNode, superGetter, sealChecker, context); + // TODO: ensure InnerClasses is remapped, and create ClassName from parent class name + ClassBuilder classBuilder = new ClassBuilder(mappings, classNode, environment); if (name.contains("$")) { String parentClass = name.substring(0, name.lastIndexOf("$")); @@ -256,23 +263,6 @@ private static void writeClass(MappingsStore mappings, ClassNode classNode, Map< @FunctionalInterface private interface ClassNodeConsumer { - void accept(Function> superGetter, ClassNode node, ClassStaticContext staticContext, Predicate sealedChecker); - } - - private static final class InnerClassStats implements ClassStaticContext { - final Map instanceInnerClasses; - - InnerClassStats(Map instanceInnerClasses) { - this.instanceInnerClasses = instanceInnerClasses; - } - - @Override - public boolean isInstanceInner(String internalName) { - if (internalName.indexOf('$') == -1) { - return false; // heuristics - } - - return instanceInnerClasses.computeIfAbsent(internalName, Main::isInstanceInnerOnClasspath); - } + void accept(ClassNode node, Environment environment); } } diff --git a/src/main/java/net/fabricmc/mappingpoet/MappingsStore.java b/src/main/java/net/fabricmc/mappingpoet/MappingsStore.java index cf87506..84abd70 100644 --- a/src/main/java/net/fabricmc/mappingpoet/MappingsStore.java +++ b/src/main/java/net/fabricmc/mappingpoet/MappingsStore.java @@ -13,71 +13,46 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package net.fabricmc.mappingpoet; -import java.io.BufferedReader; +import net.fabricmc.mappingio.MappingReader; +import net.fabricmc.mappingio.adapter.MappingSourceNsSwitch; +import net.fabricmc.mappingio.format.MappingFormat; +import net.fabricmc.mappingio.tree.MappingTreeView; +import net.fabricmc.mappingio.tree.MappingTreeView.ClassMappingView; +import net.fabricmc.mappingio.tree.MappingTreeView.ElementMappingView; +import net.fabricmc.mappingio.tree.MappingTreeView.MethodMappingView; +import net.fabricmc.mappingio.tree.MemoryMappingTree; + import java.io.IOException; -import java.nio.file.Files; import java.nio.file.Path; -import java.util.AbstractMap; -import java.util.Collection; -import java.util.HashMap; +import java.util.AbstractMap.SimpleImmutableEntry; import java.util.List; import java.util.Map; -import java.util.function.Function; -import net.fabricmc.mapping.tree.ClassDef; -import net.fabricmc.mapping.tree.FieldDef; -import net.fabricmc.mapping.tree.Mapped; -import net.fabricmc.mapping.tree.MethodDef; -import net.fabricmc.mapping.tree.TinyMappingFactory; -import net.fabricmc.mapping.tree.TinyTree; -import net.fabricmc.mapping.util.EntryTriple; +import static net.fabricmc.mappingio.tree.MappingTreeView.SRC_NAMESPACE_ID; //Taken from loom public class MappingsStore { - private final Map classes = new HashMap<>(); - private final Map fields = new HashMap<>(); - private final Map> methods = new HashMap<>(); - - private final String namespace = "named"; - private final List namespaces; + private final MappingTreeView tree; + private final int maxNamespace; public MappingsStore(Path tinyFile) { - final TinyTree mappings = readMappings(tinyFile); - - namespaces = mappings.getMetadata().getNamespaces(); - - for (ClassDef classDef : mappings.getClasses()) { - final String className = classDef.getName(namespace); - classes.put(className, classDef); - - for (FieldDef fieldDef : classDef.getFields()) { - fields.put(new EntryTriple(className, fieldDef.getName(namespace), fieldDef.getDescriptor(namespace)), fieldDef); - } - - for (MethodDef methodDef : classDef.getMethods()) { - methods.put(new EntryTriple(className, methodDef.getName(namespace), methodDef.getDescriptor(namespace)), new AbstractMap.SimpleImmutableEntry<>(className, methodDef)); - } - } + this.tree = readMappings(tinyFile); + this.maxNamespace = tree.getMaxNamespaceId(); } - private static TinyTree readMappings(Path input) { - try (BufferedReader reader = Files.newBufferedReader(input)) { - return TinyMappingFactory.loadWithDetection(reader); + private static MappingTreeView readMappings(Path input) { + var tree = new MemoryMappingTree(); + try { + MappingReader.read(input, MappingFormat.TINY_2, new MappingSourceNsSwitch(tree, "named")); } catch (IOException e) { throw new RuntimeException("Failed to read mappings", e); } + return tree; } - @Deprecated - public String getClassDoc(String className) { - ClassDef classDef = classes.get(className); - return classDef != null ? classDef.getComment() : null; - } - - private void addDoc(Mapped element, DocAdder adder) { + private void addDoc(ElementMappingView element, DocAdder adder) { String doc = element.getComment(); if (doc != null) { adder.addJavadoc("$L", doc); @@ -85,109 +60,95 @@ private void addDoc(Mapped element, DocAdder adder) { } public void addClassDoc(DocAdder adder, String className) { - ClassDef classDef = classes.get(className); + var classDef = tree.getClass(className); if (classDef == null) { return; } addDoc(classDef, adder); adder.addJavadoc("\n"); - for (String namespace : namespaces) { - String transformedName = classDef.getName(namespace); - adder.addJavadoc("@mapping {@literal $L:$L}\n", namespace, transformedName); + for (int id = SRC_NAMESPACE_ID; id < maxNamespace; id++) { + String transformedName = classDef.getName(id); + adder.addJavadoc("@mapping {@literal $L:$L}\n", tree.getNamespaceName(id), transformedName); } } - @Deprecated - public String getFieldDoc(EntryTriple fieldEntry) { - FieldDef fieldDef = fields.get(fieldEntry); - return fieldDef != null ? fieldDef.getComment() : null; - } + public void addFieldDoc(DocAdder addJavadoc, String owner, String name, String desc) { + var classDef = tree.getClass(owner); + if (classDef == null) { + return; + } - public void addFieldDoc(DocAdder addJavadoc, EntryTriple fieldEntry) { - FieldDef fieldDef = fields.get(fieldEntry); + var fieldDef = classDef.getField(name, desc); if (fieldDef == null) { return; } addDoc(fieldDef, addJavadoc); - ClassDef owner = classes.get(fieldEntry.getOwner()); addJavadoc.addJavadoc("\n"); - for (String namespace : namespaces) { - String transformedName = fieldDef.getName(namespace); - String mixinForm = "L" + owner.getName(namespace) + ";" + transformedName + ":" + fieldDef.getDescriptor(namespace); - addJavadoc.addJavadoc("@mapping {@literal $L:$L:$L}\n", namespace, transformedName, mixinForm); + for (int id = SRC_NAMESPACE_ID; id < maxNamespace; id++) { + String transformedName = fieldDef.getName(id); + String mixinForm = "L" + classDef.getName(id) + ";" + transformedName + ":" + fieldDef.getDesc(id); + addJavadoc.addJavadoc("@mapping {@literal $L:$L:$L}\n", tree.getNamespaceName(id), transformedName, mixinForm); } } - public Map.Entry getParamNameAndDoc(Function> superGetters, EntryTriple methodEntry, int index) { - Map.Entry found = searchMethod(superGetters, methodEntry); + public Map.Entry getParamNameAndDoc(Environment environment, String owner, String name, String desc, int index) { + var found = searchMethod(environment, owner, name, desc); if (found != null) { - MethodDef methodDef = found.getValue(); - if (methodDef.getParameters().isEmpty()) { + var methodDef = found.getValue(); + if (methodDef.getArgs().isEmpty()) { return null; } - return methodDef.getParameters().stream() - .filter(param -> param.getLocalVariableIndex() == index) - .map(param -> new AbstractMap.SimpleImmutableEntry<>(param.getName(namespace), param.getComment())) + return methodDef.getArgs().stream() + .filter(param -> param.getLvIndex() == index) + // Map.entry() is null-hostile + .map(param -> new SimpleImmutableEntry<>(param.getSrcName(), param.getComment())) .findFirst() .orElse(null); } return null; } - @Deprecated - public String getMethodDoc(Function> superGetters, EntryTriple methodEntry) { - Map.Entry methodDef = searchMethod(superGetters, methodEntry); - - if (methodDef != null) { - return methodDef.getValue().getComment(); // comment doc handled separately by javapoet - } - - return null; - } - - public void addMethodDoc(DocAdder adder, Function> superGetters, EntryTriple methodEntry) { - Map.Entry found = searchMethod(superGetters, methodEntry); + public void addMethodDoc(DocAdder adder, Environment environment, String owner, String name, String desc) { + var found = searchMethod(environment, owner, name, desc); if (found == null) { return; } - MethodDef methodDef = found.getValue(); - ClassDef owner = classes.get(found.getKey()); - if (!owner.getName(namespace).equals(methodEntry.getOwner())) { + var methodDef = found.getValue(); + var ownerDef = found.getKey(); + if (!ownerDef.equals(methodDef.getOwner())) { adder.addJavadoc("{@inheritDoc}"); } else { addDoc(methodDef, adder); } adder.addJavadoc("\n"); - for (String namespace : namespaces) { - String transformedName = methodDef.getName(namespace); - String mixinForm = "L" + owner.getName(namespace) + ";" + transformedName + methodDef.getDescriptor(namespace); - adder.addJavadoc("@mapping {@literal $L:$L:$L}\n", namespace, transformedName, mixinForm); + for (int id = SRC_NAMESPACE_ID; id < maxNamespace; id++) { + String transformedName = methodDef.getName(id); + String mixinForm = "L" + ownerDef.getName(id) + ";" + transformedName + methodDef.getDesc(id); + adder.addJavadoc("@mapping {@literal $L:$L:$L}\n", tree.getNamespaceName(id), transformedName, mixinForm); } } - private Map.Entry searchMethod(Function> superGetters, EntryTriple methodEntry) { - String className = methodEntry.getOwner(); - if (!classes.containsKey(className)) { + private Map.Entry searchMethod(Environment environment, String owner, String name, String desc) { + var classDef = tree.getClass(owner); + + if (classDef == null) return null; - } - if (methods.containsKey(methodEntry)) { - return methods.get(methodEntry); // Nullable! - } + var methodDef = classDef.getMethod(name, desc); + if (methodDef != null) + return Map.entry(methodDef.getOwner(), methodDef); + - for (String superName : superGetters.apply(className)) { - EntryTriple triple = new EntryTriple(superName, methodEntry.getName(), methodEntry.getDescriptor()); - Map.Entry ret = searchMethod(superGetters, triple); + for (String superName : environment.superTypes().getOrDefault(owner, List.of())) { + var ret = searchMethod(environment, superName, name, desc); if (ret != null) { - methods.put(triple, ret); return ret; } } - methods.put(methodEntry, null); return null; } diff --git a/src/main/java/net/fabricmc/mappingpoet/MethodBuilder.java b/src/main/java/net/fabricmc/mappingpoet/MethodBuilder.java index 4968448..afe2bc3 100644 --- a/src/main/java/net/fabricmc/mappingpoet/MethodBuilder.java +++ b/src/main/java/net/fabricmc/mappingpoet/MethodBuilder.java @@ -13,38 +13,31 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package net.fabricmc.mappingpoet; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Function; - -import javax.lang.model.element.Modifier; - import com.squareup.javapoet.MethodSpec; import com.squareup.javapoet.ParameterSpec; import com.squareup.javapoet.TypeName; -import org.objectweb.asm.TypeReference; -import org.objectweb.asm.tree.AnnotationNode; -import org.objectweb.asm.tree.ClassNode; -import org.objectweb.asm.tree.MethodNode; - -import net.fabricmc.mapping.util.EntryTriple; import net.fabricmc.mappingpoet.signature.AnnotationAwareDescriptors; import net.fabricmc.mappingpoet.signature.AnnotationAwareSignatures; -import net.fabricmc.mappingpoet.signature.ClassStaticContext; import net.fabricmc.mappingpoet.signature.MethodSignature; import net.fabricmc.mappingpoet.signature.TypeAnnotationBank; import net.fabricmc.mappingpoet.signature.TypeAnnotationMapping; import net.fabricmc.mappingpoet.signature.TypeAnnotationStorage; +import org.objectweb.asm.TypeReference; +import org.objectweb.asm.tree.AnnotationNode; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.MethodNode; + +import javax.lang.model.element.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; public class MethodBuilder { private static final Set RESERVED_KEYWORDS = Collections.unmodifiableSet(new HashSet<>(Arrays.asList( @@ -58,20 +51,18 @@ public class MethodBuilder { private final ClassNode classNode; private final MethodNode methodNode; private final MethodSpec.Builder builder; - private final Function> superGetter; + private final Environment environment; private final int formalParamStartIndex; - private final ClassStaticContext context; private final String receiverSignature; private final TypeAnnotationMapping typeAnnotations; private MethodSignature signature; - public MethodBuilder(MappingsStore mappings, ClassNode classNode, MethodNode methodNode, Function> superGetter, ClassStaticContext context, String receiverSignature, int formalParamStartIndex) { + public MethodBuilder(MappingsStore mappings, ClassNode classNode, MethodNode methodNode, Environment environment, String receiverSignature, int formalParamStartIndex) { this.mappings = mappings; this.classNode = classNode; this.methodNode = methodNode; - this.superGetter = superGetter; - this.context = context; + this.environment = environment; this.receiverSignature = receiverSignature; this.formalParamStartIndex = formalParamStartIndex; @@ -158,7 +149,7 @@ private MethodSpec.Builder createBuilder() { } if (methodNode.signature != null) { - signature = AnnotationAwareSignatures.parseMethodSignature(methodNode.signature, typeAnnotations, context); + signature = AnnotationAwareSignatures.parseMethodSignature(methodNode.signature, typeAnnotations, environment); builder.addTypeVariables(signature.generics()); } @@ -190,7 +181,7 @@ private void setReturnType() { typeName = signature.result(); } else { String returnDesc = methodNode.desc.substring(methodNode.desc.lastIndexOf(")") + 1); - typeName = AnnotationAwareDescriptors.parseDesc(returnDesc, typeAnnotations.getBank(TypeReference.newTypeReference(TypeReference.METHOD_RETURN)), context); + typeName = AnnotationAwareDescriptors.parseDesc(returnDesc, typeAnnotations.getBank(TypeReference.newTypeReference(TypeReference.METHOD_RETURN)), environment); } builder.returns(typeName); @@ -215,7 +206,7 @@ private void addParameters(MethodBuilder this) { ParameterSpec.Builder receiverBuilder; // only instance inner class ctor can have receivers if (methodNode.name.equals("")) { - TypeName annotatedReceiver = AnnotationAwareSignatures.parseSignature("L" + receiverSignature.substring(0, receiverSignature.lastIndexOf('.')) + ";", receiverAnnos, context); + TypeName annotatedReceiver = AnnotationAwareSignatures.parseSignature("L" + receiverSignature.substring(0, receiverSignature.lastIndexOf('.')) + ";", receiverAnnos, environment); // vulnerable heuristics String simpleNameChain = classNode.name.substring(classNode.name.lastIndexOf('/') + 1); int part1 = simpleNameChain.lastIndexOf('$'); // def exists @@ -223,7 +214,7 @@ private void addParameters(MethodBuilder this) { String usedName = simpleNameChain.substring(part2 + 1, part1); receiverBuilder = ParameterSpec.builder(annotatedReceiver, usedName + ".this"); } else { - TypeName annotatedReceiver = AnnotationAwareSignatures.parseSignature("L" + receiverSignature + ";", receiverAnnos, context); + TypeName annotatedReceiver = AnnotationAwareSignatures.parseSignature("L" + receiverSignature + ";", receiverAnnos, environment); receiverBuilder = ParameterSpec.builder(annotatedReceiver, "this"); } // receiver param cannot have its jd/param anno except type use anno @@ -269,9 +260,9 @@ private void getParams(List paramTypes, boolean instance, Set if (signatureParamIterator.hasNext()) { parsedType = signatureParamIterator.next(); } else { - parsedType = AnnotationAwareDescriptors.parseDesc(desc.substring(oldIndex, index), typeAnnotations.getBank(TypeReference.newFormalParameterReference(paramIndex - formalParamStartIndex)), context); + parsedType = AnnotationAwareDescriptors.parseDesc(desc.substring(oldIndex, index), typeAnnotations.getBank(TypeReference.newFormalParameterReference(paramIndex - formalParamStartIndex)), environment); } - paramTypes.add(new ParamType(mappings.getParamNameAndDoc(superGetter, new EntryTriple(classNode.name, methodNode.name, methodNode.desc), slot), parsedType, usedParamNames, slot)); + paramTypes.add(new ParamType(mappings.getParamNameAndDoc(environment, classNode.name, methodNode.name, methodNode.desc, slot), parsedType, usedParamNames, slot)); } slot++; if (nonAnnotatedParsedType.equals(TypeName.DOUBLE) || nonAnnotatedParsedType.equals(TypeName.LONG)) { @@ -298,14 +289,14 @@ private void addExceptions() { if (exceptions != null) { int index = 0; for (String internalName : exceptions) { - builder.addException(AnnotationAwareDescriptors.parseType(internalName, typeAnnotations.getBank(TypeReference.newExceptionReference(index)), context)); + builder.addException(AnnotationAwareDescriptors.parseType(internalName, typeAnnotations.getBank(TypeReference.newExceptionReference(index)), environment)); index++; } } } private void addJavaDoc() { - mappings.addMethodDoc(builder::addJavadoc, superGetter, new EntryTriple(classNode.name, methodNode.name, methodNode.desc)); + mappings.addMethodDoc(builder::addJavadoc, environment, classNode.name, methodNode.name, methodNode.desc); } public MethodSpec build() { diff --git a/src/main/java/net/fabricmc/mappingpoet/ModifierBuilder.java b/src/main/java/net/fabricmc/mappingpoet/ModifierBuilder.java index dcc7c79..926ee94 100644 --- a/src/main/java/net/fabricmc/mappingpoet/ModifierBuilder.java +++ b/src/main/java/net/fabricmc/mappingpoet/ModifierBuilder.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package net.fabricmc.mappingpoet; import org.objectweb.asm.tree.ClassNode; @@ -21,7 +20,6 @@ import javax.lang.model.element.Modifier; import java.util.ArrayList; import java.util.List; -import java.util.function.Predicate; public class ModifierBuilder { @@ -32,21 +30,21 @@ public ModifierBuilder(int access) { this.access = access; } - public ModifierBuilder checkUnseal(ClassNode node, Predicate sealChecker) { + public ModifierBuilder checkUnseal(ClassNode node, Environment env) { if (java.lang.reflect.Modifier.isFinal(node.access)) { return this; } if (node.interfaces != null) { for (String itf : node.interfaces) { - if (sealChecker.test(itf)) { + if (env.sealedClasses().contains(itf)) { needsUnseal = true; return this; } } } - if (node.superName != null && sealChecker.test(node.superName)) { + if (node.superName != null && env.sealedClasses().contains(node.superName)) { needsUnseal = true; } @@ -98,7 +96,7 @@ public Modifier[] getModifiers(Type type) { modifiers.add(Modifier.NATIVE); } if (java.lang.reflect.Modifier.isStrict(access)) { - modifiers.add(Modifier.STRICTFP); + modifiers.add(Modifier.STRICTFP); // obsolete as of Java 17 } if (needsUnseal && type == Type.CLASS) { diff --git a/src/main/java/net/fabricmc/mappingpoet/Signatures.java b/src/main/java/net/fabricmc/mappingpoet/Signatures.java index a4f1e82..c2b9968 100644 --- a/src/main/java/net/fabricmc/mappingpoet/Signatures.java +++ b/src/main/java/net/fabricmc/mappingpoet/Signatures.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package net.fabricmc.mappingpoet; import java.util.AbstractMap; diff --git a/src/main/java/net/fabricmc/mappingpoet/jd/MappingTaglet.java b/src/main/java/net/fabricmc/mappingpoet/jd/MappingTaglet.java index b2f07bd..08bc6a3 100644 --- a/src/main/java/net/fabricmc/mappingpoet/jd/MappingTaglet.java +++ b/src/main/java/net/fabricmc/mappingpoet/jd/MappingTaglet.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package net.fabricmc.mappingpoet.jd; import java.util.EnumSet; diff --git a/src/main/java/net/fabricmc/mappingpoet/signature/AnnotationAwareDescriptors.java b/src/main/java/net/fabricmc/mappingpoet/signature/AnnotationAwareDescriptors.java index decf8ae..c845c8d 100644 --- a/src/main/java/net/fabricmc/mappingpoet/signature/AnnotationAwareDescriptors.java +++ b/src/main/java/net/fabricmc/mappingpoet/signature/AnnotationAwareDescriptors.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package net.fabricmc.mappingpoet.signature; import java.util.AbstractMap; diff --git a/src/main/java/net/fabricmc/mappingpoet/signature/AnnotationAwareSignatures.java b/src/main/java/net/fabricmc/mappingpoet/signature/AnnotationAwareSignatures.java index c6572d6..d762dfc 100644 --- a/src/main/java/net/fabricmc/mappingpoet/signature/AnnotationAwareSignatures.java +++ b/src/main/java/net/fabricmc/mappingpoet/signature/AnnotationAwareSignatures.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package net.fabricmc.mappingpoet.signature; import com.squareup.javapoet.TypeName; diff --git a/src/main/java/net/fabricmc/mappingpoet/signature/ClassSignature.java b/src/main/java/net/fabricmc/mappingpoet/signature/ClassSignature.java index 11b0004..ab15942 100644 --- a/src/main/java/net/fabricmc/mappingpoet/signature/ClassSignature.java +++ b/src/main/java/net/fabricmc/mappingpoet/signature/ClassSignature.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package net.fabricmc.mappingpoet.signature; import java.util.List; diff --git a/src/main/java/net/fabricmc/mappingpoet/signature/ClassStaticContext.java b/src/main/java/net/fabricmc/mappingpoet/signature/ClassStaticContext.java index c1933e5..22e0536 100644 --- a/src/main/java/net/fabricmc/mappingpoet/signature/ClassStaticContext.java +++ b/src/main/java/net/fabricmc/mappingpoet/signature/ClassStaticContext.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package net.fabricmc.mappingpoet.signature; /** diff --git a/src/main/java/net/fabricmc/mappingpoet/signature/MethodSignature.java b/src/main/java/net/fabricmc/mappingpoet/signature/MethodSignature.java index 6976241..bea2f72 100644 --- a/src/main/java/net/fabricmc/mappingpoet/signature/MethodSignature.java +++ b/src/main/java/net/fabricmc/mappingpoet/signature/MethodSignature.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package net.fabricmc.mappingpoet.signature; import java.util.List; diff --git a/src/main/java/net/fabricmc/mappingpoet/signature/PoetClassMethodSignatureVisitor.java b/src/main/java/net/fabricmc/mappingpoet/signature/PoetClassMethodSignatureVisitor.java index 1c6056d..eec5be7 100644 --- a/src/main/java/net/fabricmc/mappingpoet/signature/PoetClassMethodSignatureVisitor.java +++ b/src/main/java/net/fabricmc/mappingpoet/signature/PoetClassMethodSignatureVisitor.java @@ -13,10 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package net.fabricmc.mappingpoet.signature; -import java.util.LinkedList; +import java.util.ArrayList; import com.squareup.javapoet.TypeName; import com.squareup.javapoet.TypeVariableName; @@ -29,20 +28,20 @@ public final class PoetClassMethodSignatureVisitor extends SignatureVisitor { private final TypeAnnotationMapping mapping; private final ClassStaticContext context; private final boolean forClass; - LinkedList generics = new LinkedList<>(); + ArrayList generics = new ArrayList<>(); // collecting generic String currentGenericName; - LinkedList currentGenericBounds = new LinkedList<>(); + ArrayList currentGenericBounds = new ArrayList<>(); // bound for each generic PoetTypeSignatureWriter pendingLowerBound; // classes usage - LinkedList superTypes = new LinkedList<>(); + ArrayList superTypes = new ArrayList<>(); PoetTypeSignatureWriter pendingSupertype; // methods usage - LinkedList params = new LinkedList<>(); - LinkedList throwables = new LinkedList<>(); + ArrayList params = new ArrayList<>(); + ArrayList throwables = new ArrayList<>(); PoetTypeSignatureWriter pendingSlot; TypeName returnType; @@ -84,7 +83,7 @@ public void visitFormalTypeParameter(String name) { private void collectLowerBound() { if (pendingLowerBound != null) { - currentGenericBounds.addLast(pendingLowerBound.compute()); + currentGenericBounds.add(pendingLowerBound.compute()); pendingLowerBound = null; } } @@ -113,7 +112,7 @@ public SignatureVisitor visitInterfaceBound() { private void collectSupertype() { if (pendingSupertype != null) { TypeName simple = pendingSupertype.compute(); - superTypes.addLast(simple); + superTypes.add(simple); pendingSupertype = null; } @@ -139,7 +138,7 @@ public SignatureVisitor visitInterface() { public ClassSignature collectClass() { collectSupertype(); - TypeName superclass = superTypes.removeFirst(); + TypeName superclass = superTypes.remove(0); return new ClassSignature(generics, superclass, superTypes); } @@ -148,7 +147,7 @@ public ClassSignature collectClass() { private void collectParam() { if (pendingSlot != null) { TypeName slot = pendingSlot.compute(); - params.addLast(slot); + params.add(slot); pendingSlot = null; } @@ -159,7 +158,7 @@ private void collectReturnOrThrows() { if (returnType == null) { returnType = pendingSlot.compute(); } else { - throwables.addLast(pendingSlot.compute()); + throwables.add(pendingSlot.compute()); } pendingSlot = null; diff --git a/src/main/java/net/fabricmc/mappingpoet/signature/PoetTypeSignatureWriter.java b/src/main/java/net/fabricmc/mappingpoet/signature/PoetTypeSignatureWriter.java index 1d36b73..ab8bff2 100644 --- a/src/main/java/net/fabricmc/mappingpoet/signature/PoetTypeSignatureWriter.java +++ b/src/main/java/net/fabricmc/mappingpoet/signature/PoetTypeSignatureWriter.java @@ -13,10 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package net.fabricmc.mappingpoet.signature; -import java.util.LinkedList; +import java.util.ArrayList; import java.util.Map; import java.util.Objects; @@ -42,7 +41,7 @@ public final class PoetTypeSignatureWriter extends SignatureVisitor { private final ClassStaticContext context; - private final LinkedList params = new LinkedList<>(); + private final ArrayList params = new ArrayList<>(); private /* NonNull */ TypeAnnotationBank storage; // mutable private TypeName result; // array @@ -158,7 +157,7 @@ private void collectLastTypeArgument() { }; used = AnnotationAwareDescriptors.annotate(used, storage.advance(TypePath.TYPE_ARGUMENT, params.size())); - params.addLast(used); + params.add(used); activeTypeArgument = null; activeTypeArgumentKind = 0; @@ -172,7 +171,7 @@ public void visitTypeArgument() { TypeName used = WildcardTypeName.subtypeOf(TypeName.OBJECT); used = AnnotationAwareDescriptors.annotate(used, storage.advance(TypePath.TYPE_ARGUMENT, params.size())); - params.addLast(used); + params.add(used); } // (? extends/ ? super)? ClassType like in Consumer, diff --git a/src/main/java/net/fabricmc/mappingpoet/signature/TypeAnnotationBank.java b/src/main/java/net/fabricmc/mappingpoet/signature/TypeAnnotationBank.java index 3b24907..2a26517 100644 --- a/src/main/java/net/fabricmc/mappingpoet/signature/TypeAnnotationBank.java +++ b/src/main/java/net/fabricmc/mappingpoet/signature/TypeAnnotationBank.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package net.fabricmc.mappingpoet.signature; import java.util.Collections; diff --git a/src/main/java/net/fabricmc/mappingpoet/signature/TypeAnnotationMapping.java b/src/main/java/net/fabricmc/mappingpoet/signature/TypeAnnotationMapping.java index f6caaae..340cd25 100644 --- a/src/main/java/net/fabricmc/mappingpoet/signature/TypeAnnotationMapping.java +++ b/src/main/java/net/fabricmc/mappingpoet/signature/TypeAnnotationMapping.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package net.fabricmc.mappingpoet.signature; import org.objectweb.asm.TypeReference; diff --git a/src/main/java/net/fabricmc/mappingpoet/signature/TypeAnnotationStorage.java b/src/main/java/net/fabricmc/mappingpoet/signature/TypeAnnotationStorage.java index 14af548..c132266 100644 --- a/src/main/java/net/fabricmc/mappingpoet/signature/TypeAnnotationStorage.java +++ b/src/main/java/net/fabricmc/mappingpoet/signature/TypeAnnotationStorage.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package net.fabricmc.mappingpoet.signature; import java.util.ArrayList; diff --git a/src/test/java/net/fabricmc/mappingpoet/BorkAnno.java b/src/test/java/net/fabricmc/mappingpoet/BorkAnno.java index 1e13873..3352597 100644 --- a/src/test/java/net/fabricmc/mappingpoet/BorkAnno.java +++ b/src/test/java/net/fabricmc/mappingpoet/BorkAnno.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package net.fabricmc.mappingpoet; import java.lang.annotation.Documented; diff --git a/src/test/java/net/fabricmc/mappingpoet/SignaturesTest.java b/src/test/java/net/fabricmc/mappingpoet/SignaturesTest.java index a2fd452..4d3af6c 100644 --- a/src/test/java/net/fabricmc/mappingpoet/SignaturesTest.java +++ b/src/test/java/net/fabricmc/mappingpoet/SignaturesTest.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package net.fabricmc.mappingpoet; import java.net.URLClassLoader; diff --git a/src/test/java/net/fabricmc/mappingpoet/TestAnno.java b/src/test/java/net/fabricmc/mappingpoet/TestAnno.java index d9ce704..01f589d 100644 --- a/src/test/java/net/fabricmc/mappingpoet/TestAnno.java +++ b/src/test/java/net/fabricmc/mappingpoet/TestAnno.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package net.fabricmc.mappingpoet; import java.lang.annotation.Documented; diff --git a/src/test/java/net/fabricmc/mappingpoet/TestOuter.java b/src/test/java/net/fabricmc/mappingpoet/TestOuter.java index 3ea1468..ad86065 100644 --- a/src/test/java/net/fabricmc/mappingpoet/TestOuter.java +++ b/src/test/java/net/fabricmc/mappingpoet/TestOuter.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package net.fabricmc.mappingpoet; import java.util.Comparator; From 3af98049356a6f2bd441d277e30bee3c59164702 Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Sat, 20 May 2023 21:00:33 +0100 Subject: [PATCH 39/43] Update Gradle and github actions --- .github/workflows/build.yml | 4 +- .github/workflows/release.yml | 4 +- gradle/wrapper/gradle-wrapper.jar | Bin 59821 -> 62076 bytes gradle/wrapper/gradle-wrapper.properties | 3 +- gradlew | 25 +++- gradlew.bat | 181 ++++++++++++----------- 6 files changed, 116 insertions(+), 101 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5a2abc1..18f4e65 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -5,11 +5,11 @@ jobs: strategy: matrix: java: [17-jdk] - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 container: image: openjdk:${{ matrix.java }} options: --user root steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v3 - uses: gradle/wrapper-validation-action@v1 - run: ./gradlew build test --stacktrace \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8e8fd21..0aa4e24 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -2,12 +2,12 @@ name: Release on: [workflow_dispatch] # Manual trigger jobs: build: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 container: image: openjdk:17-jdk options: --user root steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v3 - uses: gradle/wrapper-validation-action@v1 - run: ./gradlew checkVersion build publish --stacktrace env: diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 41d9927a4d4fb3f96a785543079b8df6723c946b..c1962a79e29d3e0ab67b14947c167a862655af9b 100644 GIT binary patch delta 40199 zcmaI7V{~Rgw>28uwrv|7+qP{xPn?dOj%_exmnx8HNdckXw_xa0n*U1RT6 zWB-{|bJkpI)h>a59)UwD%Yj2+Bo$yL;h}?KBr&=C8w$w(GhildVE)%L1p<^10|NvE z1_lHKLb@w#T`0x{1l?Q&b+9S)L+*UZOMUk9YN~Nr zcLekuo$Y@Aees_|7WTOb0O5*xf-|f*aNRBu9f>)*H|^*aACS{fmv)9U1eE0K1v4x?Sn-Y{ZhyVgg{)Uop+>#9_4Rp$!fZd_f^4tWJ_^~ZI8g9zHvhot=+Xie%kIcW+=j2^gM3@Ac-nfzN4ov_~>{o&jf4Snl^ncq*1DNylSjZXK@29x`M zJ9ALs^$NBj_wtUHQ33-K{bW*F4p532M3Z~!-D8(`P%_cH>0v}(Att66_!VkJWAy3JYL~CFP}$6F4NGO zLE_70fgc6VtKx&OSw224#wvA%b9h3!n8cncCH1(ej;hx=-U?uL7&~BGa<(a-x*$or z;zDm}CUZnWmb3WfBSCsVkX%OveGYS(>>jBPq0ULveG9I=$nq=06f6c)V}{X`m^W@s)*xZ#GoJIfv#alr+-XMuJqCN^?yDL%LxPb(iem^)pQwoj(* z^0jQ?F^R2-&jb*87}J5OBX6S3;J8c=4Gq#ov_R1TygWVa7y{FchKd!-F5+dp{?4>7WR#SENb$Wokj6yzKv zv3*4htp4qV7nmSy%@cKE%M-_n=pvvrK+O3G3s}9y{!B9%(lCy#GN}0Ng!dH>kcR$J zGp^LS8wb3hBw%;Co!b{D1P|=C=W-oEdquIs%&=87J4$F5hQbnzzstPOn z`Ic3I#Ti|(BAyFFQ)Gw^KP*bMhHxz2E>A6O#0Rh$LzBE#zBej~8c~JcgQcsFq9mhf zs5VfdQsCz>pC5-f#KlXM;E@G{D`sfYT%@3s%b$i>P>F^T{2Y5qMYYw>w%t}wOzjz~ zXNPi7V8EOz0Uk$d7e=KWfJuaLG{UVlUrp;@Woa``VlEU!ahftNsnw{77gG(Qty83g zGXO%AbP821+3}BCVg=T$-{MntIEc8%kf@ZXbTWI?mTVM&HcaG=gVSt1%Wlqd{YBhs zFP1|l(XpqMTy{LUEXmLIRmZQIiVD*HQDt#-2E1^+q2Cil|HjAg0KZOnqPCDJOx zw-i?e?ktI@n?ztM_iz*Uc-ouro{!P`EFNUUSzyYU;7-;;3H5sZR^R~-JU$0X37{6k zd^1DD5OZS9-OR_tT>TWQcy?8{US2wJoto*`C;{}*&fIE7DU+?c-6U~>z7$pRJgllPL#0eoiMROQmwb=h68UEq{W#m@cW>*@|mxEvB0_lDgR zdpdu~(|M_w+v2^lWP zotIVErp+?{GcgsSX0KjqzwT_QQYfQ_^@lvgqX0v;)Penj$b(HIB-+YE1~6A{!~K0?eN2)0wdR3>n|EynF-3`pF7GdSnAXb`op*wy{DZk~s#e|Yib7-q+&!~&5VFXn z6f*>pGdHrvwozL98t`UnYt5N>W@~M5&Pj+8NJLf=-WSq$Jad@g)gJ1aVHXaLuy3Q! zi46)4%<4CmxCvx!|{+;cX80md-uGqDJ zK^c?q7P7?}>Vdr?4{A-?xfX&rPn?hzy!Lp&RYs5ak<+T7pw$!%UN5ac)Ov&h3)R8} zN{$T%%BQJiWe)v&6qX@n>$o-zpQ@oq1F;IX#=bTy3p>!c=$?43{2N~+rLk5;ZQ}i&QWsWgN{J~&wi2m2+0XK?Lt$3{jji+nDzPS)?@axGqXa`_Va z{(@31ts*c@{9Z(8Gw`AQBSp2q_e1y+m`~;j#WZES=Aca$9K6%}0Q4`Y;pGc%bGhv3 z^8vehDG>XuPXVZ2-F0!#b>mqh3AzHt$}EH{`pTWR#hZXn)kcJ48856fAEmRa49cfX zWe^xV>Tsirp6^cIt|VULdQ*8lm2`v76+Q2?oI_DTKx3yY2nHa1uMMn~8-Jizs5_fg zNEIq;2$eQNA@gj2)Yv2aqkg9mFe$T+vx(numCq1$sY;FvQ}FLFBclze{$)EIixY}k z*0{r}(fj;@^p<*>@=p|GM}}f5hwEAdgzO0h9_hKp`_eVopV?tMQf~3pAY*R64@NlXz?lJ6WF{*07XxRr@Ha9hg4v_z&S5u&U*#BFeD*NDqVl>Oc!NmEh;-RvppXGO% zu`aWY!Ks ztjx-I_7wjGq%_oCY#HsSxZ>;yW)q(K5sms}fM&)s1o6_LHwp{jF~ zbzt7U-a)H`1NK5f%T+9pam=+TJ&rLuqRImOIN8zakHz}%03*JRi;IQ#z+_$E7lU&=r=vymg+e{ff$6CkjHX+>i0-OaYztdu z^rH=9^BJnwu^0%p|7~&RVI^`(#zDrj2~;z}m7>-V%cb;DM_c7t*Cy=Syr#_YkcK|` z@E_VFLc(c{Ag9`rpPHG*o?t3Am`;$jkgO#*P+ygR(WiZ%X1vLO z69zs`SbOqGcHUgg`?uf9%oa8P%DIJLN z7_nR!RQKp$udZZz{t!$y0?*X-y4^IMdTbX0dG?%SzVe{-t)0IwOv$W7B>4Z%XP>Uk zeFiQ7>a33=TzVVs{57_R_ms~{25f(WK}4vHol6~85=z*Lx*R54<>QcA4#M4LDKH!Ufmggk5qCy|Cv7^| zPr*Q_##e^RhFNcTQl#q|Hp8NQZ$48cW9Z>feZaR$&V=vj;j#v>$|LnyLX8K+n0RyS z2GmR^>OWRN%+U_rTL#ReC%k3Jr597y5ALx2ieD5nTLc_);54AU+Bo21xY#Sui|QjkU#eb8R`=k^&jYxy(%ElVnNYI)4+J5HaHn9;o}CAWPrt44rj zvZL#0lZYTv5=Q~>S>pI+yRy?UzN-(}Lc2z4-$}GIuDtn~eBmlF_#G&5X7;gZpQ`Km zcUw~s{=!X1avr-|KPy0PsioyqUPB}_hYxK$aF~n^m{SQ@*!#m?NjFUvT7y?-zJMq; zrV-Jh{f^#9+U->|w1RlqUSc|Z4on~Mm}ZqHr~<_uMRo%`Bd|w0A-?+`Dy5l}TuHuk z)r;m34@D}*eG%hPZAN})IqK=Z`}?%|dQJW6p59UL%f~K=1rz*b<12QCsw^m>ip{ZN zWqw9_C1is)gPU^ogFVJ5ah*zI2o*1ZM1()TIHo6Pz>rL;?W>Ico(Bpdd64b>AGBa{ zOLcr~q7nd%n$h;g0)z9q2yqP5V51<4k+IM%p+)2`gcDX05A0}kLv>1iK^LG6^X?9y zZluaGR?>^oLNO1dzN9r9%F72@CDR5~g_`S7i_>u>wk_k5DLGoP@d`57tQh7T1ee|7+>jaWN_-q~Jx3nNf7E22ZmbRnW*{NQ%g>PK zhk0W6{x|xR((ov-N!1mEX)u*_8WHKwqwtEKSIN z=S<}ZcI^djHg5`lznx)&xOr0?GAx!`Yp1e?aY$)Kgi+$+>LZ%suJP2x%)pIRDR+^I z0Y>@8WW0F`N~$~RJQ82 zR%P+?4lUnQY8tdRmGqcrMD$EM+b!z-^+1&BUMl*PyJ?!ZYRk_zgiE?^uP)c=VZ^8* zjW)Z&(b`n18?nwEo*XpA(o!W{rSq;Z1gP2ym#nl&5$Q0?>TK0ix$wwcUd$sYHb7J< z5xG)sh3Cy}WIEah!lMHtQm>CkMnG;;PIG$aVanDg6u~K61$f?6 zDdi+gsTi*Zkoz1H4%Vdj^;)r;W?&8xh_(FkLvSrzZQz*1O-dXh{usa#+J99SLES!p_1AAw9yw|V9IMu=M#B^5Y72j{5@sx(&}B4TP;cI16L+BMvN0*qBiaBd(6 zxS;QF?af}c9BaCR7ngJ!{Ej&u`OxT2QnNJDtaUC!9`^6#2~)2NnY_aLgu7+zzTv%p zeSF7s4$IV#iS{g^wCXcppp9f}2EK|jLJw`VbSd}=&&V=-k^47#n<9VR*xU^9bL3%J z*%JlWgNme&c2VG$u`iC%05&3;i*#k#B9NUMZJwB&9~Ww_#pp)S?U4hr8;O7W1%D08 zITHtpk&wqp_nEC?=D#ED2aJ#KIE1n;YUSOS72pUl{*7gq05si#6$&DJbtX8o@{;u| z`d)OPCkDL}bwKEmWoWTZrn8RLkq*?6Pia;%>U$L!d5RGJ&|(di0faDUsCPaF)_iOYiNCyGj!THAdi@<_={n$v@1TQ@=WXpj zAs8e0Mesa)&Q`}`WVPGa81!OeC=t|a95MJnD*FJWct1ioSVo$IQ7Z%y&+mp>fV6VP zF3O+%O+FDhXY(bRO!)oZ?&$xp+O5Manj9Di$PEMth~$5r5`PaV0i|jNO6VdOg3W)m zEA%QMtBPRAWc$nunMYe}mZ_)|&ZSfbKUxUSe>ZJSJ4OLUzUQ%xSndX1FP+Fvb9WRF zv1+4`bNSs)w%u-cbN>e39n%Nl+2Urb&l-y`(+Vt4k)!kT8E~j@sj#Y8NOPCahf;|Z zY4e#&w{-^_YoAMN0lJCuAH(>53r4cN#jl;rl4_~uADXjyQwK!EVZBIfJ%wLP{m6@U zEGXf(_n{`Q^Zrc>RejYd+DdT!5dvrEF2LCm8I4R}@LA3lnAIG-Z?d zCjLcn!3?!Fx#lN8ML&8lV_2VPc|9C#dQocHKlCf?6j>LBW;78aJ9MF#N|ZDV|U>#`{=~=ySRpmJ7TL>3)iTZ-)Qo&l`l8w&}k` zsHX*5Nh^Jkk>R&a1rul|$mFSVm_o0wAYqX8yRTwgn}lAYuOr;OG-8fI15sz45_c%i zn*mFY+eo0A%7Ce33( zDd%BrbBx7tqp!(mPt`}N&LMI}1_DNL*Ki@!#U-2vP?sUVrS@}F#&iS&?}Tp&zM+t% zy4$OKz~H9SiXQ+=IHGR#A}R0_af$B51U3`ZFt(0t$=0@ICS<)=bxSNWxuw zMU-m(lauRA4&rt)9gpLM_aD>K0v2RgQN06V%v9NV73 z#ZTNTzn);j_-Y|?9g&(JOCmf^pLaInDO9RVHTC75ZQ2I*Kv|EF@E|mv zsFv_J1M2VRjnuY-2aCdT>@x|Uf7nWM8wBfJln-{9EV(Jetr5El0$0^e1^C`zi9+(CwM@{R~1L_S5UcA zJK_^PQ6<#;hA~vT<=ahkRv*abDf`WXMB@$bMDHCLy1bh!+XM3eThFXa}jak>rl} zaVS4&V0`xI$l6)h47q-M-u6eAs|PZAt@FnYhoj)PYGGH#D9ebibaAzhLNHY`Cs)U6 z#SO+O;R8G;jb`5R45-(9^NPe3$@jt!bH=0$id-%+hob0CDJeFaI7>Vj54{QJRW}E*vA#8ljcU#pJPjoY!m%Bjz&i+pQW~)UF+b zBVT?SCXDi(CwJ+dQPstw-Z(3fc{YTM(QR0bY;n@Z&zgy0jsV!>VJ=g1*B(A49s}@_ zA9%|Ifys$7OWF4#$cvF8N)$~uNa54Fj(U~*j8Nr=+W>*99zOW#N%F*>wa7Z;nb9>p z`s<6{Pa>s8Oe*gx>JfC;$t_g}l4mo^^gWrIrQB-t;r$9NOan78OVWfHG*{w2>4D;D z3*8)aip3PZSfziDKo2leqkbvVBANAi zV{#tAU;$#*l<5t}7>An|*J6>}!FHnsF?XW_81FPM9V**R0b(tENEhHY@rjs!&ZFYR zgu=qDR2Ga%!-NKEz7|iVU|s@aH_BO0^oMxpmbTo=9hW+5Ou#fK*F~fMJZ&@F^$I|8sZ(T>=HRA_!jrt4*5_WR0n&aWW- zQsxkNPJ-2N3=0Mg&3eI5^?`ewpF8bk%0+DCA7pz+s?PccSJPi2cps6dUO7s-KEGcV ze`Xp3wkCIcm}=VHg-S|=LYd;Vc7G~nC(Ple^&U$b^g`C5Z7uZCiiHlzhgfeKByVEV z{w-jv;?4_e)E`o~d~AcK?hb29OlrxPK{nFLW&c)weqmvUC)jQy_^kz~_*N_N zEcp<-?_p(GQ8~8BU#tA>+;^SSv{pFqPER-8YTtnzfn?Ssk0(LnfOwrmD3nxaOz2L@ z*ES%Ed$`Y8{uA2h=l8+)0pL~F|Ckh;(j9=L2KAymEO!TK0?c$xXMf6;*UlRy1hS7u zhQri%1}UIjcLuq__Usk^0mE=|QJ}0i3dDqPq^2!x2_PECkq6nPs5QqvIQ{xy8NJvX$c#HR$#E%^y&3E~V|hs98B8c95yqkO;ZA24ga z_hzqXNz&{X#0GsEx!j#3ev8)mXGxIK!Rlxf-|4Z-n>0%FAe^`#*+M``?@thA zsD+Hz?2=pHN$XX9Utb`2#z1mB1{~iaO_>fIt%s@<6!*$TYVxFvJTd=BHDt2tUb zOeiz>Tbi@rk^$f;+zBn#N;T`ciBVwg5vEyVtoGMMUB!l_&r;julwvWdd9AGs`y;+E zn9c!>7o*MF3+%(2AxJoQr^_l%rg@hp0Z# zBW*7!J1kI&=tqs$5BH$w)xWXiS_B=$bZ*AI$o$8h{aYR~8ZLk4RPKpVY1V?;+bY>s3^PSk{WtsDLAf0r#rC4ViBs$tw7du zPV2Xt9Ot?2XSJ>fXHZ7`d|7l|dLueT(*Gz(Jhhl=>*hy5rViO3xKFWwvRJ89X@Wgl zx8|fT^B$!~yhp&urE^N{XehY?@MC5&iJechS@AwkB4PLHP8<@AJb7$!jo5~E)yV+E z`x%ycGEWUs6u#O_lPS9c5QgT(?=S%~ZitR+Zj?&eo&h%ZykZ$Ko$^3>X-1bz#4#a~ zpTsiHfy|x1V-w0Yl(NrP&3do2r0IDXRXEoeY)U#6=cFYFVJSRvMswl;fjNsV=tFdW zJhlfzq9q9Bv@J8>r_GPUt)e;QfQFSCcS8uFJ=>~RTtkm{JTDg#h|By66C%yrfWbUA z`M+`w8rv2)$axQs_I~lj>3;LaNd*Jtb$7Z~1Ncg}Y)&oHee#+e*;R76c(c_SOCC#Z zKAj_(X4`VSje6h5UqtNyt_uTO>JvP~QCjlHj^#5kyupGTCz8xmbfr8N47?&xmK@S* z>7OjMGUQ$GmJRhVxN2Q6fcv?SS=Ahif<{(~b)JavUqv{%g--(WyE1VoE{6RLbKTNy z;u5i!*fhjQZ)6zIQ=YftNIqo1pK=&hz*y9LE9d|R^?}z|7L_N!!elS$JyNA$MfPGc z>ZHIsQIy~?SAg2bdZ1oqr3_TMRO*c9DHf6keDAf!W;KijQKfn}isY7z(GagLqAa=M zT(j&?Q>Z$c`)@PjEEHDV2MX6>gP2pN|BX(BrWC`jf9S0GchGYG%iK7*S}|L>nwZZwtYYt~J^c|Lif`AnNGu(Lo>l*!^aDqRmDIXOq z;3xsO%}kZvp#RqbUIyyR%76cAgZxj1=s)h;83j0>PBzTPx4vuJgp$M~)VD^`5NHbiAjFeAU5qd-GKDf$R+d)1Z^|2eH*b(HRQJw~OU!rU?lLWRw2ZL(FuRVC z?oH#m?x7#mbE{HPPjTG1W-^2kht0?*k5FBoD1vK8cPdc1{T#HuqfNtuu=;=-Z@W4Q z&B+I4Q{>uQh%>QjYXP3xzVq_}&Ph3U>P@s=5&*qQX889pf}4^M5g9i*X|Hqj_UHan z$NTk6J%d%Te7&IP}S$JGbZPhXrn5;$R=1*{?EUo%)jizz2FWmhXd9ovJDw7RVD z&b*n)aLV(Iq60hO;!-SSbTwl$W`U20Aw+aK_~s+0^4XC;GnYP;XAXqc^W+JWZRq;d zD;VO1(tkwT;81;g(<71t;iMH(O;pjtF#wA;_*ZO&Ex{5G(98CpAW=>@ACL}*C^9C` zN%;#dAb$)@Kn^?JzMH}RRax@?4=Pg8b7N=(xn;A@w*=!@-5Is`)ve2=Up?z8Msr1 z3FSRliWTSBhG;F((R4)&C&46-12J@;1oeXz`3se(-jM(Iz6twQaY;*QtW^V)PGQlB zYP5uC7nY8z{(zw+P5kE;Rb?zEo;uKEHvun`cNp)Cf>XGed%T0i(Tladsm%PF^;8&i z4+|dxr@3zeZZ4(+-=4q7gCuHBrA;IwnXnNd5u5qcrzegJBYZj(R+k$J3jbw1+70-( zjg{d>2%%cfuXGTGJhoc%+K>TWjNcvW9yIK#FIj^dsJ)Dbj;e?+S3#s*0T`QkTQC7z z4jMf}e7rKEfs3OLwj9z zNmR~U+GXV7Mi#>TwrL!lvl$FK_tBWDG|CU6{*h<0D3nXTKxv-mdnv$=4R>;k87-w@ z6|YUXxOOk(8cXf}gyUh6JMWoHVbbyfdioQ;u{p%5OxpEP+e(ox0H#Yw4r8CRyS_J< z`0BDw-VS{>f^Emv8+o1&_lcn3HsEsF|8{^$GxJy#OidQPwxe<6bK{C1In_If`Irp2 z**Ked;K@wGdp`ClK($euA!4C=*)-$)TWOxsg`pkuT52xBanrnyUAw@mJk%u7uo8|b zywv(9SqcMrc7`A{KniK>-@%=EBx63#Z3B?~V+J5cM&xc88J(09Ocr*VxGT z;M7%dqn;mIR-^Ey_M+QCr&ykau3%p0MWYm@=2sVw!rLna%t5_^M0msT)|q7?7xgdE zJdiTn$%|X_I&M-@^xy+=lePyL?|G8+26-ISW(e+qVtKMer|ygE=0+wB-Ye{S9J4#u zJk?=Z<7HNI`2{lzHwfUleb&kGwC3gl8;nho>0Xc)TJTwMpxB@2z)0FnEob4ulRJ{8 zC7_~b&OI#|2CL|9SeO-*brzW{&NtHkhG`ALC;?Bz-iGKBT$hR1K!OasBkid z;u6}ZvXeVtO|~!`W-rImwY~$-Q6uMLx9chSox;6qeGo3(Pi!IJG)09^A)WH<|HwP% zGwZXp2MGKEa}G+6zp;~lXq6rrK|;@l~B%bK?7^3DO^I<6+dADNIakMw48&n^1F9bp{R z66mf|UM^!l2sm97a|sEPFMmNRH24jK;{k630?sekGt%>@kl}SgGysHL&w2{*GXl@b zEe%TRdX`*7S9_lE??qrzd0q%s5oUCtW0(_g2E0%Y46adZ>S}C znT`?(tiolQ3-oZ99S|RVZ;0vy_N9KA^DyHkd$O%8RYg>1J{6fdoOvBDrO`5aO3ims z%XiT`tQJ^V(YpH1J^I6(Fs9D&^g0R7+a*h>2j-ucJKcK@tN;s0V} zl4dQ~T6`mTZpZCY?B<~6e6atkX1M6R_u2>z1mui1r9PA-IR*;AWM*&T=9a7DW30Z? z@f|QRy*)7lDN52$Gc``O5lVwPh=;`~3x)?VM5dUWZ9dL|Zb>D&T@m6@IkH+C;z3(m z)@BRI8KiPwu~A&i^tiZ0!hT#y&~gY+I={1edX0(q^)J{LBXsmHIIMq_KDpiF_%s+2cD4ZtIap=Y6fj&^?$Q!;#R#t}mUHbftw=IC zXVs63y_F@hNJ=uCSTj$Jw|NcXpR!hfbH_LUua7mMH(LRi<>>CKC8%M9s$uTkowJHe z*wkic#0;@TArq_(*B7fQE}1vQZ?H+ERA$L9v1%!V9R(s~2 zq`k>L{wtf-so2G~QLQy&^qDdxuu@8&hnH<`Wm8NkHPk6n=a(9@aIHK47mR07@Ziz$ zBmF{^-osEw#N-rBr*bOXHA(Ay<%mv!2@8jFzX8_(4Q|-fQl7<9LP`J!c5SS9!1*G1 z{7?K34wM9OP94UK777%0yFpfV0{GF;U)g`7AbbGN=Z_wC5Qj`i?UCeqL(fN(KR7HU zFAjr&l@pZPcOfa$oG_An2=$m4%TQ*ljt+C0QhK$t=c+qs+{Mq<@+lr63#;S21J(?N zdmGXnT+o9v<_+uiQQ|X!hgmgBxCOp;B(|29T_TCutj@ID^6lxy%h74owwlWhHPv+n zZ7u+drz(vprYiK;bSF4{qKea4XfaHc=9O*DMmCgk_5F?zR8+n75d#?_^2G`}aKe&_ zO60Z(@Vi+WPW^OV{<%Oz$iZ4nuF#Gt@`cstRqFy?b4`x$5KP#ebm*Zn#>;KUBVINX zIEl7ZsP@bmSU1>I3n`sL+^>V_ib^`ZqE*1wqA|lf4x5emT(>a~juFW?6N9NcFkL)L zfl}D3>SBA_T2hNvROIVkT8*TI4+XL6Ww?NT7mMO#BA>L*!5;47T3K*lBm4sDTyHr) zw6%se4w?6e>#0YT5Sj}tV55zS9hVOuvKfA1CD zJ?+eHmK|Sdf+C)rREBU)(hC7w$F+c~k1unXOQ=jB$zM50b9&0$9V(TBv0NJ-RYOm# z-y=UVY7Ql?CB;UQ!*GpqKo=C5q@%{K)~{PNVG(jHW++5Kt#~enDk@GEWV*878o$;?N&XN4MvHg7 zKv6&ziZ{X>52<^mWYj5D#m|Q`?}>)W6e|to9v?5BJ!8#gb*VzBFSTsnsGmqMA&2hh z!%}uMv_= zCY=b%UC$D?kStAO&ZPtT8)FHHzvjkWf2sq=JS`TWmZCGWld|_pV#2BLoC5T zO9hh=E$D1nKGx>cYUc5#rh!jJQ^fE_hkFtI+9>ZZBtDDfYUEP=DPRdw?m9BoU%PJc zn`+zs_f*x3#MvRbI?(EzY-;|Bg9=%vv_E?9so^hOEMRmh}B z0{+;!Vl9$Q(?(*0IKo*XV}!T_sVv|G7wwlKUgy7pnJJ6v0{eNwC3vM))Mg`kdOfeR zPejTHcbRfht?{%7eM&8S*EoA>cMPUjOiG$Rzp(M|Av-it4XnnIHe|e8{;afQjc7H* zXvmw^*o*nF9tt4>lUD#6P1YP}oJYQtkL$rUs0f_Zv8d-y5*-7H_{UUYj+zm#$@bhw zSZ__FUFPMa|N1w?ddZA9kGMvv`u3oPn@HQI2pMV!j8#WQ-Ead9FgX?8HJnFLriywm z!q~2I&s~0z8l`ll$Wk@1Z#!~PgC*$jivRh`%o=f-E{I#DE>#Q&W(uE1h*IqfHac(+ zyH3i6U^%*QtuI)qnipdQbk96Kz}!jce#W(Ub~E5SQ!DPdes`p^1XjC8znSI6vAW4o zBhz!Dt=lhZvI0o{B!r0>e0h_s&N?oimuTa-=3g!x1%lU4fJgWj=ND9(4J7u^H5e?J zE)C+|IhfUw?xg}UNcWPVD;GHEafnR2M?V8w`x710rpFI`Sm97#Y62#s_nvK^r7eIG_t6e@=nQ;+FOSqPqExfDkJK{L)LiPDTv)i9 zB&qr2wDZodR9tT_c;CNkDW58P*J&6bwYlH(oJ%D>LcrQW;hY+286EQOEth>}6wkJZ z*I;3+@?cF3sq>UqHmr(-1CB#3Um-2LP1!BXFXSd;Nw?QO0&3<%_ATAAJ3G57RO4K& z;+g@rosdGBcyL(!9e*CKbF+EkOtCBA>!^(_Xk3PpUSuW(o9;%*EA2cBi%*C2W_ak! zh3-7M&fzlQ$^}T-xAB~s2UDTORmp36+`JISHZrTF2M7Sn?U^=MU34=B>$nqd?r>$>b4jV z=~2xPyOEUYDLnrAm={u8;Sq3c))H1~*rV}_I}?|y>DSt3%pX4II)!`uq)~;xwW8zJ zTxJ6m8#$fjl@K>aVXMQZElivFNlQoog5Ml1#Y92)v;MjQUojiEt!#$090=b4rU(v| zjTyY+ZQ1!W?kT{H*a_)LWUJ}BqUa)bCzNM+*GNn;K$+PWL4dDph5GS)dpsN1-yGjK zZc7b}b9`8-v;MNz?-{o_4c}G%q-a7S)p7skqwB)6l|Z&X77c{q!DE|1z`kARKIZ$@9F>2u~RxMa_g{eYCYwM zSv^)vOs<`~l37sLOrZ5s{&8LjDA^6&Hk2=>SNs#;z+^{~2I$O(DUlYH+)p-N80xfzeC-c9Qd z#t}`5#^s2;?Fe`2uRhs1^Ga&%bK3M{4}Q0jkKu&Q#>6J+PGHoVqddMmfJvf6k11Pa zEx=z=2YHqzU^^NGQ|Uux@+2H5GKM8QN;yu0hZy^z0}r&u#8p3piNlzGl?`*1^?LPC z#J)cTi18f}=Z*MlU#r9)IqnrY%NcBj4WTSnB1Zm4_3Hwa#5#plvB5cNvd20@HcAqb z`}oQ_88@04MSO3^j|5K zWLF<&VWQs;it>Zp4ZnJzSqJf!XfjRaRI#!Z4;@qP6#U^khZ_=G{F1~f@oIILUuI+; zqi@lO$Z{odFIx?5pGiA;|A@2-#5pyeXl|rV3q3#oHnH61c?0ha1>CT4mybKqoD@&@ zjU}Hssstnm9tZo3^T(qh^5S_~uX|xMbHv`~a|T?hU^IClaQfSx^2tWU8xNpL9#Zo# zUcd-kmRWQls()+%LINB2t+AvqRINwq$`cJfy@fG0CH9>Z#7G$nBb=B2)zTQd@at^v z_aEpAgcD_l11q~m0gX>^PDsX<4l)KC`?6Y|rCt37zc;7UnVjcp?o+AU?xz_D26c3_ zo0n#Qfc8feOW5;Cdz8WTCI~1EI&-?KfsGyNUFPeU~Tr~_qy7pa*U zVn9!NuhxB@!~`{&@cs<^8-GyfkqEDvc4uA)4Z{-~dY&XRfK%~(p2#PH-1dalIoFuR zm!rkbTXV=nDE!YWj#@(1LVy%YUQDl2C1Z-Y@Z1&5(7h+KC3h-8Kf!?`=AE}A_`cgN z=yW~39OysSq=3=4F|kcg{g|$KT1Dbk4(AASMNWIzthrLt9xEjdvM?-~Qie)y!W@@W zq`Bkh)fG)2pjmAQw&f8ngjom8vT@=8RxZX9Io-)x>C|cb`!OogfA`Z3`9R=W6x9}E z3p>&7ZWo;K+aC$&&nxs7g=t*#k=?)UGvxF5nZ8&om#bA4Kv^jz5kYw-z9J`Gg$cwQ z*B}r#D9vsxO0U5ImXNoamo|-)>RU6mL-4k8e3PvKnk$^fHPNdfo&Rh}k_HZ22NJ8@ z30S!S_aM5B7ivo|c2Y-&0ubO?Ij>!54Tlpngr>G81Wax$KEn!g$?NwqKT~z~Q%-K# zuan|37vr>|)|g~J8ScE9AFdn4zc!M)^OBDMC&N5`kw(tbf9~X?$M9P!Cfo2?KOw5n zHlAPrztS~1(9EL9IKqblDG_)ewn5uDBSNSk9g2AVi*CzrW)+Ef0pY@>(ez+bP=M0Z!* z+F^U9tbtO0zv;uBN^6kz1^^Z8(I;>9Krqc4gLhSvbnE z8dp7%8^u($UPJxWL}KZZ{H`w&Jmi8XiL8+9KS$jgfIwm0)K*=;`8H}1^h>4YrIF^t zGDCH)it{%Ru9b9MmW;quc?LPqsHx;BjjZ9Kmzr~$t)@WA82{f&IB~)c?r-n__!nfG zj=m7I{;El^Scp84)!;o?{JnaEEm_OPstz?ONTv(xvvMBln9~D5!jU9pZYli zjT#8X2!5mJ<34eS)x}_zaH9@>E@C>&ah&qx;rrGSeGe~cc>JWRS-{#VmYtKyG zRcqhgcxCDrE;p8DUw`nS-KN#t6LIC~N;LZnZ(ncWmrD=NzkW^e_sJf)&zkf&+j}DA zLFvDYtrXHz+?3W(a;DWx?#>Ze!03{y*JG0NnqN&o++k7Osva{}cB=b*0^1nAU;+l3_Uia%oime+zYO zoYm}Yod4TA3s;x(T9U;0qG}=^(e#E<9W1WIBa*>L)Flb00B}HxTH7diXM|Ce#6+?4 zh*?aejh391Wq(DzBD)V2xtq9ds&(EZoSzYHKwwXc#AJ3PbnJN%7X!Zjm9z#uyw(K? zgn-2#qNC^Q@;Ducf?~631O?AMo+XD*`R2E=6#unk)L*zi(amVS4G*u@?X}$R4EKTO zW?;Z@MmIwG4WQp%EURbqH!B*R2S`Y&&amPfqE8`oym^bUTry8cGjQ2nkookli7oP! z0tbgI@}wEPQh8fx)gl&DbJRm^2f0O2IZ_e8acPsp1rRhXdI%=p8HR#Wg|R4@#OXE+ zk2pI6ExRAXgpWnWi*1!PqhhO?(VePcs3$*j4ci8q00(I|P7l73OD3625>94_PlLJ^ zJcd!^BNnNh8M`8V~ z%?Qxdlh(A`2bI-*ycsLGY{^vNg*C-{2>snJ-TD4ZF2|W3yK1?40+KzntXJz4H_DrO z;@z$O0$^D=T((BZuC0MxT-W;y;PCd_Ye4&%h+l-3_NjOMqa|%GZx|EW4*~dco3^iC z{|{H^6r@?yZP|3CZQHhORob>~eU-K=ZQHhO+qSK){%?23y&bV%&+CeP));ec>?)z+ z=dV9~QOf!x=^D*<|5D06*2dr!?D+mVQ&sA!4m&I7KZBX0hnTxGPsn>HM5=9)& zmwe!S+LA2R<1Tq>>KluhDtDra6N}`5fT!|?#l!22hYVh-NCIr)@-Q1PS|nSSYZv7m z`J_@N)C%D(x&3xYR^bgI8D4KhRxn?gqprD2X2iYx2${QN$z#uTwyQ0EzWc$E$FPT4 zeSFy&)G88E@J5!ZC%r#>B_ag;`Aq`K@B>9lc03AUitE1|kW08z)D6scwX7ZLoz=`4-0rrnodeY2zP27cs9 z>z3ozeO5;E&JbFZtW4)zLzfPJZ?DL4XRvGxcij1yZuGJ5t%)L)XC~0O-(H+o3 z9b!y!oS;s7*w%(j$|I!&Z<9<=uw~J0k7KT1+79U|zfKg2aqcq* z(uSWi^P=W6OvFned%?#ah$C8qNLpn{i=oWKeZii84MOL@nC5qcP6Bmt z-|zzo;SXh{*mz^diC5G3}Me@1_8#~Z8o$**^)qDT; zLM2QTmCNk4qv1~^FfDvIEt*!bM>m~^E$D7ohxNXC`I}}%Q~S*DS2_w;o%)9a3hc|r z3PqI|ym=bMNuhrADPF3+lkh^LO)>kumB8p%2a!)DG{9zB>)g!ADj~jpD{%T3b5(2? zBEqdguJ7J3_&MNjH(q905X$OnM_E0QRzCPMgGLHnrd8swvwsa4%La_GEkjIoHzzYN zfEEwNA?2d#Vfha^?>7Z~Y>st!=!2n4xSlADMGDUjVYkW*@J$l+TA%6m9;{%8xXe`P z%$S7eip026ERKx6;zy_8joRZeEOSZ9HXCcXJHd)$0d<`o6GyGo#U6RHL$IFUUvu+WLWZLks%*RTQ6YTD{3>ZsrFQmKrvdc@E|{u;TYh>~;bYPl-W zl(V_Xl{`fuFB$%wDQbQj$M~QHiaThU{T7$n+Db1D&u0=%k%=L}VmUVpsrm2i0M= zPLgCYETKYEoe{V?+Fy>!lG|{^Bzwt0OjubO@pt&!_9M1FgnI*oDti{Hw3>B?qz+iV z#9o-z$oH`0orVrHWfjd+wjs-wQ?r>^5c;gmle@puxuzW$i?BYW%WB7~F3!v46BNcL z%irs*EcZKzA9*gY-@=MyX>tIg+E(%>;oiwwv`#dReXMvJd9h-uEb}o|T$|}ekgNMi zhK%hA?FDwFP`YgQ;f=%3P1 zR!HxamYhBdjtlZ>Rxyc;msgCfiLG^i%N4`_0iml1O!$>SH!DjQL}ZK^c5{#`^;Ejqp_0|u zXtnc%Ts6abuQmxvM7O#88?MfpeQuTBB5l8|mNqK0ZE__ohO|+cCecVRC^#sl3S%@! zctDpZRUW?O=JUfc}|Ah;zNxP`IHwObd_R4x*U#uFbfoN9!o zcD-0T{r;}7m8!vAN>tw|lE}D3tHN`b#F2SG<-o469egW$cbZbCRsNt=?)L=UTMBSL zZcE&*$I~mde*;)l)?GYnWjE_6)7dF>*PXkRi+hdJ$4kK3udL8j&kLT8Ce!YfzHez_ zEGI(Wvb!h9K`8%z#M)bT@v4z6&NEwNPg5gqICOhc7?=g2NcUZ*pC6=5snA%_J9-@1m24 zQs(5LivUqEwz#Q}H@gO_`onp(0xqplvnGVNkpE&a(@_jAth&Q>W6KUS54VK7J0wUA7*}mCVx|MlU{e#o zg6mVu*fh=i;kaIoCOlu8{R(`cVeseJXtqYvH6&ZgZ^CBv+b|6)DnR5Q$aeW66NDaj z=;9GzQcxhJn%$Z!dLV~VS=i9HItn?7KRHSd z-?jCam_j!zxlVp7w{L^5JIzg`tk+D zG}i#aJ{@)iz2daX14gKgON&XcM6RDaPPs!#KTg&yPTjTG0~ zV>nqJ=WSEL?t%k?PBGiRk@GDrV8goem?XdLGD*E7zUda)g^igTppvmR1qoRifyoMN z2wx?|pWa`C9#G)ZV;z!U%vAu6BM<&>W2c~`^NVNzPS7_|Dp40lD zjM{G^*O|E)%n%JAV_M2J(=e92t9qOf97!3s1584D!D)!2Zld%Gg@ikHt>TjksW;6; zC;n=4uXpx2}qa5N1?y)CwYm1}4*TfL*b1kQn2*mXt6m7y1Bdqzu(bm`>EFxm0NcZr6(V zZ85E^pSqr2gpm`uD3y{5=J+WZoOqDS9NgR@n?$*&3$vc$`?d7brgNf2*TWKej4jdK zmfe{MF^)A);o?cUg;XcW97v(8Xm{kwQAP?q0jgBqH^cwDkcnF73s^JRXG7hSyvQS7Zo3os8E=WEu`vf)0Wr=H`Ot_%5=fcq55aaigF!JeNT|fA zi;io82-TR9yT(UXD0u3wI>x8>D^*s^GmHu@T~5`P;R$rkIN7Btg((>>9Jm{3MUEiZ z4Y(5mGmNR{VX_QNK`?ew%#Wya67nnEI*Ho>8V#0YiY{`73{W#lUdBw7!ns|VGhHoQ z0L6!uq66*XTisZHeOKHwG#kY#>Hb3=ysXWOKl|4VGJxbs4xO6CM)NlKfiabK4|N|p zrF@|zJ@?rUb zatKV;+ePZ0gvLrsWc2+FTqtSHYGz;W7rL{VzYm5r$?1a8e9=LpjyP1z_@Fcw|| zZjND$F+L18I#;rT?g(6r>88o4^~|TzRK3jnfkq!SUhf9kqHz%ytqL)M;{tZ;JpYp2@dm!T zX)4y;ApD#`R#~lLY>t=B;`xue(T49-%O&m>!c#wGkcgeQl6UMjj$Fah;?~1fR&hiV zXHmJLlBiC@Kw4AB{G&E5dvX{kV27>}#=ieykepAp>`~f3-7m*M4f>1>cAjTb!k#U1 zWQmTL3QSIy`uuQ3ibo_}ydfUz9azf@CeL1Kfl<&H!|>0DN1!CoiMEI#2q;@lA(riiNx1t*;Apx>Y&Tu-h!!0J^!>IyWn zrN3ChPegrx^ihN~IaK1@!xX0Lg=$s(<`-0%!S6W?@YgJ1A7O&Hl1DhNkcL;#idPi( zTMXIHXy|XKgfWHQiqoMD6ExySx=s;fk_^W}Nu{7g?6TssAIQcNM%PE1pKs9EKu%mM zMn)+Jq9JuN3mBV!+H?z&09=VQcCl5hAhr;DsW5%*_f=9(oc{nro)svbcx z!*kDn?Zy7zzALm=<$dd)4)%vC5gwTWFr@|M^S>>y?nx(matZSSRA`4Rx@ge&BrmFpUIqi?cR`#mcYYGj_M zVNIyCXS>EE;()ABuF8?-{-RBiFZ9gaEHD4qfb*LP0^W(IQ7XgirxE9nh^H%-V#W?)*eLg%(DUsj|#tp&q`RH;t~0sZiQ3B zD|#4?HmV-QsxCu_8j}s;fH+fQc%CjS9<)1kr__-%-{JtB@E`glP<(8_v0ak4%68>F zIxydFi^dg^uTIq?Tl{yjoSJ)ZXnjh-4b^T*Q{B82)a|`J{%iF$M0Z$9-qPE+aiJvl z@=lqfxbcC2k=k5*MNiSANY$8fT;(+tuIhU`M~B#cZ?x@^!lsY`@kXk`5hL*^%Wo}X z!PwBrrg*+R1<{)w)M!|Mc(g_(9VQDLA+sm&dWXH-CN6WoS?zBQ5+M1Dv(?qPwj$$? zUYx7^T>u%>APwR2`_?2*}a|Rx@*=4m<$T4YNtDBXf`yt~gjC2|soAt#dRo>nb z&M(Q+)zKRr+8Y@>-t8?dEzM0$5a}8Jpg2To>yl7oYie0;T}ct3sLk3t*VURu&~#9x zv8=*bSKXPgw#$<5)d7-*rA;KhPpI!!$~OMg;L1Sd1_7(dJO6z&45`XCF~dNruU&+I z9T6_omOa1DfOJxYms#reT<66nGuy%0(T3o7U==tY3w1rqjEc+-LZs>H9Ww47w6Cw$ zZn(f;ck*&eHIWU#i8cR+C!#;3jRJXV2@jW@*byba20A3r3{=^84YfXJ^yw%gEmJPu zPvjOK76tq9*RQf116sA^c+o! zrjm2v@!;{F@mP|6@Y^@1Zk&fGZ(qmt*gJzn)6PDIj>+7!gtO@4)u+48QYP0X)m|$kT z%9?M;7X*5jilob8v6=+!*hRw6NLVho-7Jm>KN8vj+h^jB#q^|*frQT*%52B{o=CX; zXEBYITrR$q(4Q7c_fO4QnoUa{X9&`X0W>aiSat$n8(#F?4XZe7Pk9n_hKR+_Qo47# zl?$08&r^h8*iDZyQ`&OX7S7y`n#s5KG(3d-w5CdLj|R0{Y410cPg1`+jgK5O*C?xf zfZ;d=_0J)#pn?AC;)~fGF2>5=ey?aR+EtD@lyPTlzxsqA7>{=)YtGnOEo%?LfM&B$ ze3oPYgEjoi*nU$ft%U8wQXVP-cCjnvx?QRWQmThMgx(@1q`y{G(=VT?xKSycAuaKS z4+0*5$P|d1nR%mTY)AlzwHbt3aR}*t1gvPwBekrVX=a?RcE;wPv1(Ilp|P{bP?v>M zDa-xE&E;`)Z7X`(4MJD2l>DqetlO0rCY+3bDar}YK#5*l{G!xGkSYyy>6%jlfF8tYHmopjbT z$MZzDt*|4k<_@IR0>P*N062Ia^+QwpE@K3G58x8kNd3VA!9k~o4M`*?r?5Tqiy#p zV^k!Ksrs%Z=)_kWmH`G07o|ac@Rk}P^A*0+F#Ue&HKHXWh=N#k2h8Z6sX(w6&G-$$aq9pxiAGK)ziQn)jGG z7YfmrGkqQ)SzrF{INBrcRop|+jSqJn29t^XQyk~-!w@qRpim}|O^jJ8^a|q?Z*hy< z(c4N#&gzxpSAF;L`hnduZBO_HlV>eTxxzYrpLgfzhvJt^4-J_L^`;IuXnD2W0IB#taMW5(oqMw&<2<*uIf|IAIt(UA$tv`VKK>yV$%#Mc8-( z_P*1b+RHLLoLDtyNY0E&T6-HctVNAUv$-)$-gV)-hCjUnj%QKbV1_^U!p>rcB*cjc z7jAyp5ZqS-29DiMx2yrC@z^|(8fQhUIIUyV?EOW6{JRd~YSXvUHCqgnDZMo@qx2?R zd6B=8mBZz__>=X$?X(mWbWuz6QEwCI!{%r>yHd3zOI< z+^n>QtkGw_xAu@fkb$zr<|(Gj+m+_E)C5bwpkKmL=;(q^n&kzcB=sIo1+1~F7IpJhM8JulNhV+YKjocKj*FvU&Wb*=<(V`ej_ zW%wh@1Yc)`0A_GS>txttAFBL)5z(jd{lIieh-sJkpdQjDZRXjhGx=uPQ`Eh1HvPdq zr(R%l;I+(;(`h2$MK$2y*|%(`nrq_Fxmj|%@}*=~Y!)D)_Bl1KAo)BX)5+{WhubUL zjk32`)yhMypHy9M8*QYSiB|7af%v3&%G);m41l2~rp2_Db7zEn&_N)SRD6?YrM8n& z+Xp(A;az48+8DfApy*^`w?TC8cos!k3Dc2Wpmsg}SWWc@5k?v;tzbY64}WQ1g*`Yw zNAYS~s{*Kefqmi%u_6KJE4hZ;h8C+6qzjeO-WaWO?MD%dB>Q}PNzJqx6dIROo}^J$aXGhv zM*=X|Zv`0cZu+rj6ec5qIzq39JP6b_M&;yvN>o*xRG$pTd1PZ0o%rbxe1Qvo>F2XJ z*kEnNY6b_(Bg_Wg*LW_F;?SB0#Pf2YRC1E$h1v)Q7RJ4P=u1K5rA;e3$&oe%L|7J) zHcfKJ5vwNr=NKg-vk>K=wD8Kt8Xy2f*ZlGNu8WzRUSbmF)#3@CAdgs@)bWU7ckQ{z z!DSiZmlZXAgP_xpRf5J?i`8$tc?Hv(fF2>ycq}IT@6@Rg_T@_s+f?o~ep6TF2REj( zD}lPst|b5jN*M~p9>u(5om#`YMStC@TJrg7t{>Cfhw$QDRP@$AU-xextXczzPb3ai zPoaXdaZ8+>s2~3}DM=Raa^c~R$qw$4n6)FsBaAxFXENmb zMA7AT!#6y|SquSh&P$CSe<@azJh@k&1+Bnr@} z#hdKuq{{$P7vPU|i`8zL{WzZe^>l`j^tdRkn#Xt2ATN`irGnyil?hhZwmd6spyx-3 znU8#1{(EAk{lSP=SM`D$y?6MKfT@i6fRQkW>zxO67rNuz8hD|T6ly6HfWF)|Vxf40 zNp}stSFcEYbK8cZqId$REPW&bR_XUqb&Z%gt9qt_D!=2(gVztRN=#hvod%;Tb58m@ z_h6MpttOM=eXovsSVQ^P=3^BweX5(C^FpZWkeW<(I_X{N5S9Gmr5-guUQh(i^6+v& z11$}6)KdFz#AdN&0#3dP4JR6YroAm=g0N_yh3wqO42r-dO1A-WOZ-brECNCm@KHOV zRcG5vP*%5XG4bclWT%(s#*J0nLMOPn*W6-=xCP>espL27U~Di@+MO4S4JH~lwnMx^ zI6mW)w!B&#bT7dXt+O0grwg+HB)k#?i|E&TABzuAelb5f_f`x)c^9HbKO`TyUupzX z1;8c=MCHQKn$iHC_#`(XFOl09!}E}$<~hi#+{nFPMS~#=jx-mtAw}!w{)QJKc!na1 zGiHyAqet6!)YF@ioLuIv*zw1f-gj{7`Cl$Wfgiz~;e@67I3O3>8yy3H1v*Z(b2WgfLrzU6p@~M^ z5n*b2NB9f1ywGUGURCEwm>T$yStdvxT7lmVIu3ylY;s&3`Fvx$5#Z47l)SRG{{SKw zx#YnQ2vtiJ!i8<2@zhV{g141UZG*St)11Rr!zBqMC}o3(kS`kN9T{s52SteRL!&e^ zOzi7~t;GST?|q!eDvtDE9|Q`FQ6i(U1@TC+<*&XqS@!gy*<$b&_yx^+i`{O+v;H~q zpEmt7ZLeq8MZJB^Oy_4$cGb8=bP}eyA9Iy1=118bKy4ZF!5N$ODOJiuPZf{G;reju zTt?7Y|pNcp^)hdlqa-dCD;>rDlblDQp&V=#aTJ96(%Ux3JL9e4-y(#g#k0po>m{u{Vi zzl5FC**kif`s1D?@sH#W7=CaF4V69aA>Mp6l3))i6C!@-3#T$65GksJpIA>b-y2kA z5L1RpRn)i^lw9M4DQ(+jDYy7Tyu|N%K1jBjwpMx}v!)}VUwig1^_|9oS9N$C>)K%uv!Np>cNwSAl$pii`eZ`?wa`9I86+bRN=* zj>O95v7>Aoq32?-_zB-J(=6p`2B|7tCtpjet7kp6N@f;t7P}bRYmtx?ZS@y@4O@vj>XeBf9j+h6^yVY`bRr!15@o zvxl{fwR7sG2ne4ybmxfw=_TH+wxn8mVe!qDU0K)BccU_HKfQ7)yG`xikBtrXO ztTYe}4rqWDS6wtrjd$(@@aRX9))>oTnKSkoB=mu!fu<_W1xCWsFYRgaj&w{=XOF;4 z=CjC12m3cdk7+?T1S2p*7pq?Smn9&mqfJuQqE13D>MvBGPcXS$H*$Vn{zYm3Wl%axEJC*>~t+YuQjgtG*t-I`gCP@Ib#*mkyADy_&n zo7Cln+ONe$IZSaLAWBso+f-E9l@)Kd3U-m$ zZ8r&fu@-P~UUm^O>9m;*B4O~5z>;idj%=>1UbL4O(_WZX=PGcLAbHaTOBCEbEUjRT z$+eQyoO4P-u{vINe=A@6Tk2o02=k*QRkOTVL19ik+{B$MfQN0efRQb23d$E1?><+A?*()nBrNrC<-@ zAj?B)V4}5b4-KM*`HHQxdJnGiU*%V4)h-^~%|0L8%>gJlfz>M{f%R)po4}AcH2=yi zc(=-JQb^4mAUed}QQ5$IF7knEgTwsDX?cyD$|EXkt4*s%A*WKdqqkc1fqwS=kFIb_ zPpQuuhtucxy^6>{Qai(kr3vJtN@r2h&C0l4?BMHo)r=%Sy&)+0;P=Zxq|+L%^CH`$l*Anv+zFnbb4Tgj%(!=~_|~ zt>ye7+)T#v9A+0g`(?ha!mN0m= zl#I+fp#F4<=-KRwVdh?2*{?Y{#asgX*w1{r88=Hy_wJF#X_M{DH9RT9M*B^{y2yj6 zegIc<1e+M<+RS4~;t)4+R+a$ggK#$B{M`$G6sW2yIBD3acHRVDEq(p*3N=rk0-1D4 ztb<7#?wr6nsZE<6%X!+wd6n5;hrly1Q1chZ*o`QXaZszTt3QUtE7k<2?6&y3&$QS z_(qSpoH1UYb3qYeWa72Z5Iu1CAZFhYrlZrg`w6IOw3|2}+P6=qbx@yU(26V98+=9v zkj;r*jvAXQ{$?SluNJ!`#_OOE8A&Gx{c^80kAS1ieVZW!WCo+GN;>>;`egMb%pOLB zh#$n#>19;H6oNQ8U6P*PUv|i3Ah|WB5T9r3@8x7zd^sp9QfCs z&xT66rOL@C|2P%)83_Z83eE>G9uUA(FM{&~nJ2k5@ntamDr3A5@@2c z%_cS=>F+;FMFDd-r@@tm25)kxe59NWkJPeL8M6&4(m%VrP&POL-$=Acn2m=s|278>CW=I-tuqM{^gp0g{ zSj+>2lg4b_r~xZz_gMtSceVj$+4b$qrjrlgqU|6;!o@I>$BqZ_f*95_Q4Mt;js7KF zjSd>OMyle`1TFAw9){$)-Fl;cTeXZLfGs674-!jFhGJp>_0s>*vi#rBu??k$SL$=mJldxeflv%LHx^D{G=(y-iVl{PGl5*@;GEAk* z!lKtKi%o(z5CTzy0D8oa7MaZltAdB+_6vYFoJgXNL{L?F*zl(_nVY^#PlQBCaabFK zoK9nm=P)!_9dzBCts7)?6&E0{-Yo~fB47@4PwR2G1>rG8{SXv1m&QPO&GyHQv)9h8S^_;1|vPo6Hypp4Lbth6j-3l zt;jRv=3=vbl#a2Y@AbMr(bnxx*C{N{eB0x$@3CDyrzmza9%l&IKL19;?V+nid#d$M z#9dAL{ho=YmxpK}3mtT4^c0pg^CHjyI3l@!ge{n(?C`AL#k}$;m4rV?^SU;!Z5g?x zb8ep`L@Zz`cl;)x4VV@G0#(5NAHDh~mYhOM|J?EmHXtCvL?mv!|5Kz;^&f<`Byciy zPoDV8gs8U`UXs+rR03I41er7yOjZL{!!)6jv>-9f(F|m;$+axsqH0;I(e*;O3a63H zUrEfmV!7F>YU|R<`o;H6tI4YSr|o7+93trZJa+SCTX&jo;)nJnW~S$(h$74)zIjfD ztWzr;!V(+MwKyinUE_$@b6=RE4|{X7q|xqqZ)_b`9Zsh1ANopVqG zVwWO@$8GIqj&IfvcT{PI0A){;&G<$lQ_-cT_*SX$^nq{vWssi?etxpXt}r5gMN?@E!{AUjrDqk z&k_KTXL)x$I(92_-`wAh9KAs?>`c9Qyy{`K{l;w7C-<8l$hp5Sd1I-+zP66)$VI1uaQ(G!J#I}ZfVOK0%#WCkdnj2v=Z775|cz2&C3g})<= zJ;==4EWOpH^i0OeJOriCpAaDs+}$SX`9%PF5=MSMs0ZiNc)ntJ^3!DSmOQL$PJ&?_<1*d3p<)^%Op|xcaTh5X6JG+_{@9(Gd5#cj=H=ZA3%Z z?<~B1$cj62W~FCcwbWQD6!-Kf>J}mrFNm-( zse_V%bLD7Agf02F68Pg^9jB0;Xx#@0ndH)7UD{m2!;bppo@yOH)X?3r5jCO>y7yt)=4GgV{A#c$2=kh`1oX6pHKN_IL#GIoqLj|`K21L9Zv3cSc8CM0Vl*zYRUDuCU6jd-0QXP|V_OyVg z`^4OqtjxA@hVw{eKYTmm9A;Dz`|k;}(y11Rf_u0uU<5OjWTBqmF0=d&fsDW@(|;r| zn9J%ihz%Yr3MRwscPG;kVJ8{@P>iWLH~5^FE)y_^U7Nm-^qFFE-cld{gm8t43*_Pr zY5?r=m>TXF4syVa?0+4p1*#ZKoTVS!6BW-GIJiaupJvl`aso}YJt)XpWX2Jk#mRB0=ZB(4s4c$e)@^q!1M zV?@h}j<<+x8vu(l0tu?GQ^Dm6pdg87t0NrHpff;Gp)lpSRbV|E{4O}Ip4>K8&6*Zi zexpFF;XuA%UkNLUA=5(!^sj;ipGNy@c%nt%9k?H)D=se=ff2C7-f9TEEt+J zl?Xv;?f6@l+Gtym7w!je#&{15lj(|RWe3`vszo1}y6)3pWKvm(7>%f1$Gl`o(!=dS z?q{|^ih(Dujl{x?lbvG=8by-?OT8D|UdIc!ft9HE6-d+tnRSX1t=zi2ZXFGq?d_bj?eX zT$;&3?q!gVPoUBSaXG(*;ATwjpxkL&S>~DzZe0o#T7m`m_m-lPA`1=0Xc%?fu3mC1 zj)Kv62`M63n?}wY!>;{jrU;C17Cbnygrv#^9Hr}wZmj{Zvi|g7GHvE} z3X||glVCa^c%D|;xlXh-EQ=N6Cy-iXqe&y3%u+8Inn9JKFEZ}Vt#sG;U@}{sZUJ_> zgaGSN^*vq4eqI}bZ@dTWE3v%ObnXIzPc{~_F_zzY7W9!T5Wg@K_8aX->ttv2p#|b6 z24H_n@cKfT5M!JWEPNdc@e}?7tH&b7^vdw59ux;KW?+A{zhpU00dvy}*7O%z?_g&+74xFv64@*9Wz2+xPc6f8$T2oyF_|&RXY~F|^BiVyT(iFwc+Hvr zB-mUhi24{n`iT*wTs`=OVI|!J`BhWc$?mY*w&a*}4fox0dJPwUtmucL;*?@YiOP&- z=4u28PkmMNo7nyN1JXlBPCu9CO{ewmtD3xWsYJCsBpF;I`4Ryn|B%c}X4aCBVK@}4_G92Y z@$m6k78h)h{;0taMrZ8b5*Af45JpfU6UG37#^l9r*(Ejx#L^?2bfTc)F&i#e^>F;A zyY-+#JX~){2%r-#7U#&hnw5QMbZJmnGk1fOZ z4q2AV-(V2=`&i#ueWCzYOAYXq)jt4%IReRCrmqJl{GsEwf;vca@{mtNL&@iQBe^6z z>+&nd)A@V5S7&!p@`%7DZmZKl!CGy7%3$Z))ds8Z&85aMsvV|#Y?_}P?H|90DF<;UQs~(l#i-pZBjIer zLuO1t4E1BE`(iZLovv8ZdWa)uR8+%jiMSC$^4cL=!h< zyeTLuMG~h_&&)t;Gv@J11(*>+t_eFVG{%KN9n%VKq1<|>BsPu;WnTH4wSJ7hQv&bD zlm9B@Oxkx%uD`x3CYtgKI91KFQ5()O*cpzC=>N!fzw(Jw`7jUF@EGK@ojdD+QOXdl z^j>qukXd2(M(mPb;12?%vz;RNq%Whq|Aw1#*~@SCwUTvGAW03gw$xIWOqAoU02!AR z#x`p{*cQid^pIlswz&mi;(!p>3}wXFUqE_~d+#J0_&Rze`#Mu};kWHrE0(yZyHg^M zIBUVn6xs7UdE~BaqQVeAC*!#mxw4-6j&z2n4Cock2y0p2Z;JqM%erasq2S16fmu>v zigkRIG>?77n88NVFkP)O+F-t~VJjq><&-HMv`;>bGX>}Gr>J?hk>vdsHciFEPvwyZ zhar{uJ=FP;u7}ZKV&USAx9hov5Rp}ztFmL?cla=`pddTAxhn+^uIoTE8f>~Zk4;6H z$9$!$-oi)MAIShZQku?oJ_m(c6wuo?@V zj$O|VE}6Nev$K_zDg12Q|5bqrO2L-`qFSjIPNc;vNaDeSg$dUqyqZY-QG!eD15}3S z{QDT8OIO+-n#FL3ILu|`zhD5c_jgW7B9>(>bq4c19y@tT7>xhsN{iV|)$sF?36OI=} z%!WFT6jA2o0=~f|H?UwR)`O8FG#q1+MTso+zn{DA|88kvyS*v zW;8XKgo6iE9!b$|e%En82_sbrdy_|(c+~=0v1vJ|m(?_J3N^H)f1M$wI?RE*BjZ5? z-?7Ga%S!aFi>B^Lc|rHf7Fj-`b+(;aRyrDe8%=&v`%W2U5(w(!i`zYMg<2X_P1H?Z z=@kdQNqLVc?{CYrI}>o>P4JRscPUtk9YM;`*I?&S9o6?@lIsW0un8+q(9CkdRlEQc zjjKvT-FGB{`BxfD4Dd;_6fd0Uo%IW1lTUMUmEjjArw3RooP$2a8bU4Mn|X>X==DO% zT!Q5Jl=i!wAICv=U2&_58Z5a=<|Vcm&EkWhb`vp^2y*=at3A>)EvNR zNm+iV6^W_YCpRC-xm+sP8^KU;cEo4@8r9A9;PVB2+}yp_dME!=z0ktw4DPvIn;#2Fykow<3tk}sLT92l_SOugQL>}{vQPp3`wM3)EEC_wE-S^s1 zOQT}KIR5vJ{zct3uY^@rubbX{u8d&iIUyZd27Lo0!ovL|R!N@vYy&ad_y>_DkXe*) z0;MeZZ;VM#sKV&{q!RD|t=>(*{ddJ~xcY*o!i`rue1*I5SF}b04vk$<+Ka)G9OK=T z3x_XcjAJCT8xJf`3Ofx6cbylLuXdXRP~EQSJ3Oo#R^~OAmzY=pg%XfQzZ-`q3Z;dH zb67VFHN5HSQDL-^u`bqqa3LL?vsyS=4+k_47fWc7deocmyFZ?|9vBl~?OEr@qUqx_ zvsreis?q1jrEZOyHR<`IZV47KGakE=+er{=7lOpKncEyBMU+5nNB6V~wDk+Ke_wB1 z)O{ZP-GiFaYY$^)4gqa_Mvm%e^RIelg^!SO`6x-1W=Z>xffRCsE2dYHpUKFzeLxgg zyXz4ooO!bve!f?6bGZm02-}B&Za@Y!P|uOQ7Tb0;Gdo!=ZoScT=d|J1BL5jA0Abx5 z3G612W#_kboM(ExZ9@N~_~>gLbnGq>*(5g^$UOpc7Y zHD`~JEq_gV3Ri4FyN%3?=GgKbHB>bO^`95H z%`INyYLsM~4VR(-9TGo^d(PZuunSxt;sBV#<{OfNWikf-6{N7mIWwAk^s`~r{c^8; zzjCU=xpL%{eH!?AaT*|7r)`-xe)GNn!}ZRglfTtm+SQJC-E%1>1@m79b|9Els(D65 zURqY`QT;)=kQ}Itz-1kXW8To2UJ#oe^r#9DXtd(bI`Ei)#eGlmY`ESRtuO#Q^D+D3 zq~Bp!B+^o790C8I?h7DO#VgNVAELz*-;}fCnMr{0pLf3X+-U}YzA*bkxb#mx?=C88=b0*6V#Y7XrT7jdKl5*N7GW7c|2Aj@ujpLg*jFFyEx+0UEI^8CrN{$*U#+pYrxMsH;_Oeb#nJEO)INdRKuD z*Hsns|LW^Xz@hry{}_qv#@5&wvTs=`hU~itC2Q8kk~Ly1-!ayTL}QJHY*Tgy*|Uc< zLS^5#QG_f}%5P{@&;Ng)=RWt&dq1CZ&imeT&pdPIoX@*`gSDN$b6s|Ky2v>3+MTi; zD}iS3!Q`^|@aV{VSQi|C8;o$#_k7)8+SopNC%}i#R9zEeJmaQ`Dag+rSh;a0y;4lj zkyjlZKoA}9KBn99?Lq+6+*M4_&am3fr4v({XE-G- z&_=l$#QDfTljU4=1 zA>=mWQc6&<&ZVxNZ#5*5XjMB2BX?L=4Pmrt;Ls~+{c`*!My~^!03heYY)MeJh>fAO;h;Kn*XaS1b4LD1h>Z!}OgOSm*4TA9Yyo&GSp$ zzs9GYg`sN}1C18!STU$%x;q}rLtgka%kaU6K^+i=$P!Qjh**wEsz_cOlxTOgQXG`v z+wNy6@MKv|SY?M)7{9p?<;+|m?{LY0Lf%!O_mxA2wa@K&DMf?l5>|Jh+qD9_`rEy_6l~Lmy(`D zl(}f|eH>r*j;QMfM+2YqV8)9zAl6IB+b%*=EY%~x z2fY-w;p!ED$rt|W-7gpH7btnf`P1!-bu_3;&2Un-I<^gBxgX^&v6mUGp7pL*RhRn$ z??~gy>e^4Td7glIeJ;wW*LGz5_I2+t#B1p@ai^DyE_s*cXrx}l=e5GmSn4OnsUJ(=xT$*70nBhO}ldBg9u4W^@8kI63rV+162$=<*BfX@Ry+- zz16Bk|FGHh@$KHM%KF$UZ;CB%R;Zl=L+7|CF*}Bd|MYTDGhNBPRdVb6Da5304cq`|C(#X%{#lL*%^^CpvUa* zFDQ-;E;vyz=aW@{ML~j}%v`oG5oX$Z%V6z}&D?OV>i6|07ovzOoR_npSsbps&&*pe zSNMp%Q~M35CoSup{>81(d|$Jv`NVBUBy%R}MW{(u2f6^Dq8no_zg?ZHI6L;m>`}+V zkzTh|LfUbmr*CH4gcm%g0HzE;*MNAnqJ56V%js7)zJ32Y6JSshGTDrYu&mOMjPQ@AG$O&uctD9EvRB1<1cdk7WuRji z$y8G|B#M5;RCL+Xyb0`)lF$LVPJc?X6@M~GTT`2e$XZ_HzP-sg*QCPt?n<9WDc)oyg6Z44cmH8@ZHc2jQj(}l8LGG6(o zLa^@ck$~Jcyj($jVwU{1-hrCyZMv;{K96NCWjoSysRO@>>JKi9Ae(&_QbNRGuMHW* zoNH?*T`phRFnl7*#x-l=%qE@)7-F_1>F%#qeRu|GA zAzr@|HGUMbLp@#VvRGFPxsNMl22~B^In~xhm3M%JKLyj9-W>O1e(L|S%f~~!ccek- zZRX_!hK6L!f_buGjZLk%Pq3f_!2`5ui*Xmzr-`}g`e)rOo zCV%nW6Dq&8I?7p1(I$Xz+Z#ZxpLfd(ZE;LJ0=nSX*2H#PrG$J|TJe%shE1dJ*JC{G z$4947cHd;laB@?HVMacZ{gKnFu`fhpP*cxS0Gwz#m3=ZfjHe$a?&mr5t9S6OpPL!AdT8W=rOZ61+h+5 zMXfjz_}vF*f|WX;ahhkFtmCFjC_5EpnH?B8K85J{2Dgc6fn^dExi)FSIO-Ri-u{@Q z^=l2|(<|xl(GvhbAtL}FKv<5K2O)uYcx?M!{$gA*H1o@`0; z50YA~kAQhlO}jxAn=+n8txBYOt7~E`a@eXqE!9G@2%QTWJ3eh zI=-mx01A9!&fF8e5+Qgw-~o)^f4iBM1K}8UEoEBuG{>x0WEZI;wAhB~!s*>s@|)8T z%Fh=`I9mltIG;Pq?wlaWXyRA(H&S`A;NX&ZzQ)UwYj{)&Iy6bhv@(e>omN+o!|x@UathblT972FLGRQGtbM^y+ROA@lwqn2s6B}JStK8M%B_#Ll5CL zE>Zt6zaYvuY#g+(s7Z{Z^N3p-8iFYcKPbeh@C@c1wlVdVic~=CgUt6e=UZPTEx+Oc4an6_Ceq1rz_^M zxJnPd4*gJ!jdPXlwI##Z6zBN#v@JwM!*D6y)%**ukJ^jo4C=BQC1|l%l0b^) zHC7szR|WNA@oz(9TWTZgdMc8J^URKyjO$m8ChC6UR=vGO$^< zmsOg`h_VJhwkCAtdP(BCGdLrD-OPKx+CA_MWZVfOvId&z+vnGHu<{Sl8wQV`tNXAQ zci%E9HAdVm+j%4>BkBFyA+eW;a$nsx!A!GR2e<5dltwL{TznOZ50y@AXaueGUSw*_ zHwx^qqvA;b~fQ0AWy~W7Y&mN)`)03 zUwGz<)9sst7x@>cfL zmL0o}R<)eE&Q!dl(W&yy{=NRr$J#Fnoi#TbOw5HJ=jmK&fQ)sR1c9&GI$zDj`Ji)i zXHxN|eRnw+8}P=G&9yEkFCx}uf*yv)1ibUlP8z%vL_BHYCG2jxE}CT0(T5qP7ixUT zHfd{zN=|w33V&Re@zkZD!RDconZTaB370t|29ojkwcxyOnK4s<{kRk7?Nk&h%N6n} zT|+FLm^wE(XZd6NqwZwPz)YGHi;|%AT_O$|5zIBu)VFuej-BR@Xf;KY@*|4v(u3D2 znD%t{blOYc+pIB$$*iL9o4`znv^#ZPqr(o~qoU*86JsBx^_kW!7@xJSUfM%S@kP^t z5hm;WduAP1P4*ZO#_N82svYMq?NPvZuj3^lSwcL4lz}|ux|54Jnu-|AT}f5WyC==A z*5OWp9C17)H=hKXS&Smydl_XL_=(@ZH-$TX@N#bfd6bY&hjw=-dEQ>tH+$>%_{(L@ zT?@!*sCd%rV=j0*^y};U9WyHf7Z`WWl%9Hq)-GRI5H87&blSD*vb@X4%z_b240>&9 zVn1=O1{6vkAX|d1%M5*b<*ZtF1}f*(6Lt+89cHe9B5Ee2jsez(P)b0T>wv5=32vRe zdB?J}w>6fRSc4=L!r!}Ss|YDP+8{A`K6p~Ws=R8zK3Y7fpT7J_C)yh%r%$To^Ga5o zPsXH?Vi&hyerixHc#^M&P7kJcv#sUEnD$zZlU~Pd2KuHm`8|^;xGFlx)AQJ?($UWTiZsTED-w5;1Vwzdna%|k*?E*<{T^Zc=->jUBcdO^u6sRP zr?)KXyPbubD0hy7%|w-zYF1yXnSF4!?%J;O<@BKN>vyKO*|<^cnCr^K!6jT2qj;Jv zou1ajxzE%ywGU<*$&>A6=HJRN#K@$ynJ+(=V{5An_fmLNh&q*WK#W zfn8^terJ5L;|7tWJ*lo;N2)QO<#dLNMEdmPJUlKTQ|jP~<7+i-wh6y9F(+l1Hbs$bGg7JgGx-?}fUd ztM+B%iytBq$}`PGBZ|-t;erp-oGi8Mg^^eex<{jSXExx74y0`kT*4E3MopiMC-z>9 z65?a&waDci+U5K%YC`|*#}MEe!BIXn0t^Iq&GLVvGQS;E29K@-JhB?I?Ce_ zrB_fQcUUOfmvG3}S{da0I#YMddrm=~b401UoG`&vedN$|y3m5lN%)Y8&PkGGCNO;m z$8s)~{7J(-1RIlp9G9|B!1>zag*UJ=1hE(*p*bB^5d)^kJ0MkmG`={7AX;1z5tq-N z6VBQ1Za@oztS|3M7l2ays#DH@&TI^}&lK^OB3U|5T!$JF1r?B17n50<9xH}SF;_Qz zv6>=vVq{R)$yH{Azj>gfJ0Q*C`5cp00hjReYwrD4Du5wf5EpWKw7-Jz{ab2|S zyX?JkANh<_(H1jOf4 zpqvM}i5TL=z^I%-0m4Zp7_~5X^5BFK#V`ct{&UMg#!#SACxyS4J2FWP+@nCfo0RF zC9j`K5A>YCyD!|Q5an~W^Nl-yGU-Jb)`e{MO*K<-0$K`cn*?;=Ts zpYeVr{Hpb(Afy5Q$sinaknX&PBy>D0s(AL#=&re~fpiJ=tP*6)G>%Z(1qc+af9il@ zD0ImQjq;}h02Gc8e1s3{$W3AUhjb)A@e$JS=|j@14Ay^0zca!9UDKcpsw`I!r8m#^ zN5uY4&H1yM9OT$p0{q-RSzVb#jfNX;r8!e>5*L=^ zAJXriH1$AD!U0peg_$`V&t$<{)Xjeo(jw;gTGN0PSxc8t(CuvGe{PW5%JtAS!N{5vbw! z6HL$;JjM98`-ie&sC@!(Fz^=;N)7(UrQf1N008%q_Ps#-B8r2KqpZgcZhh7W1h{zr z#|4gGqaD#G1UQH~G$Z)9ewpnE=7|Rcv-mF)-8nEyY>XV3_3#jFFvj>tuzs)c0swf9 zG$sap2+ueI|GjMC@7NOM9Ku(}{v1+|%pyNhdPm-m(n!X@QJ{{sQ)I&fn`14E1ZD*;r;J- wl7G9?+;<57I`OAFM_$Doafj#45BR~G8CnJsg1-7ew&F7Y2t5FxI(hKve{&7NHUIzs delta 37942 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/dev/null 2>&1 +then + die "xargs is not available" +fi + # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. diff --git a/gradlew.bat b/gradlew.bat index 107acd3..6689b85 100755 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,89 +1,92 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega From 37aa1f276241a09d7dd5a3aeb6b23d92bcb01b49 Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Sat, 20 May 2023 21:18:37 +0100 Subject: [PATCH 40/43] Update docker image for build --- .github/workflows/build.yml | 2 +- .github/workflows/release.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 18f4e65..e79124e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -7,7 +7,7 @@ jobs: java: [17-jdk] runs-on: ubuntu-22.04 container: - image: openjdk:${{ matrix.java }} + image: eclipse-temurin:${{ matrix.java }} options: --user root steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0aa4e24..0c47192 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -4,7 +4,7 @@ jobs: build: runs-on: ubuntu-22.04 container: - image: openjdk:17-jdk + image: eclipse-temurin:17-jdk options: --user root steps: - uses: actions/checkout@v3 From f35cb7338fb1d057b16f8b96a10148e706c40257 Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Sat, 20 May 2023 21:22:17 +0100 Subject: [PATCH 41/43] Dont use gradle toolchains. --- build.gradle | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 81c1cb9..846ed59 100644 --- a/build.gradle +++ b/build.gradle @@ -34,9 +34,9 @@ dependencies { java { withSourcesJar() - toolchain { - languageVersion = JavaLanguageVersion.of(17) - } + + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 } tasks.withType(JavaCompile) { From 6c09b18769a0bb59e4c1332352f43d08d39e32e0 Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Wed, 27 Mar 2024 16:57:10 +0000 Subject: [PATCH 42/43] Update ASM --- build.gradle | 12 ++++++------ src/main/java/net/fabricmc/mappingpoet/Main.java | 2 +- .../signature/PoetClassMethodSignatureVisitor.java | 2 +- .../signature/PoetTypeSignatureWriter.java | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/build.gradle b/build.gradle index 846ed59..317a831 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ plugins { } group 'net.fabricmc' -version '0.4.0' +version '0.4.1' def ENV = System.getenv() version = version + (ENV.GITHUB_ACTIONS ? "" : "+local") @@ -22,11 +22,11 @@ dependencies { implementation 'net.fabricmc:javapoet:0.1.0' implementation 'net.fabricmc:mapping-io:0.4.0' - implementation 'org.ow2.asm:asm:9.2' - implementation 'org.ow2.asm:asm-analysis:9.2' - implementation 'org.ow2.asm:asm-commons:9.2' - implementation 'org.ow2.asm:asm-tree:9.2' - implementation 'org.ow2.asm:asm-util:9.2' + implementation 'org.ow2.asm:asm:9.7' + implementation 'org.ow2.asm:asm-analysis:9.7' + implementation 'org.ow2.asm:asm-commons:9.7' + implementation 'org.ow2.asm:asm-tree:9.7' + implementation 'org.ow2.asm:asm-util:9.7' testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.1' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.1' diff --git a/src/main/java/net/fabricmc/mappingpoet/Main.java b/src/main/java/net/fabricmc/mappingpoet/Main.java index 83c614b..62c9e12 100644 --- a/src/main/java/net/fabricmc/mappingpoet/Main.java +++ b/src/main/java/net/fabricmc/mappingpoet/Main.java @@ -194,7 +194,7 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IO try (InputStream is = jarFile.getInputStream(entry)) { ClassReader reader = new ClassReader(is); - reader.accept(new ClassVisitor(Opcodes.ASM8) { + reader.accept(new ClassVisitor(Opcodes.ASM9) { @Override public void visitInnerClass(String name, String outerName, String simpleName, int access) { instanceInnerClasses.put(name, new Environment.NestedClassInfo(outerName, !Modifier.isStatic(access), simpleName)); diff --git a/src/main/java/net/fabricmc/mappingpoet/signature/PoetClassMethodSignatureVisitor.java b/src/main/java/net/fabricmc/mappingpoet/signature/PoetClassMethodSignatureVisitor.java index eec5be7..a65c6ae 100644 --- a/src/main/java/net/fabricmc/mappingpoet/signature/PoetClassMethodSignatureVisitor.java +++ b/src/main/java/net/fabricmc/mappingpoet/signature/PoetClassMethodSignatureVisitor.java @@ -46,7 +46,7 @@ public final class PoetClassMethodSignatureVisitor extends SignatureVisitor { TypeName returnType; public PoetClassMethodSignatureVisitor(TypeAnnotationMapping mapping, ClassStaticContext context, boolean forClass) { - super(Opcodes.ASM8); + super(Opcodes.ASM9); this.mapping = mapping; this.context = context; this.forClass = forClass; diff --git a/src/main/java/net/fabricmc/mappingpoet/signature/PoetTypeSignatureWriter.java b/src/main/java/net/fabricmc/mappingpoet/signature/PoetTypeSignatureWriter.java index ab8bff2..c4e920b 100644 --- a/src/main/java/net/fabricmc/mappingpoet/signature/PoetTypeSignatureWriter.java +++ b/src/main/java/net/fabricmc/mappingpoet/signature/PoetTypeSignatureWriter.java @@ -54,7 +54,7 @@ public final class PoetTypeSignatureWriter extends SignatureVisitor { private PoetTypeSignatureWriter activeTypeArgument; public PoetTypeSignatureWriter(TypeAnnotationBank storage, ClassStaticContext context) { - super(Opcodes.ASM8); + super(Opcodes.ASM9); this.storage = storage; this.context = context; } From eef318f1f076c612170ad9d643ceebdf7fa2f043 Mon Sep 17 00:00:00 2001 From: Player Date: Wed, 15 May 2024 13:40:29 -0400 Subject: [PATCH 43/43] Improve debug output, update javapoet (#32) * Update gradle * Fix test eclipse java compiler compatbility * Always dump class name on errors, remove some streams, reformat * Bump javapoet * Update javapoet --- build.gradle | 5 +- gradle/wrapper/gradle-wrapper.properties | 2 +- .../fabricmc/mappingpoet/ClassBuilder.java | 71 ++++++++++++------- .../java/net/fabricmc/mappingpoet/Main.java | 53 +++++++------- .../net/fabricmc/mappingpoet/TestAnno.java | 2 +- .../net/fabricmc/mappingpoet/TestOuter.java | 2 +- 6 files changed, 80 insertions(+), 55 deletions(-) diff --git a/build.gradle b/build.gradle index 317a831..f7b07d1 100644 --- a/build.gradle +++ b/build.gradle @@ -1,11 +1,12 @@ plugins { id 'java' + id 'eclipse' id 'maven-publish' id 'com.diffplug.spotless' version '5.8.2' } group 'net.fabricmc' -version '0.4.1' +version '0.4.2' def ENV = System.getenv() version = version + (ENV.GITHUB_ACTIONS ? "" : "+local") @@ -19,7 +20,7 @@ repositories { } dependencies { - implementation 'net.fabricmc:javapoet:0.1.0' + implementation 'net.fabricmc:javapoet:0.1.1' implementation 'net.fabricmc:mapping-io:0.4.0' implementation 'org.ow2.asm:asm:9.7' diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 37aef8d..20db9ad 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java b/src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java index 0aa9bf3..3677191 100644 --- a/src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java +++ b/src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java @@ -15,16 +15,17 @@ */ package net.fabricmc.mappingpoet; +import static net.fabricmc.mappingpoet.FieldBuilder.parseAnnotation; + +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.List; + import com.squareup.javapoet.AnnotationSpec; import com.squareup.javapoet.ClassName; import com.squareup.javapoet.ParameterSpec; import com.squareup.javapoet.TypeSpec; import com.squareup.javapoet.TypeVariableName; -import net.fabricmc.mappingpoet.signature.AnnotationAwareDescriptors; -import net.fabricmc.mappingpoet.signature.AnnotationAwareSignatures; -import net.fabricmc.mappingpoet.signature.ClassSignature; -import net.fabricmc.mappingpoet.signature.TypeAnnotationMapping; -import net.fabricmc.mappingpoet.signature.TypeAnnotationStorage; import org.objectweb.asm.Handle; import org.objectweb.asm.Opcodes; import org.objectweb.asm.TypeReference; @@ -36,11 +37,11 @@ import org.objectweb.asm.tree.InvokeDynamicInsnNode; import org.objectweb.asm.tree.MethodNode; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.List; - -import static net.fabricmc.mappingpoet.FieldBuilder.parseAnnotation; +import net.fabricmc.mappingpoet.signature.AnnotationAwareDescriptors; +import net.fabricmc.mappingpoet.signature.AnnotationAwareSignatures; +import net.fabricmc.mappingpoet.signature.ClassSignature; +import net.fabricmc.mappingpoet.signature.TypeAnnotationMapping; +import net.fabricmc.mappingpoet.signature.TypeAnnotationStorage; public class ClassBuilder { static final Handle OBJ_MTH_BOOTSTRAP = new Handle( @@ -48,8 +49,7 @@ public class ClassBuilder { "java/lang/runtime/ObjectMethods", "bootstrap", "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/TypeDescriptor;Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;", - false - ); + false); private final MappingsStore mappings; private final ClassNode classNode; @@ -131,14 +131,17 @@ public void addMembers() { } private ClassSignature setupSignature() { - return classNode.signature == null ? - AnnotationAwareDescriptors.parse(classNode.superName, classNode.interfaces, typeAnnotations, environment) : - AnnotationAwareSignatures.parseClassSignature(classNode.signature, typeAnnotations, environment); + if (classNode.signature == null) { + return AnnotationAwareDescriptors.parse(classNode.superName, classNode.interfaces, typeAnnotations, environment); + } else { + return AnnotationAwareSignatures.parseClassSignature(classNode.signature, typeAnnotations, environment); + } } private TypeSpec.Builder setupBuilder() { TypeSpec.Builder builder; ClassName name = parseInternalName(classNode.name); // no type anno here + if (Modifier.isInterface(classNode.access)) { if (classNode.interfaces.size() == 1 && classNode.interfaces.get(0).equals("java/lang/annotation/Annotation")) { builder = TypeSpec.annotationBuilder(name); @@ -172,18 +175,19 @@ private TypeSpec.Builder setupBuilder() { return builder .addModifiers(new ModifierBuilder(classNode.access) .checkUnseal(classNode, environment) - .getModifiers(ModifierBuilder.getType(enumClass, recordClass)) - ); + .getModifiers(ModifierBuilder.getType(enumClass, recordClass))); } private void addInterfaces() { if (annotationClass) { return; } + if (signature != null) { builder.addSuperinterfaces(signature.superinterfaces()); return; } + if (classNode.interfaces.isEmpty()) return; for (String iFace : classNode.interfaces) { @@ -201,6 +205,7 @@ private void addDirectAnnotations(List regularAnnotations) { if (regularAnnotations == null) { return; } + for (AnnotationNode annotation : regularAnnotations) { builder.addAnnotation(parseAnnotation(annotation)); } @@ -208,27 +213,33 @@ private void addDirectAnnotations(List regularAnnotations) { private void addMethods() { if (classNode.methods == null) return; - methodsLoop: - for (MethodNode method : classNode.methods) { + + methodsLoop: for (MethodNode method : classNode.methods) { if ((method.access & Opcodes.ACC_SYNTHETIC) != 0 || (method.access & Opcodes.ACC_MANDATED) != 0) { continue; } + if (method.name.equals("")) { continue; } + int formalParamStartIndex = 0; + if (enumClass) { // Skip enum sugar methods if (method.name.equals("values") && method.desc.equals("()[L" + classNode.name + ";")) { continue; } + if (method.name.equals("valueOf") && method.desc.equals("(Ljava/lang/String;)L" + classNode.name + ";")) { continue; } + if (method.name.equals("")) { formalParamStartIndex = 2; // 0 String 1 int } } + if (recordClass) { // skip record sugars if (method.name.equals("equals") && method.desc.equals("(Ljava/lang/Object;)Z") @@ -244,17 +255,20 @@ private void addMethods() { // todo test component getters } + if (instanceInner) { if (method.name.equals("")) { formalParamStartIndex = 1; // 0 this$0 } } + builder.addMethod(new MethodBuilder(mappings, classNode, method, environment, receiverSignature, formalParamStartIndex).build()); } } private void addFields() { if (classNode.fields == null) return; + for (FieldNode field : classNode.fields) { if (recordClass && !Modifier.isStatic(field.access)) { // proguard elevates record field access for direct record field gets @@ -270,9 +284,11 @@ private void addFields() { continue; } + if ((field.access & Opcodes.ACC_SYNTHETIC) != 0 || (field.access & Opcodes.ACC_MANDATED) != 0) { continue; // hide synthetic stuff } + if ((field.access & Opcodes.ACC_ENUM) == 0) { builder.addField(new FieldBuilder(mappings, classNode, field, environment).build()); } else { @@ -288,6 +304,7 @@ private void addFields() { .add(field.visibleTypeAnnotations) .build().getBank(TypeReference.newTypeReference(TypeReference.FIELD)) .getCurrentAnnotations(); + if (!annotations.isEmpty()) { enumBuilder.addAnnotations(annotations); // no custom paths for annotations rip } @@ -301,6 +318,7 @@ private void addDirectAnnotations(TypeSpec.Builder builder, List if (regularAnnotations == null) { return; } + for (AnnotationNode annotation : regularAnnotations) { builder.addAnnotation(parseAnnotation(annotation)); } @@ -312,6 +330,7 @@ private void addJavaDoc() { public void addInnerClass(ClassBuilder classBuilder) { InnerClassNode innerClassNode = null; + if (classNode.innerClasses != null) { for (InnerClassNode node : classNode.innerClasses) { if (node.name.equals(classBuilder.classNode.name)) { @@ -339,8 +358,8 @@ public void addInnerClass(ClassBuilder classBuilder) { classBuilder.builder.modifiers.remove(javax.lang.model.element.Modifier.PUBLIC); // this modifier may come from class access classBuilder.builder.addModifiers(new ModifierBuilder(innerClassNode.access) .checkUnseal(classBuilder.classNode, environment) - .getModifiers(ModifierBuilder.getType(classBuilder.enumClass, classBuilder.recordClass)) - ); + .getModifiers(ModifierBuilder.getType(classBuilder.enumClass, classBuilder.recordClass))); + if (!Modifier.isStatic(innerClassNode.access)) { classBuilder.instanceInner = true; } @@ -352,6 +371,7 @@ public void addInnerClass(ClassBuilder classBuilder) { sb.append(innerClassNode.innerName); // append simple name List innerClassGenerics = classBuilder.signature.generics(); + if (!innerClassGenerics.isEmpty()) { sb.append("<"); for (TypeVariableName each : innerClassGenerics) { @@ -359,9 +379,11 @@ public void addInnerClass(ClassBuilder classBuilder) { } sb.append(">"); } + classBuilder.receiverSignature = sb.toString(); } } + innerClasses.add(classBuilder); } @@ -370,9 +392,10 @@ public String getClassName() { } public TypeSpec build() { - innerClasses.stream() - .map(ClassBuilder::build) - .forEach(builder::addType); + for (ClassBuilder innerCb : innerClasses) { + builder.addType(innerCb.build()); + } + return builder.build(); } } diff --git a/src/main/java/net/fabricmc/mappingpoet/Main.java b/src/main/java/net/fabricmc/mappingpoet/Main.java index 62c9e12..9ff8ae2 100644 --- a/src/main/java/net/fabricmc/mappingpoet/Main.java +++ b/src/main/java/net/fabricmc/mappingpoet/Main.java @@ -15,17 +15,6 @@ */ package net.fabricmc.mappingpoet; -import com.squareup.javapoet.ClassName; -import com.squareup.javapoet.JavaFile; -import net.fabricmc.mappingpoet.Environment.ClassNamePointer; -import net.fabricmc.mappingpoet.Environment.NestedClassInfo; -import net.fabricmc.mappingpoet.signature.ClassStaticContext; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.ClassNode; -import org.objectweb.asm.tree.InnerClassNode; - import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -50,6 +39,16 @@ import java.util.jar.JarEntry; import java.util.jar.JarFile; +import com.squareup.javapoet.JavaFile; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.InnerClassNode; + +import net.fabricmc.mappingpoet.Environment.ClassNamePointer; +import net.fabricmc.mappingpoet.Environment.NestedClassInfo; + public class Main { public static void main(String[] args) { @@ -66,8 +65,8 @@ public static void main(String[] args) { if (Files.exists(outputDirectory)) { try (var stream = Files.walk(outputDirectory)) { stream.sorted(Comparator.reverseOrder()) - .map(Path::toFile) - .forEach(File::delete); + .map(Path::toFile) + .forEach(File::delete); } } @@ -94,20 +93,20 @@ public static void generate(Path mappings, Path inputJar, Path outputDirectory, Map classes = new HashMap<>(); forEachClass(inputJar, (classNode, environment) -> writeClass(mapping, classNode, classes, environment), librariesDir); - classes.values().stream() - .filter(classBuilder -> !classBuilder.getClassName().contains("$")) - .forEach(classBuilder -> { - int packageEnd = classBuilder.getClassName().lastIndexOf("/"); - JavaFile javaFile = JavaFile.builder(packageEnd == -1 ? "" : classBuilder.getClassName().substring(0, packageEnd).replaceAll("/", "."), classBuilder.build()) - .build(); - try { - javaFile.writeTo(outputDirectory); - } catch (IOException e) { - throw new RuntimeException("Failed to write class", e); - } - }); + for (ClassBuilder classBuilder : classes.values()) { + String name = classBuilder.getClassName(); + if (name.contains("$")) continue; + try { + int packageEnd = classBuilder.getClassName().lastIndexOf("/"); + String pkgName = packageEnd < 0 ? "" : classBuilder.getClassName().substring(0, packageEnd).replaceAll("/", "."); + JavaFile javaFile = JavaFile.builder(pkgName, classBuilder.build()).build(); + javaFile.writeTo(outputDirectory); + } catch (Throwable t) { + throw new RuntimeException("Failed to process class "+name, t); + } + } } private static void forEachClass(Path jar, ClassNodeConsumer classNodeConsumer, Path librariesDir) { @@ -170,7 +169,9 @@ private static void forEachClass(Path jar, ClassNodeConsumer classNodeConsumer, //Sort all the classes making sure that inner classes come after the parent classes classes.sort(Comparator.comparing(o -> o.name)); - classes.forEach(node -> classNodeConsumer.accept(node, new Environment(supers, sealedClasses, nestedClasses))); + for (ClassNode node : classes) { + classNodeConsumer.accept(node, new Environment(supers, sealedClasses, nestedClasses)); + } } private static void scanNestedClasses(Map classNames, Map instanceInnerClasses, Path librariesDir) { diff --git a/src/test/java/net/fabricmc/mappingpoet/TestAnno.java b/src/test/java/net/fabricmc/mappingpoet/TestAnno.java index 01f589d..bb4cccf 100644 --- a/src/test/java/net/fabricmc/mappingpoet/TestAnno.java +++ b/src/test/java/net/fabricmc/mappingpoet/TestAnno.java @@ -23,7 +23,7 @@ @Documented @Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE_USE) +@Target({ElementType.TYPE_USE, ElementType.FIELD}) public @interface TestAnno { String value() default ""; } diff --git a/src/test/java/net/fabricmc/mappingpoet/TestOuter.java b/src/test/java/net/fabricmc/mappingpoet/TestOuter.java index ad86065..213c331 100644 --- a/src/test/java/net/fabricmc/mappingpoet/TestOuter.java +++ b/src/test/java/net/fabricmc/mappingpoet/TestOuter.java @@ -72,7 +72,7 @@ class InnerThree { class OuterTwo { static class InnerOne { class InnerTwo { - InnerTwo(InnerOnenet.fabricmc.mappingpoet.OuterTwo.InnerOne.this) { + InnerTwo(InnerOneInnerOne.this) { }